Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
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
23
QT_BEGIN_NAMESPACE
24
25
class
QDeadlineTimer;
26
27
namespace
QV4
{
28
29
struct
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
*/
54
struct
HeapItem
;
55
struct
Chunk
{
56
enum
{
57
ChunkSize
= 64*1024,
58
ChunkShift
= 16,
59
SlotSize
= 32,
60
SlotSizeShift
= 5,
61
NumSlots
=
ChunkSize
/
SlotSize
,
62
BitmapSize
=
NumSlots
/8,
63
HeaderSize
= 3*
BitmapSize
,
64
DataSize
=
ChunkSize
-
HeaderSize
,
65
AvailableSlots
=
DataSize
/
SlotSize
,
66
#
if
QT_POINTER_SIZE
==
8
67
Bits = 64,
68
BitShift = 6,
69
#
else
70
Bits
= 32,
71
BitShift
= 5,
72
#
endif
73
EntriesInBitmap
= BitmapSize/
sizeof
(quintptr)
74
};
75
quintptr
blackBitmap
[
BitmapSize
/
sizeof
(
quintptr
)];
76
quintptr
objectBitmap
[
BitmapSize
/
sizeof
(
quintptr
)];
77
quintptr
extendsBitmap
[
BitmapSize
/
sizeof
(
quintptr
)];
78
char
data
[
DataSize
];
79
80
HeapItem
*
realBase
();
81
HeapItem
*
first
();
82
83
static
Q_ALWAYS_INLINE size_t
bitmapIndex
(
size_t
index
) {
84
return
index
>>
BitShift
;
85
}
86
static
Q_ALWAYS_INLINE
quintptr
bitForIndex
(
size_t
index
) {
87
return
static_cast
<
quintptr
>(1) << (
index
& (
Bits
- 1));
88
}
89
90
static
void
setBit
(
quintptr
*
bitmap
,
size_t
index
) {
91
// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
92
bitmap
+=
bitmapIndex
(
index
);
93
quintptr
bit
=
bitForIndex
(
index
);
94
*
bitmap
|=
bit
;
95
}
96
static
void
clearBit
(
quintptr
*
bitmap
,
size_t
index
) {
97
// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
98
bitmap
+=
bitmapIndex
(
index
);
99
quintptr
bit
=
bitForIndex
(
index
);
100
*
bitmap
&= ~
bit
;
101
}
102
static
bool
testBit
(
quintptr
*
bitmap
,
size_t
index
) {
103
// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
104
bitmap
+=
bitmapIndex
(
index
);
105
quintptr
bit
=
bitForIndex
(
index
);
106
return
(*
bitmap
&
bit
);
107
}
108
static
void
setBits
(
quintptr
*
bitmap
,
size_t
index
,
size_t
nBits
) {
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) {
115
size_t
bitsToSet
=
qMin
(
nBits
,
Bits
-
index
);
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
}
125
static
bool
hasNonZeroBit
(
quintptr
*
bitmap
) {
126
for
(
uint
i
= 0;
i
<
EntriesInBitmap
; ++
i
)
127
if
(
bitmap
[
i
])
128
return
true
;
129
return
false
;
130
}
131
static
uint
lowestNonZeroBit
(
quintptr
*
bitmap
) {
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
) {
147
quintptr
used
=
objectBitmap
[
i
] |
extendsBitmap
[
i
];
148
usedSlots
+=
qPopulationCount
(
used
);
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
160
struct
HeapItem
{
161
union
{
162
struct
{
163
HeapItem
*next;
164
size_t availableSlots;
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
188
void
setAllocatedSlots
(
size_t
nSlots
) {
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));
193
Chunk
::
setBit
(
c
->
objectBitmap
,
index
);
194
Chunk
::
setBits
(
c
->
extendsBitmap
,
index
+ 1,
nSlots
- 1);
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
();
204
Q_ASSERT
(
Chunk
::
testBit
(
c
->
objectBitmap
,
index
));
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
213
inline
HeapItem
*
Chunk
::
realBase
()
214
{
215
return
reinterpret_cast
<
HeapItem
*>(
this
);
216
}
217
218
inline
HeapItem
*
Chunk
::
first
()
219
{
220
return
reinterpret_cast
<
HeapItem
*>(
data
);
221
}
222
223
Q_STATIC_ASSERT
(
sizeof
(
Chunk
) ==
Chunk
::
ChunkSize
);
224
Q_STATIC_ASSERT
((1 <<
Chunk
::
ChunkShift
) ==
Chunk
::
ChunkSize
);
225
Q_STATIC_ASSERT
(1 <<
Chunk
::
SlotSizeShift
==
Chunk
::
SlotSize
);
226
Q_STATIC_ASSERT
(
sizeof
(
HeapItem
) ==
Chunk
::
SlotSize
);
227
Q_STATIC_ASSERT
(
QT_POINTER_SIZE
*8 ==
Chunk
::
Bits
);
228
Q_STATIC_ASSERT
((1 <<
Chunk
::
BitShift
) ==
Chunk
::
Bits
);
229
230
struct
Q_QML_EXPORT
MarkStack
{
231
MarkStack
(
ExecutionEngine
*
engine
);
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
255
qptrdiff
remainingBeforeSoftLimit
()
const
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);
266
private
:
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
341
QT_END_NAMESPACE
342
343
#
endif
QV4
Definition
qjsvalue.h:24
QV4::Q_STATIC_ASSERT
Q_STATIC_ASSERT(sizeof(CppStackFrame)==sizeof(JSTypesStackFrame))
HEAP_OBJECT_MARKOBJECTS_EXPANSION
#define HEAP_OBJECT_MARKOBJECTS_EXPANSION(c, gcType, type, name)
Definition
qv4mmdefs_p.h:302
HEAP_OBJECT_OFFSET_MEMBER_EXPANSION
#define HEAP_OBJECT_OFFSET_MEMBER_EXPANSION(c, gcType, type, name)
Definition
qv4mmdefs_p.h:282
HEAP_OBJECT_MEMBER_EXPANSION
#define HEAP_OBJECT_MEMBER_EXPANSION(c, gcType, type, name)
Definition
qv4mmdefs_p.h:290
DECLARE_HEAP_OBJECT_BASE
#define DECLARE_HEAP_OBJECT_BASE(name, base)
Definition
qv4mmdefs_p.h:313
QV4::Chunk
Definition
qv4mmdefs_p.h:55
QV4::Chunk::objectBitmap
quintptr objectBitmap[BitmapSize/sizeof(quintptr)]
Definition
qv4mmdefs_p.h:76
QV4::Chunk::first
HeapItem * first()
Definition
qv4mmdefs_p.h:218
QV4::Chunk::NumSlots
@ NumSlots
Definition
qv4mmdefs_p.h:61
QV4::Chunk::DataSize
@ DataSize
Definition
qv4mmdefs_p.h:64
QV4::Chunk::ChunkShift
@ ChunkShift
Definition
qv4mmdefs_p.h:58
QV4::Chunk::BitShift
@ BitShift
Definition
qv4mmdefs_p.h:71
QV4::Chunk::SlotSize
@ SlotSize
Definition
qv4mmdefs_p.h:59
QV4::Chunk::ChunkSize
@ ChunkSize
Definition
qv4mmdefs_p.h:57
QV4::Chunk::AvailableSlots
@ AvailableSlots
Definition
qv4mmdefs_p.h:65
QV4::Chunk::EntriesInBitmap
@ EntriesInBitmap
Definition
qv4mmdefs_p.h:73
QV4::Chunk::BitmapSize
@ BitmapSize
Definition
qv4mmdefs_p.h:62
QV4::Chunk::HeaderSize
@ HeaderSize
Definition
qv4mmdefs_p.h:63
QV4::Chunk::Bits
@ Bits
Definition
qv4mmdefs_p.h:70
QV4::Chunk::SlotSizeShift
@ SlotSizeShift
Definition
qv4mmdefs_p.h:60
QV4::Chunk::sweep
bool sweep(ExecutionEngine *engine)
Definition
qv4mm.cpp:258
QV4::Chunk::freeAll
void freeAll(ExecutionEngine *engine)
Definition
qv4mm.cpp:324
QV4::Chunk::realBase
HeapItem * realBase()
Definition
qv4mmdefs_p.h:213
QV4::Chunk::extendsBitmap
quintptr extendsBitmap[BitmapSize/sizeof(quintptr)]
Definition
qv4mmdefs_p.h:77
QV4::Chunk::sortIntoBins
void sortIntoBins(HeapItem **bins, uint nBins)
Definition
qv4mm.cpp:366
QV4::Chunk::data
char data[DataSize]
Definition
qv4mmdefs_p.h:78
QV4::Chunk::blackBitmap
quintptr blackBitmap[BitmapSize/sizeof(quintptr)]
Definition
qv4mmdefs_p.h:75
QV4::HeapItem
Definition
qv4mmdefs_p.h:160
QV4::MarkStack
Definition
qv4mmdefs_p.h:230
QV4::MarkStack::isEmpty
bool isEmpty() const
Definition
qv4mmdefs_p.h:253
QV4::MarkStack::drain
void drain()
Definition
qv4mm.cpp:1131
QV4::MarkStack::remainingBeforeSoftLimit
qptrdiff remainingBeforeSoftLimit() const
Definition
qv4mmdefs_p.h:255
QV4::MarkStack::~MarkStack
~MarkStack()
Definition
qv4mmdefs_p.h:232
QV4::MarkStack::DrainState
DrainState
Definition
qv4mmdefs_p.h:263
QV4::MarkStack::DrainState::Ongoing
@ Ongoing
Definition
qv4mmdefs_p.h:263
QV4::MarkStack::DrainState::Complete
@ Complete
Definition
qv4mmdefs_p.h:263
QV4::MarkStack::push
void push(Heap::Base *m)
Definition
qv4mmdefs_p.h:234
QV4::MarkStack::drain
DrainState drain(QDeadlineTimer deadline)
Definition
qv4mm.cpp:1142
QV4::MarkStack::engine
ExecutionEngine * engine() const
Definition
qv4mmdefs_p.h:260
QV4::MarkStack::setSoftLimit
void setSoftLimit(size_t size)
Definition
qv4mm.cpp:1157
qtdeclarative
src
qml
memory
qv4mmdefs_p.h
Generated on
for Qt by
1.18.0