From aebfad19b475eb41cc20d3439123f8759861e100 Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Tue, 26 Jan 2016 17:32:18 +0200 Subject: [PATCH] Ensure QObject wrappers are garbage-collected if appropriate upstrema commits: https://github.com/qtproject/qtscript/commit/378416af7542e34196908896c9a69573b995adb0 Signed-off-by: Ivailo Monev --- .../JavaScriptCore/runtime/Collector.cpp | 6 +++--- src/script/api/qscriptengine.cpp | 3 +++ src/script/bridge/qscriptqobject.cpp | 18 +++++++++++++----- src/script/bridge/qscriptqobject_p.h | 20 ++++++++++++++++++++ 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.cpp index cc17f07fe..0db970375 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Collector.cpp @@ -1102,9 +1102,6 @@ void Heap::markRoots() // Mark explicitly registered roots. markProtectedObjects(markStack); - if (m_globalData->clientData) - m_globalData->clientData->mark(markStack); - // Mark misc. other roots. if (m_markListSet && m_markListSet->size()) MarkedArgumentBuffer::markLists(markStack, *m_markListSet); @@ -1116,6 +1113,9 @@ void Heap::markRoots() if (m_globalData->firstStringifierToMark) JSONObject::markStringifiers(markStack, m_globalData->firstStringifierToMark); + if (m_globalData->clientData) + m_globalData->clientData->mark(markStack); + markStack.drain(); markStack.compact(); diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index 9f9f7c981..a16703adc 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -1258,6 +1258,9 @@ void QScriptEnginePrivate::setContextFlags(JSC::ExecState *exec, uint flags) } +// This function is called by JSC after all objects reachable by JSC itself +// have been processed (see JSC::Heap::markRoots()). +// Here we should mark additional objects managed by QtScript. void QScriptEnginePrivate::mark(JSC::MarkStack& markStack) { Q_Q(QScriptEngine); diff --git a/src/script/bridge/qscriptqobject.cpp b/src/script/bridge/qscriptqobject.cpp index 1a0f87d6a..e4601c6f7 100644 --- a/src/script/bridge/qscriptqobject.cpp +++ b/src/script/bridge/qscriptqobject.cpp @@ -96,7 +96,7 @@ struct QObjectConnection QObjectDelegate *inst = static_cast(delegate); if ((inst->ownership() == QScriptEngine::ScriptOwnership) || ((inst->ownership() == QScriptEngine::AutoOwnership) - && inst->value() && !inst->value()->parent())) { + && !inst->hasParent())) { senderWrapper = JSC::JSValue(); } else { markStack.append(senderWrapper); @@ -2319,6 +2319,10 @@ QObjectData::~QObjectData() } } +// This function assumes all objects reachable elsewhere in the JS environment +// (stack, heap) have been marked already (see QScriptEnginePrivate::mark()). +// This determines whether any of QtScript's internal QObject wrappers are only +// weakly referenced and can be discarded. void QObjectData::mark(JSC::MarkStack& markStack) { if (connectionManager) @@ -2327,10 +2331,14 @@ void QObjectData::mark(JSC::MarkStack& markStack) QList::iterator it; for (it = wrappers.begin(); it != wrappers.end(); ) { const QScript::QObjectWrapperInfo &info = *it; - // ### don't mark if there are no other references. - // we need something like isMarked() - markStack.append(info.object); - ++it; + if (JSC::Heap::isCellMarked(info.object)) { + ++it; + } else if (info.isCollectableWhenWeaklyReferenced()) { + it = wrappers.erase(it); + } else { + markStack.append(info.object); + ++it; + } } } } diff --git a/src/script/bridge/qscriptqobject_p.h b/src/script/bridge/qscriptqobject_p.h index c635c91e0..cf44de996 100644 --- a/src/script/bridge/qscriptqobject_p.h +++ b/src/script/bridge/qscriptqobject_p.h @@ -95,6 +95,7 @@ public: inline QObject *value() const { return data->value; } inline void setValue(QObject* value) { data->value = value; } + inline bool hasParent() const { return data->value && data->value->parent(); } inline QScriptEngine::ValueOwnership ownership() const { return data->ownership; } @@ -138,6 +139,25 @@ struct QObjectWrapperInfo QScriptObject *object; QScriptEngine::ValueOwnership ownership; QScriptEngine::QObjectWrapOptions options; + + // Returns true if this wrapper can be garbage-collected when there are no + // other references to it in the JS environment (weak reference), otherwise + // returns false (should not be collected). + bool isCollectableWhenWeaklyReferenced() const + { + switch (ownership) { + case QScriptEngine::ScriptOwnership: + return true; + case QScriptEngine::AutoOwnership: { + QScriptObjectDelegate *delegate = object->delegate(); + Q_ASSERT(delegate && (delegate->type() == QScriptObjectDelegate::QtObject)); + return !static_cast(delegate)->hasParent(); + } + default: + break; + } + return false; + } }; class QObjectData // : public QObjectUserData -- 2.11.0