From 8833ade28b06f9951a6ae671dfdfcaced98d06b8 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 14 Jun 2013 12:21:45 +0200 Subject: [PATCH] Fix JS ownership of children of marked but floating QObjects This patch fixes four qqmlecmascript tests: propertyVarImplicitOwnership, propertyVarReparent, propertyVarReparentNullContext, propertyVarCircular2 Usually QObjects wrapped in JS are kept alive because the GC knows about their weak values stored in the QQmlData, and so it has to do few steps only to locate those and mark them. A slightly less common case is a QObject that's wrapped in JS, without a parent and is stored in a var or variant property. It's visible to the GC, but the only strong reference to it is through that var property. So when such an object gets marked (it's without parent), we also have to mark the child QObjects's JS wrappers (if existent), all recursively. Change-Id: Ice347a37a841212c145b6d7a58216e449e5cce08 Reviewed-by: Lars Knoll --- src/qml/qml/v4/qv4qobjectwrapper.cpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/qml/qml/v4/qv4qobjectwrapper.cpp b/src/qml/qml/v4/qv4qobjectwrapper.cpp index 5da472b..087458d 100644 --- a/src/qml/qml/v4/qv4qobjectwrapper.cpp +++ b/src/qml/qml/v4/qv4qobjectwrapper.cpp @@ -856,13 +856,34 @@ Value QObjectWrapper::method_disconnect(SimpleCallContext *ctx) return QV4::Value::undefinedValue(); } +static void markChildQObjectsRecursively(QObject *parent) +{ + const QObjectList &children = parent->children(); + for (int i = 0; i < children.count(); ++i) { + QObject *child = children.at(i); + QQmlData *ddata = QQmlData::get(child, /*create*/false); + if (ddata) + ddata->jsWrapper.markOnce(); + markChildQObjectsRecursively(child); + } +} + void QObjectWrapper::markObjects(Managed *that) { QObjectWrapper *This = static_cast(that); - QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(This->m_object); - if (vme) - vme->mark(); + if (QObject *o = This->m_object.data()) { + QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o); + if (vme) + vme->mark(); + + // Children usually don't need to be marked, the gc keeps them alive. + // But in the rare case of a "floating" QObject without a parent that + // _gets_ marked (we've been called here!) then we also need to + // propagate the marking down to the children recursively. + if (!o->parent()) + markChildQObjectsRecursively(o); + } QV4::Object::markObjects(that); } -- 2.7.4