aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
authorFabian Kosmale <[email protected]>2023-11-21 19:36:26 +0100
committerFabian Kosmale <[email protected]>2023-12-20 08:38:26 +0100
commitb9d37a328ba09bcb2a7a95b5778cb8c63d0ace26 (patch)
tree340739253c3e15f0b6c051434d94061e8e3385c6 /src/qml/jsruntime
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 <[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.h3
-rw-r--r--src/qml/jsruntime/qv4identifiertable.cpp5
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp14
-rw-r--r--src/qml/jsruntime/qv4persistent.cpp18
-rw-r--r--src/qml/jsruntime/qv4propertykey.cpp1
-rw-r--r--src/qml/jsruntime/qv4propertykey_p.h12
-rw-r--r--src/qml/jsruntime/qv4symbol.cpp2
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)