-
Notifications
You must be signed in to change notification settings - Fork 47
Expand file tree
/
Copy pathMarkedBlock.h
More file actions
319 lines (251 loc) · 8.36 KB
/
MarkedBlock.h
File metadata and controls
319 lines (251 loc) · 8.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef MarkedBlock_h
#define MarkedBlock_h
#include <wtf/Bitmap.h>
#include <wtf/DoublyLinkedList.h>
#include <wtf/HashFunctions.h>
#include <wtf/PageAllocationAligned.h>
#include <wtf/StdLibExtras.h>
namespace JSC {
class Heap;
class JSCell;
typedef uintptr_t Bits;
static const size_t KB = 1024;
void destructor(JSCell*); // Defined in JSCell.h.
class MarkedBlock : public DoublyLinkedListNode<MarkedBlock> {
friend class WTF::DoublyLinkedListNode<MarkedBlock>;
public:
static const size_t atomSize = sizeof(double); // Ensures natural alignment for all built-in types.
static const size_t blockSize = 16 * KB;
static const size_t atomsPerBlock = blockSize / atomSize; // ~1.5% overhead
static const size_t ownerSetsPerBlock = 8; // ~2% overhead.
struct VoidFunctor {
typedef void ReturnType;
void returnValue() { }
};
class OwnerSet {
public:
OwnerSet();
void add(const JSCell*);
void clear();
size_t size();
bool didOverflow();
const JSCell** owners();
private:
static const size_t capacity = 5;
unsigned char m_size;
const JSCell* m_owners[capacity];
};
static MarkedBlock* create(Heap*, size_t cellSize);
static void destroy(MarkedBlock*);
static bool isAtomAligned(const void*);
static MarkedBlock* blockFor(const void*);
static size_t firstAtom();
Heap* heap() const;
bool inNewSpace();
void setInNewSpace(bool);
void* allocate();
void resetAllocator();
void sweep();
bool isEmpty();
void clearMarks();
size_t markCount();
size_t cellSize();
size_t size();
size_t capacity();
bool isMarked(const void*);
bool testAndSetMarked(const void*);
bool testAndClearMarked(const void*);
void setMarked(const void*);
void addOldSpaceOwner(const JSCell* owner, const JSCell*);
template <typename Functor> void forEachCell(Functor&);
private:
static const size_t blockMask = ~(blockSize - 1); // blockSize must be a power of two.
static const size_t atomMask = ~(atomSize - 1); // atomSize must be a power of two.
typedef char Atom[atomSize];
MarkedBlock(const PageAllocationAligned&, Heap*, size_t cellSize);
Atom* atoms();
size_t atomNumber(const void*);
size_t ownerSetNumber(const JSCell*);
size_t m_nextAtom;
size_t m_endAtom; // This is a fuzzy end. Always test for < m_endAtom.
size_t m_atomsPerCell;
WTF::Bitmap<blockSize / atomSize> m_marks;
bool m_inNewSpace;
OwnerSet m_ownerSets[ownerSetsPerBlock];
PageAllocationAligned m_allocation;
Heap* m_heap;
MarkedBlock* m_prev;
MarkedBlock* m_next;
};
inline size_t MarkedBlock::firstAtom()
{
return WTF::roundUpToMultipleOf<atomSize>(sizeof(MarkedBlock)) / atomSize;
}
inline MarkedBlock::Atom* MarkedBlock::atoms()
{
return reinterpret_cast<Atom*>(this);
}
inline bool MarkedBlock::isAtomAligned(const void* p)
{
return !(reinterpret_cast<Bits>(p) & ~atomMask);
}
inline MarkedBlock* MarkedBlock::blockFor(const void* p)
{
return reinterpret_cast<MarkedBlock*>(reinterpret_cast<Bits>(p) & blockMask);
}
inline Heap* MarkedBlock::heap() const
{
return m_heap;
}
inline bool MarkedBlock::inNewSpace()
{
return m_inNewSpace;
}
inline void MarkedBlock::setInNewSpace(bool inNewSpace)
{
m_inNewSpace = inNewSpace;
}
inline void MarkedBlock::resetAllocator()
{
m_nextAtom = firstAtom();
}
inline bool MarkedBlock::isEmpty()
{
return m_marks.isEmpty();
}
#if !ENABLE(JSC_ZOMBIES)
inline void MarkedBlock::clearMarks()
{
m_marks.clearAll();
}
#endif
inline size_t MarkedBlock::markCount()
{
return m_marks.count();
}
inline size_t MarkedBlock::cellSize()
{
return m_atomsPerCell * atomSize;
}
inline size_t MarkedBlock::size()
{
return markCount() * cellSize();
}
inline size_t MarkedBlock::capacity()
{
return m_allocation.size();
}
inline size_t MarkedBlock::atomNumber(const void* p)
{
return (reinterpret_cast<Bits>(p) - reinterpret_cast<Bits>(this)) / atomSize;
}
inline bool MarkedBlock::isMarked(const void* p)
{
return m_marks.get(atomNumber(p));
}
inline bool MarkedBlock::testAndSetMarked(const void* p)
{
return m_marks.testAndSet(atomNumber(p));
}
inline bool MarkedBlock::testAndClearMarked(const void* p)
{
return m_marks.testAndClear(atomNumber(p));
}
inline void MarkedBlock::setMarked(const void* p)
{
m_marks.set(atomNumber(p));
}
template <typename Functor> inline void MarkedBlock::forEachCell(Functor& functor)
{
for (size_t i = firstAtom(); i < m_endAtom; i += m_atomsPerCell) {
if (!m_marks.get(i))
continue;
functor(reinterpret_cast<JSCell*>(&atoms()[i]));
}
}
inline void* MarkedBlock::allocate()
{
while (m_nextAtom < m_endAtom) {
if (!m_marks.testAndSet(m_nextAtom)) {
JSCell* cell = reinterpret_cast<JSCell*>(&atoms()[m_nextAtom]);
m_nextAtom += m_atomsPerCell;
destructor(cell);
return cell;
}
m_nextAtom += m_atomsPerCell;
}
return 0;
}
inline size_t MarkedBlock::ownerSetNumber(const JSCell* cell)
{
return (reinterpret_cast<Bits>(cell) - reinterpret_cast<Bits>(this)) * ownerSetsPerBlock / blockSize;
}
inline void MarkedBlock::addOldSpaceOwner(const JSCell* owner, const JSCell* cell)
{
OwnerSet& ownerSet = m_ownerSets[ownerSetNumber(cell)];
ownerSet.add(owner);
}
inline MarkedBlock::OwnerSet::OwnerSet()
: m_size(0)
{
}
inline void MarkedBlock::OwnerSet::add(const JSCell* owner)
{
if (m_size < capacity) {
m_owners[m_size++] = owner;
return;
}
m_size = capacity + 1; // Signals overflow.
}
inline void MarkedBlock::OwnerSet::clear()
{
m_size = 0;
}
inline size_t MarkedBlock::OwnerSet::size()
{
return m_size;
}
inline bool MarkedBlock::OwnerSet::didOverflow()
{
return m_size > capacity;
}
inline const JSCell** MarkedBlock::OwnerSet::owners()
{
return m_owners;
}
} // namespace JSC
namespace WTF {
struct MarkedBlockHash : PtrHash<JSC::MarkedBlock*> {
static unsigned hash(JSC::MarkedBlock* const& key)
{
// Aligned VM regions tend to be monotonically increasing integers,
// which is a great hash function, but we have to remove the low bits,
// since they're always zero, which is a terrible hash function!
return reinterpret_cast<JSC::Bits>(key) / JSC::MarkedBlock::blockSize;
}
};
template<> struct DefaultHash<JSC::MarkedBlock*> {
typedef MarkedBlockHash Hash;
};
} // namespace WTF
#endif // MarkedBlock_h