diff options
author | Fabian Kosmale <[email protected]> | 2023-11-21 19:36:26 +0100 |
---|---|---|
committer | Fabian Kosmale <[email protected]> | 2023-12-20 08:38:26 +0100 |
commit | b9d37a328ba09bcb2a7a95b5778cb8c63d0ace26 (patch) | |
tree | 340739253c3e15f0b6c051434d94061e8e3385c6 /src/qml/jsruntime | |
parent | d08ede57dd530a67c3420b3858fe39bf1e5eb598 (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 <[email protected]>
Task-number: QTBUG-119274
Change-Id: I1d94f41bc7a434fad67de0fd46454b6db285f2eb
Reviewed-by: Ulf Hermann <[email protected]>
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r-- | src/qml/jsruntime/qv4enginebase_p.h | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4identifiertable.cpp | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4internalclass.cpp | 14 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4persistent.cpp | 18 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4propertykey.cpp | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4propertykey_p.h | 12 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4symbol.cpp | 2 |
7 files changed, 49 insertions, 6 deletions
diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h index 721a024efb..68e906baa1 100644 --- a/src/qml/jsruntime/qv4enginebase_p.h +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -45,7 +45,8 @@ struct Q_QML_EXPORT EngineBase { quint8 isExecutingInRegExpJIT = false; quint8 isInitialized = false; - quint8 padding[2]; + quint8 inShutdown = false; + quint8 isGCOngoing = false; // incremental gc is ongoing (but mutator might be running) MemoryManager *memoryManager = nullptr; union { diff --git a/src/qml/jsruntime/qv4identifiertable.cpp b/src/qml/jsruntime/qv4identifiertable.cpp index d8999951dc..4c915442f4 100644 --- a/src/qml/jsruntime/qv4identifiertable.cpp +++ b/src/qml/jsruntime/qv4identifiertable.cpp @@ -36,7 +36,7 @@ void IdentifierTable::addEntry(Heap::StringOrSymbol *str) if (str->subtype == Heap::String::StringType_ArrayIndex) return; - str->identifier = PropertyKey::fromStringOrSymbol(str); + str->identifier = PropertyKey::fromStringOrSymbol(engine, str); bool grow = (alloc <= size*2); @@ -165,6 +165,9 @@ PropertyKey IdentifierTable::asPropertyKeyImpl(const Heap::String *str) while (Heap::StringOrSymbol *e = entriesByHash[idx]) { if (e->stringHash == hash && e->toQString() == str->toQString()) { str->identifier = e->identifier; + QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) { + e->identifier.asStringOrSymbol()->mark(stack); + }); return e->identifier; } ++idx; diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp index e4c401f5a7..ddf38c968d 100644 --- a/src/qml/jsruntime/qv4internalclass.cpp +++ b/src/qml/jsruntime/qv4internalclass.cpp @@ -122,6 +122,11 @@ PropertyKey SharedInternalClassDataPrivate<PropertyKey>::at(uint i) const void SharedInternalClassDataPrivate<PropertyKey>::set(uint i, PropertyKey t) { Q_ASSERT(data && i < size()); + QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) { + if constexpr (QV4::WriteBarrier::isInsertionBarrier) + if (auto string = t.asStringOrSymbol()) + string->mark(stack); + }); data->values.values[i].rawValueRef() = t.id(); } @@ -256,6 +261,11 @@ void InternalClass::init(Heap::InternalClass *other) protoId = engine->newProtoId(); internalClass.set(engine, other->internalClass); + QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) { + if constexpr (QV4::WriteBarrier::isInsertionBarrier) { + other->mark(stack); + } + }); } void InternalClass::destroy() @@ -476,6 +486,10 @@ Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto) // create a new class and add it to the tree Heap::InternalClass *newClass = engine->newClass(this); + QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) { + if (proto && QV4::WriteBarrier::isInsertionBarrier) + proto->mark(stack); + }); newClass->prototype = proto; t.lookup = newClass; diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index 75353935a1..3cbaec1dac 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -171,7 +171,7 @@ Value *PersistentValueStorage::allocate() Value *v = p->values + p->header.freeList; p->header.freeList = v->int_32(); - if (p->header.freeList != -1 && p != firstPage) { + if (p->header.freeList != -1 && p != firstPage && !engine->isGCOngoing) { unlink(p); insertInFront(this, p); } @@ -304,6 +304,10 @@ void PersistentValue::set(ExecutionEngine *engine, const Value &value) { if (!val) val = engine->memoryManager->m_persistentValues->allocate(); + QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack){ + if (QV4::WriteBarrier::isInsertionBarrier && value.isManaged()) + stack->push(value.heapObject()); + }); *val = value; } @@ -311,6 +315,13 @@ void PersistentValue::set(ExecutionEngine *engine, ReturnedValue value) { if (!val) val = engine->memoryManager->m_persistentValues->allocate(); + QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack){ + if constexpr (!QV4::WriteBarrier::isInsertionBarrier) + return; + auto val = Value::fromReturnedValue(value); + if (val.isManaged()) + stack->push(val.heapObject()); + }); *val = value; } @@ -318,6 +329,11 @@ void PersistentValue::set(ExecutionEngine *engine, Heap::Base *obj) { if (!val) val = engine->memoryManager->m_persistentValues->allocate(); + QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack){ + if constexpr (QV4::WriteBarrier::isInsertionBarrier) + stack->push(obj); + }); + *val = obj; } diff --git a/src/qml/jsruntime/qv4propertykey.cpp b/src/qml/jsruntime/qv4propertykey.cpp index d93ff8e794..65dd7e7fc1 100644 --- a/src/qml/jsruntime/qv4propertykey.cpp +++ b/src/qml/jsruntime/qv4propertykey.cpp @@ -7,6 +7,7 @@ #include <qv4string_p.h> #include <qv4engine_p.h> #include <qv4scopedvalue_p.h> +#include <private/qv4mm_p.h> using namespace Qt::Literals::StringLiterals; diff --git a/src/qml/jsruntime/qv4propertykey_p.h b/src/qml/jsruntime/qv4propertykey_p.h index 0b8ad084d2..d6d15e402d 100644 --- a/src/qml/jsruntime/qv4propertykey_p.h +++ b/src/qml/jsruntime/qv4propertykey_p.h @@ -14,6 +14,7 @@ // We mean it. // +#include <private/qv4writebarrier_p.h> #include <private/qv4global_p.h> #include <private/qv4staticvalue_p.h> #include <QtCore/qhashfunctions.h> @@ -70,11 +71,18 @@ public: // We cannot #include the declaration of Heap::StringOrSymbol here. // Therefore we do some gymnastics to enforce the type safety. - template<typename StringOrSymbol = Heap::StringOrSymbol> - static PropertyKey fromStringOrSymbol(StringOrSymbol *b) + template<typename StringOrSymbol = Heap::StringOrSymbol, typename Engine = QV4::EngineBase> + static PropertyKey fromStringOrSymbol(Engine *engine, StringOrSymbol *b) { static_assert(std::is_base_of_v<Heap::StringOrSymbol, StringOrSymbol>); PropertyKey key; + QV4::WriteBarrier::markCustom(engine, [&](QV4::MarkStack *stack) { + if constexpr (QV4::WriteBarrier::isInsertionBarrier) { + // treat this as an insertion - the StringOrSymbol becomes reachable + // via the propertykey, so we consequently need to mark it durnig gc + b->mark(stack); + } + }); key.val.setM(b); Q_ASSERT(key.isManaged()); return key; diff --git a/src/qml/jsruntime/qv4symbol.cpp b/src/qml/jsruntime/qv4symbol.cpp index 585038937e..5f7ec89fd2 100644 --- a/src/qml/jsruntime/qv4symbol.cpp +++ b/src/qml/jsruntime/qv4symbol.cpp @@ -16,7 +16,7 @@ void Heap::Symbol::init(const QString &s) Q_ASSERT(s.at(0) == QLatin1Char('@')); QString desc(s); StringOrSymbol::init(desc.data_ptr()); - identifier = PropertyKey::fromStringOrSymbol(this); + identifier = PropertyKey::fromStringOrSymbol(internalClass->engine, this); } void Heap::SymbolCtor::init(QV4::ExecutionContext *scope) |