9#include <QtCore/qalgorithms.h>
10#include <QtCore/private/qnumeric_p.h>
11#include <QtCore/qloggingcategory.h>
12#include <private/qv4alloca_p.h>
14#include "PageReservation.h"
15#include "PageAllocation.h"
17#include <QElapsedTimer>
19#include <QScopedValueRollback>
32#if !defined(MM_STATS) && !defined(QT_NO_DEBUG)
37#define DEBUG qDebug() << "MM:"
39#define DEBUG if (1) ; else qDebug() << "MM:"
43#include <valgrind/valgrind.h>
44#include <valgrind/memcheck.h>
47#ifdef V4_USE_HEAPTRACK
48#include <heaptrack_api.h>
52#include <sys/storage.h>
55#if USE(PTHREADS) && HAVE(PTHREAD_NP_H)
56#include <pthread_np.h>
82 SegmentSize = NumChunks*Chunk::ChunkSize,
87 size += Chunk::ChunkSize;
88 if (
size < SegmentSize)
91 pageReservation = PageReservation::reserve(
size, OSAllocator::JSGCHeapPages);
92 base =
reinterpret_cast<Chunk *
>((
reinterpret_cast<quintptr>(pageReservation.base()) + Chunk::ChunkSize - 1) & ~(Chunk::ChunkSize - 1));
95 if (availableBytes < SegmentSize)
108 pageReservation.deallocate();
121 allocatedMap &= ~bit;
126 return (allocatedMap & bit);
131 DEBUG <<
"freeing chunk" << chunk;
132 size_t index =
static_cast<size_t>(chunk -
base);
133 size_t end =
qMin(
static_cast<size_t>(NumChunks),
index + (
size - 1)/Chunk::ChunkSize + 1);
140 size_t pageSize = WTF::pageSize();
141 size = (
size + pageSize - 1) & ~(pageSize - 1);
142#if !defined(Q_OS_LINUX) && !defined(Q_OS_WIN)
147 memset(chunk, 0,
size);
149 pageReservation.decommit(chunk,
size);
159 size_t availableBytes = 0;
165 if (!allocatedMap &&
size >= SegmentSize) {
169 allocatedMap = ~static_cast<quint64>(0);
174 Chunk *candidate =
nullptr;
175 for (
uint i = 0;
i < nChunks; ++
i) {
178 candidate =
base +
i;
184 if (sequence == requiredChunks) {
185 pageReservation.commit(candidate,
size);
186 for (
uint i = 0;
i < requiredChunks; ++
i)
200 size += Chunk::HeaderSize;
201 size_t pageSize = WTF::pageSize();
202 size = (
size + pageSize - 1) & ~(pageSize - 1);
203 if (
size < Chunk::ChunkSize)
204 size = Chunk::ChunkSize;
209 void free(
Chunk *chunk,
size_t size = 0);
217 for (
auto &
m : memorySegments) {
218 if (~
m.allocatedMap) {
227 Chunk *
c = memorySegments.back().allocate(
size);
235 for (
auto &
m : memorySegments) {
236 if (
m.contains(chunk)) {
247 while (
s.length() < 64)
248 s.prepend(QChar::fromLatin1(
'0'));
254#define SDUMP if (1) ; else qDebug
263static
void increaseFreedCountForClass(const
char *
className)
265 (*freedObjectStatsGlobal())[
className]++;
271 bool hasUsedSlots =
false;
272 SDUMP() <<
"sweeping chunk" <<
this;
274 bool lastSlotFree =
false;
275 for (
uint i = 0;
i < Chunk::EntriesInBitmap; ++
i) {
276 quintptr toFree = objectBitmap[
i] ^ blackBitmap[
i];
277 Q_ASSERT((toFree & objectBitmap[
i]) == toFree);
279 SDUMP() <<
" index=" <<
i;
304 const VTable *
v =
b->internalClass->vtable;
309 b->_checkIsDestroyed();
311#ifdef V4_USE_HEAPTRACK
312 heaptrack_report_free(itemToFree);
316 - (blackBitmap[
i] | e)) * Chunk::SlotSize,
317 Profiling::SmallItem);
318 objectBitmap[
i] = blackBitmap[
i];
319 hasUsedSlots |= (blackBitmap[
i] != 0);
320 extendsBitmap[
i] = e;
321 lastSlotFree = !((objectBitmap[
i]|extendsBitmap[
i]) >> (
sizeof(
quintptr)*8 - 1));
323 SDUMP() <<
" lastSlotFree" << lastSlotFree;
324 Q_ASSERT((objectBitmap[
i] & extendsBitmap[
i]) == 0);
335 for (
uint i = 0;
i < Chunk::EntriesInBitmap; ++
i) {
357 if (
b->internalClass->vtable->destroy) {
359 b->_checkIsDestroyed();
361#ifdef V4_USE_HEAPTRACK
362 heaptrack_report_free(itemToFree);
368 extendsBitmap[
i] = e;
374void Chunk::resetBlackBits()
376 memset(blackBitmap, 0,
sizeof(blackBitmap));
383#if QT_POINTER_SIZE == 8
390 uint allocatedSlots = 0;
392 for (
int i =
start;
i < EntriesInBitmap; ++
i) {
393 quintptr usedSlots = (objectBitmap[
i]|extendsBitmap[
i]);
394#if QT_POINTER_SIZE == 8
409 if (++
i < EntriesInBitmap) {
410 usedSlots = (objectBitmap[
i]|extendsBitmap[
i]);
415 usedSlots = std::numeric_limits<quintptr>::max();
428 uint nSlots = freeEnd - freeStart;
433 Q_ASSERT(freeEnd > freeStart && freeEnd <= NumSlots);
434 freeItem->freeData.availableSlots = nSlots;
436 freeItem->freeData.next = bins[bin];
437 bins[bin] = freeItem;
447 size_t slotsRequired =
size >> Chunk::SlotSizeShift;
450 ++allocationStats[binForSlots(slotsRequired)];
456 if (slotsRequired < NumBins - 1) {
457 m = freeBins[slotsRequired];
459 freeBins[slotsRequired] =
m->
freeData.next;
464 if (nFree >= slotsRequired) {
468 nextFree += slotsRequired;
469 nFree -= slotsRequired;
475 last = &freeBins[NumBins - 1];
476 while ((
m = *last)) {
477 if (
m->freeData.availableSlots >= slotsRequired) {
480 size_t remainingSlots =
m->freeData.availableSlots - slotsRequired;
482 if (remainingSlots == 0)
486 if (remainingSlots > nFree) {
488 size_t bin = binForSlots(nFree);
489 nextFree->freeData.next = freeBins[bin];
490 nextFree->freeData.availableSlots = nFree;
491 freeBins[bin] = nextFree;
493 nextFree = remainder;
494 nFree = remainingSlots;
496 remainder->freeData.availableSlots = remainingSlots;
497 size_t binForRemainder = binForSlots(remainingSlots);
498 remainder->freeData.next = freeBins[binForRemainder];
499 freeBins[binForRemainder] = remainder;
506 if (slotsRequired < NumBins - 1) {
508 for (
size_t i = slotsRequired + 1;
i < NumBins - 1; ++
i) {
511 freeBins[
i] =
m->freeData.next;
513 size_t remainingSlots =
i - slotsRequired;
514 Q_ASSERT(remainingSlots < NumBins - 1);
516 remainder->
freeData.availableSlots = remainingSlots;
517 remainder->freeData.next = freeBins[remainingSlots];
518 freeBins[remainingSlots] = remainder;
525 if (!forceAllocation)
530 size_t bin = binForSlots(nFree);
531 nextFree->freeData.next = freeBins[bin];
532 nextFree->freeData.availableSlots = nFree;
533 freeBins[bin] = nextFree;
535 Chunk *newChunk = chunkAllocator->allocate();
537 chunks.push_back(newChunk);
538 nextFree = newChunk->first();
539 nFree = Chunk::AvailableSlots;
541 nextFree += slotsRequired;
542 nFree -= slotsRequired;
546 m->setAllocatedSlots(slotsRequired);
548#ifdef V4_USE_HEAPTRACK
549 heaptrack_report_alloc(
m, slotsRequired * Chunk::SlotSize);
555void BlockAllocator::sweep()
559 memset(freeBins, 0,
sizeof(freeBins));
562 usedSlotsAfterLastSweep = 0;
564 auto firstEmptyChunk = std::partition(chunks.begin(), chunks.end(), [
this](
Chunk *
c) {
565 return c->sweep(engine);
568 std::for_each(chunks.begin(), firstEmptyChunk, [
this](
Chunk *
c) {
569 c->sortIntoBins(freeBins, NumBins);
570 usedSlotsAfterLastSweep += c->nUsedSlots();
575 std::for_each(firstEmptyChunk, chunks.end(), [
this](
Chunk *
c) {
576 Q_V4_PROFILE_DEALLOC(engine, Chunk::DataSize, Profiling::HeapPage);
577 chunkAllocator->free(c);
580 chunks.erase(firstEmptyChunk, chunks.end());
583void BlockAllocator::freeAll()
585 for (
auto c : chunks)
587 for (
auto c : chunks) {
589 chunkAllocator->free(
c);
593void BlockAllocator::resetBlackBits()
595 for (
auto c : chunks)
602 if (
size >= MemorySegment::SegmentSize/2) {
604 size += Chunk::HeaderSize;
605 size_t pageSize = WTF::pageSize();
606 size = (
size + pageSize - 1) & ~(pageSize - 1);
610 c = chunkAllocator->allocate(
size);
614 Chunk::setBit(
c->objectBitmap,
c->first() -
c->realBase());
616#ifdef V4_USE_HEAPTRACK
617 heaptrack_report_alloc(
c,
size);
626 const VTable *
v =
b->internalClass->vtable;
628 classCountPtr(
v->className);
632 b->_checkIsDestroyed();
636 c.segment->free(
c.chunk,
c.size);
639 chunkAllocator->
free(
c.chunk,
c.size);
641#ifdef V4_USE_HEAPTRACK
642 heaptrack_report_free(
c.chunk);
646void HugeItemAllocator::sweep(ClassDestroyStatsCallback classCountPtr)
648 auto isBlack = [
this, classCountPtr] (
const HugeChunk &
c) {
649 bool b =
c.chunk->first()->isBlack();
650 Chunk::clearBit(
c.chunk->blackBitmap,
c.chunk->first() -
c.chunk->realBase());
658 auto newEnd = std::remove_if(chunks.begin(), chunks.end(), isBlack);
659 chunks.erase(newEnd, chunks.end());
662void HugeItemAllocator::resetBlackBits()
664 for (
auto c : chunks)
665 Chunk::clearBit(
c.chunk->blackBitmap,
c.chunk->first() -
c.chunk->realBase());
668void HugeItemAllocator::freeAll()
670 for (
auto &
c : chunks) {
681 that->mm->m_markStack = std::make_unique<MarkStack>(that->mm->engine);
682 that->mm->engine->isGCOngoing =
true;
686GCState markGlobalObject(GCStateMachine *that, ExtraData &)
688 that->mm->engine->markObjects(that->mm->m_markStack.get());
692GCState markJSStack(GCStateMachine *that, ExtraData &)
694 that->mm->collectFromJSStack(that->mm->markStack());
698GCState initMarkPersistentValues(GCStateMachine *that, ExtraData &stateData)
700 if (!that->mm->m_persistentValues)
702 stateData = GCIteratorStorage { that->mm->m_persistentValues->begin() };
706static constexpr int markLoopIterationCount = 1024;
710 if (ms->remainingBeforeSoftLimit() > markLoopIterationCount)
717GCState markPersistentValues(GCStateMachine *that, ExtraData &stateData) {
718 auto markStack = that->mm->markStack();
719 if (wasDrainNecessary(markStack, that->deadline) && that->deadline.hasExpired())
721 PersistentValueStorage::Iterator&
it = get<GCIteratorStorage>(stateData).it;
723 for (
int i = 0;
i < markLoopIterationCount; ++
i) {
726 if (Managed *
m = (*it).as<Managed>())
733GCState initMarkWeakValues(GCStateMachine *that, ExtraData &stateData)
735 stateData = GCIteratorStorage { that->mm->m_weakValues->begin() };
739GCState markWeakValues(GCStateMachine *that, ExtraData &stateData)
741 auto markStack = that->mm->markStack();
742 if (wasDrainNecessary(markStack, that->deadline) && that->deadline.hasExpired())
744 PersistentValueStorage::Iterator&
it = get<GCIteratorStorage>(stateData).it;
746 for (
int i = 0;
i < markLoopIterationCount; ++
i) {
749 QObjectWrapper *qobjectWrapper = (*it).as<QObjectWrapper>();
753 QObject *qobject = qobjectWrapper->object();
760 while (parent->parent())
761 parent = parent->parent();
767 qobjectWrapper->mark(that->mm->markStack());
772GCState markDrain(GCStateMachine *that, ExtraData &)
774 if (that->deadline.isForever()) {
775 that->mm->markStack()->drain();
778 auto drainState = that->mm->m_markStack->drain(that->deadline);
779 return drainState == MarkStack::DrainState::Complete
784GCState markReady(GCStateMachine *, ExtraData &)
793void redrain(GCStateMachine *that)
795 that->mm->collectFromJSStack(that->mm->markStack());
796 that->mm->m_markStack->drain();
799GCState initCallDestroyObjects(GCStateMachine *that, ExtraData &stateData)
803 if (!that->mm->m_weakValues)
805 stateData = GCIteratorStorage { that->mm->m_weakValues->begin() };
808GCState callDestroyObject(GCStateMachine *that, ExtraData &stateData)
810 PersistentValueStorage::Iterator&
it = get<GCIteratorStorage>(stateData).it;
814 that->mm->gcBlocked = oldState;
817 for (
int i = 0;
i < markLoopIterationCount; ++
i) {
820 Managed *
m = (*it).managed();
822 if (!
m ||
m->markBit())
826 if (QObjectWrapper *qobjectWrapper =
m->as<QObjectWrapper>())
827 qobjectWrapper->destroyObject(
false);
832void freeWeakMaps(MemoryManager *mm)
834 for (
auto [
map, lastMap] = std::tuple {mm->weakMaps, &mm->weakMaps };
map;
map =
map->nextWeakMap) {
835 if (!
map->isMarked())
837 map->removeUnmarkedKeys();
839 lastMap = &
map->nextWeakMap;
843GCState freeWeakMaps(GCStateMachine *that, ExtraData &)
845 freeWeakMaps(that->mm);
849void freeWeakSets(MemoryManager *mm)
851 for (
auto [
set, lastSet] = std::tuple {mm->weakSets, &mm->weakSets};
set;
set =
set->nextWeakSet) {
853 if (!
set->isMarked())
855 set->removeUnmarkedKeys();
857 lastSet = &
set->nextWeakSet;
861GCState freeWeakSets(GCStateMachine *that, ExtraData &)
863 freeWeakSets(that->mm);
867GCState handleQObjectWrappers(GCStateMachine *that, ExtraData &)
869 that->mm->cleanupDeletedQObjectWrappersInSweep();
873GCState doSweep(GCStateMachine *that, ExtraData &)
877 mm->engine->identifierTable->sweep();
878 mm->blockAllocator.sweep();
879 mm->hugeItemAllocator.sweep(that->mm->gcCollectorStats ? increaseFreedCountForClass :
nullptr);
880 mm->icAllocator.sweep();
883 mm->blockAllocator.resetBlackBits();
884 mm->hugeItemAllocator.resetBlackBits();
885 mm->icAllocator.resetBlackBits();
887 mm->usedSlotsAfterLastFullSweep = mm->blockAllocator.usedSlotsAfterLastSweep + mm->icAllocator.usedSlotsAfterLastSweep;
888 mm->gcBlocked = MemoryManager::Unblocked;
889 mm->m_markStack.reset();
890 mm->engine->isGCOngoing =
false;
892 mm->updateUnmanagedHeapSizeGCLimit();
903 , blockAllocator(chunkAllocator,
engine)
904 , icAllocator(chunkAllocator,
engine)
905 , hugeItemAllocator(chunkAllocator,
engine)
908 , unmanagedHeapSizeGCLimit(MinUnmanagedHeapSizeGCLimit)
910 , gcStats(lcGcStats().isDebugEnabled())
911 , gcCollectorStats(lcGcAllocatorStats().isDebugEnabled())
913#ifdef V4_USE_VALGRIND
914 VALGRIND_CREATE_MEMPOOL(
this, 0,
true);
936 initMarkPersistentValues,
940 markPersistentValues,
960 initCallDestroyObjects,
976 handleQObjectWrappers,
995 memset(
m, 0, stringSize);
1020 if (nMembers <= vtable->nInlineProperties) {
1025 std::size_t memberSize =
align(
sizeof(Heap::MemberData) + (nMembers - 1)*
sizeof(
Value));
1026 size_t totalSize =
size + memberSize;
1027 Heap::MemberData *
m;
1034 o =
static_cast<Heap::Object *
>(
b);
1036 m = mh->as<Heap::MemberData>();
1045 m->values.alloc =
static_cast<uint>((memberSize -
sizeof(Heap::MemberData) +
sizeof(
Value))/
sizeof(
Value));
1046 m->values.size =
o->memberData->values.alloc;
1062 m_hardLimit = m_base +
size;
1063 m_softLimit = m_base +
size * 3 / 4;
1069 while (m_top > m_base) {
1073 h->internalClass->vtable->markObjects(
h,
this);
1080 for (
int i = 0;
i <= markLoopIterationCount * 10; ++
i) {
1081 if (m_top == m_base)
1086 h->internalClass->vtable->markObjects(
h,
this);
1118 if (!
m ||
m->markBit())
1123 qobjectWrapper->destroyObject(lastSweep);
1160 if (!
m ||
m->markBit())
1168 QVector<Value *> remainingWeakQObjectWrappers;
1169 remainingWeakQObjectWrappers.reserve(pendingCount);
1170 for (
int i = 0;
i < pendingCount; ++
i) {
1172 if (
v->isUndefined() ||
v->isEmpty())
1175 remainingWeakQObjectWrappers.append(
v);
1182 if (
it.value().isNullOrUndefined())
1183 it = multiplyWrappedQObjects->
erase(
it);
1190bool MemoryManager::shouldRunGC()
const
1201 size_t totalSlotMem = 0;
1203 qDebug(stats) <<
"Slot map for" <<
title <<
"allocator:";
1209 totalSlotMem +=
h->freeData.availableSlots;
1210 h =
h->freeData.next;
1213 qDebug(stats) <<
" number of entries in slot" <<
i <<
":" << nEntries;
1215 SDUMP() <<
" large slot map";
1219 h =
h->freeData.next;
1240 const bool incrementalGCIsAlreadyRunning =
m_markStack !=
nullptr;
1241 Q_ASSERT(incrementalGCIsAlreadyRunning);
1242 auto oldTimeLimit = std::exchange(
gcStateMachine->timeLimit, std::chrono::microseconds::max());
1253 const bool incrementalGCStillRunning =
m_markStack !=
nullptr;
1254 if (incrementalGCStillRunning)
1282 qDebug(stats) <<
"========== GC ==========";
1289 qDebug(stats) <<
"Allocated" << totalMem <<
"bytes in" << oldChunks <<
"chunks";
1290 qDebug(stats) <<
"Fragmented memory before GC" << (totalMem - usedBefore);
1297 qint64 markTime =
t.nsecsElapsed()/1000;
1302 if (triggeredByUnmanagedHeap) {
1303 qDebug(stats) <<
"triggered by unmanaged heap:";
1304 qDebug(stats) <<
" old unmanaged heap size:" << oldUnmanagedSize;
1310 qDebug(stats) <<
"Marked object in" << markTime <<
"us.";
1315 std::swap(freedObjectStats, *freedObjectStatsGlobal());
1316 typedef std::pair<const char*, int> ObjectStatInfo;
1317 std::vector<ObjectStatInfo> freedObjectsSorted;
1318 freedObjectsSorted.reserve(freedObjectStats.size());
1320 freedObjectsSorted.push_back(std::make_pair(
it.key(),
it.value()));
1322 std::sort(freedObjectsSorted.begin(), freedObjectsSorted.end(), [](
const ObjectStatInfo &
a,
const ObjectStatInfo &
b) {
1323 return a.second > b.second && strcmp(a.first, b.first) < 0;
1326 qDebug(stats) <<
"Used memory before GC:" << usedBefore;
1327 qDebug(stats) <<
"Used memory after GC:" << usedAfter;
1328 qDebug(stats) <<
"Freed up bytes :" << (usedBefore - usedAfter);
1331 - memInBins - usedAfter;
1333 qDebug(stats) <<
"!!!!!!!!!!!!!!!!!!!!! LOST MEM:" << lost <<
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
1334 if (largeItemsBefore || largeItemsAfter) {
1335 qDebug(stats) <<
"Large item memory before GC:" << largeItemsBefore;
1336 qDebug(stats) <<
"Large item memory after GC:" << largeItemsAfter;
1337 qDebug(stats) <<
"Large item memory freed up:" << (largeItemsBefore - largeItemsAfter);
1340 for (
auto it = freedObjectsSorted.
cbegin();
it != freedObjectsSorted.
cend(); ++
it) {
1344 qDebug(stats) <<
"======== End GC ========";
1425#ifdef V4_USE_VALGRIND
1426 VALGRIND_DESTROY_MEMPOOL(
this);
1438 qDebug(stats) <<
"Qml GC memory allocation statistics:";
1440 qDebug(stats) <<
"Max memory used before a GC run:" <<
statistics.maxAllocatedMem;
1441 qDebug(stats) <<
"Max memory used after a GC run:" <<
statistics.maxUsedMem;
1442 qDebug(stats) <<
"Requests for different item sizes:";
1466 timeLimit = std::chrono::milliseconds { (1000 / 60) / 3 };
1472 bool deadlineExpired =
false;
1488 if (stateInfo.breakAfter)
1491 if (deadlineExpired)
bool hasExpired() const noexcept
Returns true if this QDeadlineTimer object has expired, false if there remains time left.
static constexpr ForeverConstant Forever
void start() noexcept
\typealias QElapsedTimer::Duration Synonym for std::chrono::nanoseconds.
QObject * parent() const
Returns a pointer to the parent object.
static bool keepAliveDuringGarbageCollection(const QObject *object)
const_iterator constBegin() const noexcept
const_iterator cend() const noexcept
const_iterator constEnd() const noexcept
iterator erase(const_iterator i)
const_iterator cbegin() const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Heap::Base * allocString(std::size_t unmanagedSize)
expects size to be aligned
QVector< Value * > m_pendingFreedObjectWrapperValue
Heap::SetObject * weakSets
QV4::ExecutionEngine * engine
Heap::Object * allocObjectWithMemberData(const QV4::VTable *vtable, uint nMembers)
size_t getLargeItemsMem() const
bool tryForceGCCompletion()
size_t lastAllocRequestedSlots
std::unique_ptr< GCStateMachine > gcStateMachine
ObjectType::Data * allocate(Args &&... args)
struct QV4::MemoryManager::@640 statistics
ChunkAllocator * chunkAllocator
PersistentValueStorage * m_persistentValues
void collectFromJSStack(MarkStack *markStack) const
void sweep(bool lastSweep=false, ClassDestroyStatsCallback classCountPtr=nullptr)
void cleanupDeletedQObjectWrappersInSweep()
PersistentValueStorage * m_weakValues
std::size_t unmanagedHeapSize
void registerWeakMap(Heap::MapObject *map)
std::size_t usedSlotsAfterLastFullSweep
BlockAllocator blockAllocator
HugeItemAllocator hugeItemAllocator
size_t getUsedMem() const
std::unique_ptr< MarkStack > m_markStack
Heap::Base * allocData(std::size_t size)
size_t getAllocatedMem() const
void setGCTimeLimit(int timeMs)
void registerWeakSet(Heap::SetObject *set)
Heap::MapObject * weakMaps
void updateUnmanagedHeapSizeGCLimit()
std::size_t unmanagedHeapSizeGCLimit
static constexpr std::size_t align(std::size_t size)
BlockAllocator icAllocator
QMap< QString, QString > map
[6]
QSet< QString >::iterator it
Combined button and popup list for selecting options.
void(* ClassDestroyStatsCallback)(const char *)
static size_t dumpBins(BlockAllocator *b, const char *title)
static uint markStackSize
@ InitMarkPersistentValues
QHash< const char *, int > MMStatsHash
static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocator::HugeChunk &c, ClassDestroyStatsCallback classCountPtr)
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
constexpr uint qCountTrailingZeroBits(quint32 v) noexcept
Q_DECL_CONST_FUNCTION QT_POPCOUNT_CONSTEXPR uint qPopulationCount(quint32 v) noexcept
static bool testBit(long bit, const long *field)
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define Q_LOGGING_CATEGORY(name,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qMax(const T &a, const T &b)
GLsizei GLsizei GLenum void * binary
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLdouble GLdouble GLdouble GLdouble top
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLfloat GLfloat GLfloat GLfloat h
static constexpr qint64 HeaderSize
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
QT_BEGIN_NAMESPACE constexpr void qSwap(T &value1, T &value2) noexcept(std::is_nothrow_swappable_v< T >)
void gc(QV4::ExecutionEngine &engine, GCFlags flags)
Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
unsigned long long quint64
#define Q_V4_PROFILE_DEALLOC(engine, size, type)
#define Q_V4_PROFILE_ALLOC(engine, size, type)
const char className[16]
[1]
QFuture< QSet< QChar > > set
[10]
QDeadlineTimer deadline(30s)
size_t usedSlotsAfterLastSweep
std::vector< Chunk * > chunks
size_t totalSlots() const
size_t allocatedMem() const
void free(Chunk *chunk, size_t size=0)
size_t requiredChunkSize(size_t size)
std::vector< MemorySegment > memorySegments
static void setBit(quintptr *bitmap, size_t index)
static void clearBit(quintptr *bitmap, size_t index)
IdentifierTable * identifierTable
Heap::InternalClass * internalClasses(InternalClassType icType)
WTF::PageAllocation * gcStack
int maxGCStackSize() const
MultiplyWrappedQObjectMap * m_multiplyWrappedQObjects
std::variant< std::monostate, GCIteratorStorage > ExtraData
GCState(* execute)(GCStateMachine *, ExtraData &)
Q_QML_EXPORT void transition()
std::chrono::microseconds timeLimit
void handleTimeout(GCState state)
std::array< GCStateInfo, GCState::Count > stateInfoMap
struct QV4::HeapItem::@638::@641 freeData
Pointer< InternalClass *, 0 > internalClass
HeapItem * allocate(size_t size)
void sweep(ClassDestroyStatsCallback classCountPtr)
MarkStack(ExecutionEngine *engine)
ExecutionEngine * engine() const
void free(Chunk *chunk, size_t size)
MemorySegment(size_t size)
PageReservation pageReservation
void setBit(size_t index)
bool testBit(size_t index) const
void clearBit(size_t index)
bool contains(Chunk *c) const
MemorySegment(MemorySegment &&other)
static void free(Value *v)
quint16 inlinePropertyOffset
quint16 nInlineProperties
QML_NEARLY_ALWAYS_INLINE ManagedPtr managed() const
static constexpr Value undefinedValue()