Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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#ifndef QV4MMDEFS_P_H
4#define QV4MMDEFS_P_H
5
6//
7// W A R N I N G
8// -------------
9//
10// This file is not part of the Qt API. It exists purely as an
11// implementation detail. This header file may change from version to
12// version without notice, or even be removed.
13//
14// We mean it.
15//
16
17#include <private/qv4global_p.h>
18#include <private/qv4runtimeapi_p.h>
19#include <QtCore/qalgorithms.h>
20#include <QtCore/qmath.h>
21
23
24class QDeadlineTimer;
25
26namespace QV4 {
27
28struct MarkStack;
29
30typedef void(*ClassDestroyStatsCallback)(const char *);
31
32/*
33 * Chunks are the basic structure containing GC managed objects.
34 *
35 * Chunks are 64k aligned in memory, so that retrieving the Chunk pointer from a Heap object
36 * is a simple masking operation. Each Chunk has 4 bitmaps for managing purposes,
37 * and 32byte wide slots for the objects following afterwards.
38 *
39 * The gray and black bitmaps are used for mark/sweep.
40 * The object bitmap has a bit set if this location represents the start of a Heap object.
41 * The extends bitmap denotes the extend of an object. It has a cleared bit at the start of the object
42 * and a set bit for all following slots used by the object.
43 *
44 * Free memory has both used and extends bits set to 0.
45 *
46 * This gives the following operations when allocating an object of size s:
47 * Find s/Alignment consecutive free slots in the chunk. Set the object bit for the first
48 * slot to 1. Set the extends bits for all following slots to 1.
49 *
50 * All used slots can be found by object|extents.
51 *
52 * When sweeping, simply copy the black bits over to the object bits.
53 *
54 */
55struct HeapItem;
56struct Chunk {
57 enum {
58 ChunkSize = 64*1024,
67#if QT_POINTER_SIZE == 8
68 Bits = 64,
69 BitShift = 6,
70#else
71 Bits = 32,
73#endif
75 };
80
82 HeapItem *first();
83
84 static Q_ALWAYS_INLINE size_t bitmapIndex(size_t index) {
85 return index >> BitShift;
86 }
88 return static_cast<quintptr>(1) << (index & (Bits - 1));
89 }
90
91 static void setBit(quintptr *bitmap, size_t index) {
92// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
95 *bitmap |= bit;
96 }
97 static void clearBit(quintptr *bitmap, size_t index) {
98// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
101 *bitmap &= ~bit;
102 }
103 static bool testBit(quintptr *bitmap, size_t index) {
104// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
107 return (*bitmap & bit);
108 }
109 static void setBits(quintptr *bitmap, size_t index, size_t nBits) {
110// Q_ASSERT(index >= HeaderSize/SlotSize && index + nBits <= ChunkSize/SlotSize);
111 if (!nBits)
112 return;
113 bitmap += index >> BitShift;
114 index &= (Bits - 1);
115 while (1) {
116 size_t bitsToSet = qMin(nBits, Bits - index);
117 quintptr mask = static_cast<quintptr>(-1) >> (Bits - bitsToSet) << index;
118 *bitmap |= mask;
119 nBits -= bitsToSet;
120 if (!nBits)
121 return;
122 index = 0;
123 ++bitmap;
124 }
125 }
127 for (uint i = 0; i < EntriesInBitmap; ++i)
128 if (bitmap[i])
129 return true;
130 return false;
131 }
133 for (uint i = 0; i < EntriesInBitmap; ++i) {
134 if (bitmap[i]) {
135 quintptr b = bitmap[i];
136 return i*Bits + qCountTrailingZeroBits(b);
137 }
138 }
139 return 0;
140 }
141
142 uint nFreeSlots() const {
143 return AvailableSlots - nUsedSlots();
144 }
145 uint nUsedSlots() const {
146 uint usedSlots = 0;
147 for (uint i = 0; i < EntriesInBitmap; ++i) {
149 usedSlots += qPopulationCount(used);
150 }
151 return usedSlots;
152 }
153
154 bool sweep(ClassDestroyStatsCallback classCountPtr);
155 void resetBlackBits();
158
159 void sortIntoBins(HeapItem **bins, uint nBins);
160};
161
162struct HeapItem {
163 union {
164 struct {
169 };
170 operator Heap::Base *() { return reinterpret_cast<Heap::Base *>(this); }
171
172 template<typename T>
173 T *as() { return static_cast<T *>(reinterpret_cast<Heap::Base *>(this)); }
174
175 Chunk *chunk() const {
176 return reinterpret_cast<Chunk *>(reinterpret_cast<quintptr>(this) >> Chunk::ChunkShift << Chunk::ChunkShift);
177 }
178
179 bool isBlack() const {
180 Chunk *c = chunk();
181 std::ptrdiff_t index = this - c->realBase();
182 return Chunk::testBit(c->blackBitmap, index);
183 }
184 bool isInUse() const {
185 Chunk *c = chunk();
186 std::ptrdiff_t index = this - c->realBase();
187 return Chunk::testBit(c->objectBitmap, index);
188 }
189
190 void setAllocatedSlots(size_t nSlots) {
191// Q_ASSERT(size && !(size % sizeof(HeapItem)));
192 Chunk *c = chunk();
193 size_t index = this - c->realBase();
194// Q_ASSERT(!Chunk::testBit(c->objectBitmap, index));
195 Chunk::setBit(c->objectBitmap, index);
196 Chunk::setBits(c->extendsBitmap, index + 1, nSlots - 1);
197// for (uint i = index + 1; i < nBits - 1; ++i)
198// Q_ASSERT(Chunk::testBit(c->extendsBitmap, i));
199// Q_ASSERT(!Chunk::testBit(c->extendsBitmap, index));
200 }
201
202 // Doesn't report correctly for huge items
203 size_t size() const {
204 Chunk *c = chunk();
205 std::ptrdiff_t index = this - c->realBase();
206 Q_ASSERT(Chunk::testBit(c->objectBitmap, index));
207 // ### optimize me
208 std::ptrdiff_t end = index + 1;
209 while (end < Chunk::NumSlots && Chunk::testBit(c->extendsBitmap, end))
210 ++end;
211 return (end - index)*sizeof(HeapItem);
212 }
213};
214
216{
217 return reinterpret_cast<HeapItem *>(this);
218}
219
221{
222 return reinterpret_cast<HeapItem *>(data);
223}
224
231
232struct Q_QML_EXPORT MarkStack {
234 ~MarkStack() { /* we drain manually */ }
235
237 *(m_top++) = m;
238
239 if (m_top < m_softLimit)
240 return;
241
242 // If at or above soft limit, partition the remaining space into at most 64 segments and
243 // allow one C++ recursion of drain() per segment, plus one for the fence post.
244 const quintptr segmentSize = qNextPowerOfTwo(quintptr(m_hardLimit - m_softLimit) / 64u);
245 if (m_drainRecursion * segmentSize <= quintptr(m_top - m_softLimit)) {
246 ++m_drainRecursion;
247 drain();
248 --m_drainRecursion;
249 } else if (m_top == m_hardLimit) {
250 qFatal("GC mark stack overrun. Either simplify your application or"
251 "increase QV4_GC_MAX_STACK_SIZE");
252 }
253 }
254
255 bool isEmpty() const { return m_top == m_base; }
256
258 {
259 return m_softLimit - m_top;
260 }
261
262 ExecutionEngine *engine() const { return m_engine; }
263
264 void drain();
265 enum class DrainState { Ongoing, Complete };
266 DrainState drain(QDeadlineTimer deadline);
267private:
268 Heap::Base *pop() { return *(--m_top); }
269
270 Heap::Base **m_top = nullptr;
271 Heap::Base **m_base = nullptr;
272 Heap::Base **m_softLimit = nullptr;
273 Heap::Base **m_hardLimit = nullptr;
274
275 ExecutionEngine *m_engine = nullptr;
276
277 quintptr m_drainRecursion = 0;
278};
279
280// Some helper to automate the generation of our
281// functions used for marking objects
282
283#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION(c, gcType, type, name) \
284 HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_##gcType(c, type, name)
285
286#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_Pointer(c, type, name) Pointer<type, 0> name;
287#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_NoMark(c, type, name) type name;
288#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_HeapValue(c, type, name) HeapValue<0> name;
289#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION_ValueArray(c, type, name) type<0> name;
290
291#define HEAP_OBJECT_MEMBER_EXPANSION(c, gcType, type, name) \
292 HEAP_OBJECT_MEMBER_EXPANSION_##gcType(c, type, name)
293
294#define HEAP_OBJECT_MEMBER_EXPANSION_Pointer(c, type, name) \
295 Pointer<type, offsetof(c##OffsetStruct, name) + baseOffset> name;
296#define HEAP_OBJECT_MEMBER_EXPANSION_NoMark(c, type, name) \
297 type name;
298#define HEAP_OBJECT_MEMBER_EXPANSION_HeapValue(c, type, name) \
299 HeapValue<offsetof(c##OffsetStruct, name) + baseOffset> name;
300#define HEAP_OBJECT_MEMBER_EXPANSION_ValueArray(c, type, name) \
301 type<offsetof(c##OffsetStruct, name) + baseOffset> name;
302
303#define HEAP_OBJECT_MARKOBJECTS_EXPANSION(c, gcType, type, name) \
304 HEAP_OBJECT_MARKOBJECTS_EXPANSION_##gcType(c, type, name)
305#define HEAP_OBJECT_MARKOBJECTS_EXPANSION_Pointer(c, type, name) \
306 if (o->name) o->name.heapObject()->mark(stack);
307#define HEAP_OBJECT_MARKOBJECTS_EXPANSION_NoMark(c, type, name)
308#define HEAP_OBJECT_MARKOBJECTS_EXPANSION_HeapValue(c, type, name) \
309 o->name.mark(stack);
310#define HEAP_OBJECT_MARKOBJECTS_EXPANSION_ValueArray(c, type, name) \
311 o->name.mark(stack);
312
313
314#define DECLARE_HEAP_OBJECT_BASE(name, base) \
315 struct name##OffsetStruct { \
316 name##Members(name, HEAP_OBJECT_OFFSET_MEMBER_EXPANSION) \
317 }; \
318 struct name##SizeStruct : base, name##OffsetStruct {}; \
319 struct name##Data { \
320 typedef base SuperClass; \
321 static constexpr size_t baseOffset = sizeof(name##SizeStruct) - sizeof(name##OffsetStruct); \
322 name##Members(name, HEAP_OBJECT_MEMBER_EXPANSION) \
323 }; \
324 Q_STATIC_ASSERT(sizeof(name##SizeStruct) == sizeof(name##Data) + name##Data::baseOffset); \
325
326#define DECLARE_HEAP_OBJECT(name, base) \
327 DECLARE_HEAP_OBJECT_BASE(name, base) \
328 struct name : base, name##Data
329#define DECLARE_EXPORTED_HEAP_OBJECT(name, base) \
330 DECLARE_HEAP_OBJECT_BASE(name, base) \
331 struct Q_QML_EXPORT name : base, name##Data
332
333#define DECLARE_MARKOBJECTS(class) \
334 static void markObjects(Heap::Base *b, MarkStack *stack) { \
335 class *o = static_cast<class *>(b); \
336 class##Data::SuperClass::markObjects(o, stack); \
337 class##Members(class, HEAP_OBJECT_MARKOBJECTS_EXPANSION) \
338 }
339
340}
341
343
344#endif
\inmodule QtCore
Combined button and popup list for selecting options.
void(* ClassDestroyStatsCallback)(const char *)
Definition qv4mmdefs_p.h:30
constexpr uint qCountTrailingZeroBits(quint32 v) noexcept
Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR uint qPopulationCount(quint32 v) noexcept
#define Q_STATIC_ASSERT(Condition)
Definition qassert.h:108
#define Q_ALWAYS_INLINE
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
#define qFatal
Definition qlogging.h:168
constexpr quint32 qNextPowerOfTwo(quint32 v)
Definition qmath.h:335
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
GLboolean GLboolean GLboolean b
const GLfloat * m
GLuint index
[2]
GLuint GLuint end
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
const GLubyte * c
GLsizei GLfixed GLfixed GLfixed GLfixed const GLubyte * bitmap
#define QT_POINTER_SIZE
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
size_t quintptr
Definition qtypes.h:167
ptrdiff_t qptrdiff
Definition qtypes.h:164
unsigned long long quint64
Definition qtypes.h:61
unsigned int uint
Definition qtypes.h:34
QDeadlineTimer deadline(30s)
QJSEngine engine
[0]
quintptr objectBitmap[BitmapSize/sizeof(quintptr)]
Definition qv4mmdefs_p.h:77
static void setBit(quintptr *bitmap, size_t index)
Definition qv4mmdefs_p.h:91
char data[ChunkSize - HeaderSize]
Definition qv4mmdefs_p.h:79
HeapItem * first()
static uint lowestNonZeroBit(quintptr *bitmap)
uint nUsedSlots() const
static bool hasNonZeroBit(quintptr *bitmap)
static bool testBit(quintptr *bitmap, size_t index)
static Q_ALWAYS_INLINE quintptr bitForIndex(size_t index)
Definition qv4mmdefs_p.h:87
void freeAll(ExecutionEngine *engine)
Definition qv4mm.cpp:331
HeapItem * realBase()
quintptr extendsBitmap[BitmapSize/sizeof(quintptr)]
Definition qv4mmdefs_p.h:78
void resetBlackBits()
Definition qv4mm.cpp:374
void sortIntoBins(HeapItem **bins, uint nBins)
Definition qv4mm.cpp:379
static Q_ALWAYS_INLINE size_t bitmapIndex(size_t index)
Definition qv4mmdefs_p.h:84
static void setBits(quintptr *bitmap, size_t index, size_t nBits)
uint nFreeSlots() const
quintptr blackBitmap[BitmapSize/sizeof(quintptr)]
Definition qv4mmdefs_p.h:76
static void clearBit(quintptr *bitmap, size_t index)
Definition qv4mmdefs_p.h:97
bool sweep(ClassDestroyStatsCallback classCountPtr)
quint64 payload[Chunk::SlotSize/sizeof(quint64)]
size_t size() const
HeapItem * next
struct QV4::HeapItem::@638::@641 freeData
bool isBlack() const
size_t availableSlots
void setAllocatedSlots(size_t nSlots)
Chunk * chunk() const
bool isInUse() const
bool isEmpty() const
qptrdiff remainingBeforeSoftLimit() const
void push(Heap::Base *m)
ExecutionEngine * engine() const