aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/memory/qv4mm_p.h
diff options
context:
space:
mode:
authorFabian Kosmale <fabian.kosmale@qt.io>2023-11-21 19:36:26 +0100
committerFabian Kosmale <fabian.kosmale@qt.io>2023-12-20 08:38:26 +0100
commitb9d37a328ba09bcb2a7a95b5778cb8c63d0ace26 (patch)
tree340739253c3e15f0b6c051434d94061e8e3385c6 /src/qml/memory/qv4mm_p.h
parentd08ede57dd530a67c3420b3858fe39bf1e5eb598 (diff)
Long live incremental garbage collection in QML!
The design of the garbage collector is described in src/qml/memory/design.md. The gc and gcdone test helpers are adjusted to drive the gc to completion, even when in incremental mode. Parts of tst_qv4mm and tst_qqmlqt need to run with the incremental gc disabled, as they call gc inside QML and assumes that the GC finishes before returning. Initial-patch-by: Rafal Chomentowski <rafal.chomentowski@ge.com> Task-number: QTBUG-119274 Change-Id: I1d94f41bc7a434fad67de0fd46454b6db285f2eb Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/qml/memory/qv4mm_p.h')
-rw-r--r--src/qml/memory/qv4mm_p.h85
1 files changed, 83 insertions, 2 deletions
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index 3a05bca536..9ed5b946b7 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -28,6 +28,68 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+enum GCState {
+ MarkStart = 0,
+ MarkGlobalObject,
+ MarkJSStack,
+ InitMarkPersistentValues,
+ MarkPersistentValues,
+ InitMarkWeakValues,
+ MarkWeakValues,
+ MarkDrain,
+ MarkReady,
+ Sweep,
+ Invalid,
+ Count,
+};
+
+struct GCData { virtual ~GCData(){};};
+
+struct GCIteratorStorage {
+ PersistentValueStorage::Iterator it{nullptr, 0};
+};
+struct GCStateMachine;
+
+struct GCStateInfo {
+ using ExtraData = std::variant<std::monostate, GCIteratorStorage>;
+ GCState (*execute)(GCStateMachine *, ExtraData &) = nullptr; // Function to execute for this state, returns true if ready to transition
+ bool breakAfter{false};
+};
+
+struct GCStateMachine {
+ using ExtraData = GCStateInfo::ExtraData;
+ GCState state{GCState::Invalid};
+ std::chrono::microseconds timeLimit{};
+ QDeadlineTimer deadline;
+ std::array<GCStateInfo, GCState::Count> stateInfoMap;
+ MemoryManager *mm = nullptr;
+ ExtraData stateData; // extra date for specific states
+
+ GCStateMachine();
+
+ inline void step() {
+ if (!inProgress()) {
+ reset();
+ }
+ transition();
+ }
+
+ inline bool inProgress() {
+ return state != GCState::Invalid;
+ }
+
+ inline void reset() {
+ state = GCState::MarkStart;
+ }
+
+ Q_QML_EXPORT void transition();
+
+ inline void handleTimeout(GCState state) {
+ Q_UNUSED(state);
+ }
+};
+
+
struct ChunkAllocator;
struct MemorySegment;
@@ -258,12 +320,24 @@ public:
typename ManagedType::Data *allocIC()
{
Heap::Base *b = *allocate(&icAllocator, align(sizeof(typename ManagedType::Data)));
+ if (m_markStack) {
+ // If the gc is running right now, it will not have a chance to mark the newly created item
+ // and may therefore sweep it right away.
+ // Protect the new object from the current GC run to avoid this.
+ b->setMarkBit();
+ }
return static_cast<typename ManagedType::Data *>(b);
}
void registerWeakMap(Heap::MapObject *map);
void registerWeakSet(Heap::SetObject *set);
+ void onEventLoop();
+
+ //GC related methods
+ void setGCTimeLimit(int timeMs);
+ MarkStack* markStack() { return m_markStack.get(); }
+
protected:
/// expects size to be aligned
Heap::Base *allocString(std::size_t unmanagedSize);
@@ -275,14 +349,18 @@ private:
MinUnmanagedHeapSizeGCLimit = 128 * 1024
};
+public:
void collectFromJSStack(MarkStack *markStack) const;
- void mark();
void sweep(bool lastSweep = false, ClassDestroyStatsCallback classCountPtr = nullptr);
+private:
bool shouldRunGC() const;
- void collectRoots(MarkStack *markStack);
HeapItem *allocate(BlockAllocator *allocator, std::size_t size)
{
+ // We must not call runGC if incremental gc is running
+ // so temporarily set gcBlocked in that case, too
+ QBoolBlocker block(gcBlocked, m_markStack != nullptr || gcBlocked);
+
bool didGCRun = false;
if (aggressiveGC) {
runGC();
@@ -329,6 +407,9 @@ public:
Heap::MapObject *weakMaps = nullptr;
Heap::SetObject *weakSets = nullptr;
+ std::unique_ptr<GCStateMachine> gcStateMachine{nullptr};
+ std::unique_ptr<MarkStack> m_markStack{nullptr};
+
std::size_t unmanagedHeapSize = 0; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items.
std::size_t unmanagedHeapSizeGCLimit;
std::size_t usedSlotsAfterLastFullSweep = 0;