From: Simon Hausmann Date: Fri, 14 Jun 2013 10:21:45 +0000 (+0200) Subject: Fix JS ownership of children of marked but floating QObjects X-Git-Tag: upstream/5.2.1~669^2~213 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8833ade28b06f9951a6ae671dfdfcaced98d06b8;p=platform%2Fupstream%2Fqtdeclarative.git 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 --- 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); }