Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qv4mmdefs_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:low-level-memory-management
4#ifndef QV4MMDEFS_P_H
5#define QV4MMDEFS_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <private/qv4global_p.h>
19#include <private/qv4runtimeapi_p.h>
20#include <QtCore/qalgorithms.h>
21#include <QtCore/qmath.h>
22
23QT_BEGIN_NAMESPACE
24
25class QDeadlineTimer;
26
27namespace QV4 {
28
29struct MarkStack;
30
31/*
32 * Chunks are the basic structure containing GC managed objects.
33 *
34 * Chunks are 64k aligned in memory, so that retrieving the Chunk pointer from a Heap object
35 * is a simple masking operation. Each Chunk has 4 bitmaps for managing purposes,
36 * and 32byte wide slots for the objects following afterwards.
37 *
38 * The black bitmaps are used for mark/sweep.
39 * The object bitmap has a bit set if this location represents the start of a Heap object.
40 * The extends bitmap denotes the extend of an object. It has a cleared bit at the start of the object
41 * and a set bit for all following slots used by the object.
42 *
43 * Free memory has both used and extends bits set to 0.
44 *
45 * This gives the following operations when allocating an object of size s:
46 * Find s/Alignment consecutive free slots in the chunk. Set the object bit for the first
47 * slot to 1. Set the extends bits for all following slots to 1.
48 *
49 * All used slots can be found by object|extents.
50 *
51 * When sweeping, simply copy the black bits over to the object bits.
52 *
53 */
54struct HeapItem;
55struct Chunk {
56 enum {
57 ChunkSize = 64*1024,
66#if QT_POINTER_SIZE == 8
67 Bits = 64,
68 BitShift = 6,
69#else
70 Bits = 32,
72#endif
73 EntriesInBitmap = BitmapSize/sizeof(quintptr)
74 };
79
81 HeapItem *first();
82
83 static Q_ALWAYS_INLINE size_t bitmapIndex(size_t index) {
84 return index >> BitShift;
85 }
87 return static_cast<quintptr>(1) << (index & (Bits - 1));
88 }
89
91// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
94 *bitmap |= bit;
95 }
97// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
100 *bitmap &= ~bit;
101 }
103// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
106 return (*bitmap & bit);
107 }
109// Q_ASSERT(index >= HeaderSize/SlotSize && index + nBits <= ChunkSize/SlotSize);
110 if (!nBits)
111 return;
112 bitmap += index >> BitShift;
113 index &= (Bits - 1);
114 while (1) {
116 quintptr mask = static_cast<quintptr>(-1) >> (Bits - bitsToSet) << index;
117 *bitmap |= mask;
118 nBits -= bitsToSet;
119 if (!nBits)
120 return;
121 index = 0;
122 ++bitmap;
123 }
124 }
126 for (uint i = 0; i < EntriesInBitmap; ++i)
127 if (bitmap[i])
128 return true;
129 return false;
130 }
132 for (uint i = 0; i < EntriesInBitmap; ++i) {
133 if (bitmap[i]) {
134 quintptr b = bitmap[i];
135 return i*Bits + qCountTrailingZeroBits(b);
136 }
137 }
138 return 0;
139 }
140
141 uint nFreeSlots() const {
142 return AvailableSlots - nUsedSlots();
143 }
144 uint nUsedSlots() const {
145 uint usedSlots = 0;
146 for (uint i = 0; i < EntriesInBitmap; ++i) {
149 }
150 return usedSlots;
151 }
152
153 void resetBlackBits();
154 bool sweep(ExecutionEngine *engine);
155 void freeAll(ExecutionEngine *engine);
156
157 void sortIntoBins(HeapItem **bins, uint nBins);
158};
159
160struct HeapItem {
161 union {
162 struct {
165 } freeData;
166 quint64 payload[Chunk::SlotSize/sizeof(quint64)];
167 };
168 operator Heap::Base *() { return reinterpret_cast<Heap::Base *>(this); }
169
170 template<typename T>
171 T *as() { return static_cast<T *>(reinterpret_cast<Heap::Base *>(this)); }
172
173 Chunk *chunk() const {
174 return reinterpret_cast<Chunk *>(reinterpret_cast<quintptr>(this) >> Chunk::ChunkShift << Chunk::ChunkShift);
175 }
176
177 bool isBlack() const {
178 Chunk *c = chunk();
179 std::ptrdiff_t index = this - c->realBase();
180 return Chunk::testBit(c->blackBitmap, index);
181 }
182 bool isInUse() const {
183 Chunk *c = chunk();
184 std::ptrdiff_t index = this - c->realBase();
185 return Chunk::testBit(c->objectBitmap, index);
186 }
187
189// Q_ASSERT(size && !(size % sizeof(HeapItem)));
190 Chunk *c = chunk();
191 size_t index = this - c->realBase();
192// Q_ASSERT(!Chunk::testBit(c->objectBitmap, index));
195// for (uint i = index + 1; i < nBits - 1; ++i)
196// Q_ASSERT(Chunk::testBit(c->extendsBitmap, i));
197// Q_ASSERT(!Chunk::testBit(c->extendsBitmap, index));
198 }
199
200 // Doesn't report correctly for huge items
201 size_t size() const {
202 Chunk *c = chunk();
203 std::ptrdiff_t index = this - c->realBase();
205 // ### optimize me
206 std::ptrdiff_t end = index + 1;
207 while (end < Chunk::NumSlots && Chunk::testBit(c->extendsBitmap, end))
208 ++end;
209 return (end - index)*sizeof(HeapItem);
210 }
211};
212
214{
215 return reinterpret_cast<HeapItem *>(this);
216}
217
219{
220 return reinterpret_cast<HeapItem *>(data);
221}
222
229
230struct Q_QML_EXPORT MarkStack {
232 ~MarkStack() { /* we drain manually */ }
233
234 void push(Heap::Base *m) {
235 *(m_top++) = m;
236
237 if (m_top < m_softLimit)
238 return;
239
240 // If at or above soft limit, partition the remaining space into at most 64 segments and
241 // allow one C++ recursion of drain() per segment, plus one for the fence post.
242 const quintptr segmentSize = qNextPowerOfTwo(quintptr(m_hardLimit - m_softLimit) / 64u);
243 if (m_drainRecursion * segmentSize <= quintptr(m_top - m_softLimit)) {
244 ++m_drainRecursion;
245 drain();
246 --m_drainRecursion;
247 } else if (m_top == m_hardLimit) {
248 qFatal("GC mark stack overrun. Either simplify your application or"
249 "increase QV4_GC_MAX_STACK_SIZE");
250 }
251 }
252
253 bool isEmpty() const { return m_top == m_base; }
254
256 {
257 return m_softLimit - m_top;
258 }
259
260 ExecutionEngine *engine() const { return m_engine; }
261
262 void drain();
263 enum class DrainState { Ongoing, Complete };
264 DrainState drain(QDeadlineTimer deadline);
265 void setSoftLimit(size_t size);
266private:
267 Heap::Base *pop() { return *(--m_top); }
268
269 Heap::Base **m_top = nullptr;
270 Heap::Base **m_base = nullptr;
271 Heap::Base **m_softLimit = nullptr;
272 Heap::Base **m_hardLimit = nullptr;
273
274 ExecutionEngine *m_engine = nullptr;
275
276 quintptr m_drainRecursion = 0;
277};
278
279// Some helper to automate the generation of our
280// functions used for marking objects
281
282#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION(c, gcType, type, name)
283 HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_##gcType(c, type, name)
284
285#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_Pointer(c, type, name) Pointer<type, 0> name;
286#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_NoMark(c, type, name) type name;
287#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_HeapValue(c, type, name) HeapValue<0> name;
288#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_ValueArray(c, type, name) type<0> name;
289
290#define HEAP_OBJECT_MEMBER_EXPANSION(c, gcType, type, name)
291 HEAP_OBJECT_MEMBER_EXPANSION_##gcType(c, type, name)
292
293#define HEAP_OBJECT_MEMBER_EXPANSION_Pointer(c, type, name)
294 Pointer<type, offsetof(c##OffsetStruct, name) + baseOffset> name;
295#define HEAP_OBJECT_MEMBER_EXPANSION_NoMark(c, type, name)
296 type name;
297#define HEAP_OBJECT_MEMBER_EXPANSION_HeapValue(c, type, name)
298 HeapValue<offsetof(c##OffsetStruct, name) + baseOffset> name;
299#define HEAP_OBJECT_MEMBER_EXPANSION_ValueArray(c, type, name)
300 type<offsetof(c##OffsetStruct, name) + baseOffset> name;
301
302#define HEAP_OBJECT_MARKOBJECTS_EXPANSION(c, gcType, type, name)
303 HEAP_OBJECT_MARKOBJECTS_EXPANSION_##gcType(c, type, name)
304#define HEAP_OBJECT_MARKOBJECTS_EXPANSION_Pointer(c, type, name)
305 if (o->name) o->name.heapObject()->mark(stack);
306#define HEAP_OBJECT_MARKOBJECTS_EXPANSION_NoMark(c, type, name)
307#define HEAP_OBJECT_MARKOBJECTS_EXPANSION_HeapValue(c, type, name)
308 o->name.mark(stack);
309#define HEAP_OBJECT_MARKOBJECTS_EXPANSION_ValueArray(c, type, name)
310 o->name.mark(stack);
311
312
313#define DECLARE_HEAP_OBJECT_BASE(name, base)
314 struct name##OffsetStruct {
315 name##Members(name, HEAP_OBJECT_OFFSET_MEMBER_EXPANSION)
316 };
317 struct name##SizeStruct : base, name##OffsetStruct {};
318 struct name##Data {
319 typedef base SuperClass;
320 static constexpr size_t baseOffset = sizeof(name##SizeStruct) - sizeof(name##OffsetStruct);
321 name##Members(name, HEAP_OBJECT_MEMBER_EXPANSION)
322 };
323 Q_STATIC_ASSERT(sizeof(name##SizeStruct) == sizeof(name##Data) + name##Data::baseOffset);
324
325#define DECLARE_HEAP_OBJECT(name, base)
326 DECLARE_HEAP_OBJECT_BASE(name, base)
327 struct name : base, name##Data
328#define DECLARE_EXPORTED_HEAP_OBJECT(name, base)
329 DECLARE_HEAP_OBJECT_BASE(name, base)
330 struct Q_QML_EXPORT name : base, name##Data
331
332#define DECLARE_MARKOBJECTS(class)
333 static void markObjects(Heap::Base *b, MarkStack *stack) {
334 class *o = static_cast<class *>(b);
335 class##Data::SuperClass::markObjects(o, stack);
336 class##Members(class, HEAP_OBJECT_MARKOBJECTS_EXPANSION)
337 }
338
339}
340
341QT_END_NAMESPACE
342
343#endif
Definition qjsvalue.h:24
Q_STATIC_ASSERT(sizeof(CppStackFrame)==sizeof(JSTypesStackFrame))
#define HEAP_OBJECT_MARKOBJECTS_EXPANSION(c, gcType, type, name)
#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION(c, gcType, type, name)
#define HEAP_OBJECT_MEMBER_EXPANSION(c, gcType, type, name)
#define DECLARE_HEAP_OBJECT_BASE(name, base)
quintptr objectBitmap[BitmapSize/sizeof(quintptr)]
Definition qv4mmdefs_p.h:76
HeapItem * first()
bool sweep(ExecutionEngine *engine)
Definition qv4mm.cpp:258
void freeAll(ExecutionEngine *engine)
Definition qv4mm.cpp:318
HeapItem * realBase()
quintptr extendsBitmap[BitmapSize/sizeof(quintptr)]
Definition qv4mmdefs_p.h:77
void sortIntoBins(HeapItem **bins, uint nBins)
Definition qv4mm.cpp:362
char data[DataSize]
Definition qv4mmdefs_p.h:78
quintptr blackBitmap[BitmapSize/sizeof(quintptr)]
Definition qv4mmdefs_p.h:75
quint64 payload[Chunk::SlotSize/sizeof(quint64)]
HeapItem * next
size_t availableSlots
bool isEmpty() const
qptrdiff remainingBeforeSoftLimit() const
void push(Heap::Base *m)
DrainState drain(QDeadlineTimer deadline)
Definition qv4mm.cpp:1137
ExecutionEngine * engine() const
void setSoftLimit(size_t size)
Definition qv4mm.cpp:1152