diff options
| -rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 34 | ||||
| -rw-r--r-- | tests/auto/qml/qqmlecmascript/data/frozenQObject3.qml | 30 | ||||
| -rw-r--r-- | tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 24 |
3 files changed, 85 insertions, 3 deletions
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index ad10053394..c01f6986be 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -1328,9 +1328,37 @@ void Heap::QObjectWrapper::markObjects(Heap::Base *that, MarkStack *markStack) QObjectWrapper *This = static_cast<QObjectWrapper *>(that); if (QObject *o = This->object()) { - QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o); - if (vme) - vme->mark(markStack); + if (QQmlData *ddata = QQmlData::get(o)) { + if (ddata->hasVMEMetaObject) { + if (QQmlVMEMetaObject *vme + = static_cast<QQmlVMEMetaObject *>(QObjectPrivate::get(o)->metaObject)) { + vme->mark(markStack); + } + } + + if (ddata->hasConstWrapper) { + Scope scope(that->internalClass->engine); + Q_ASSERT(scope.engine->m_multiplyWrappedQObjects); + + Scoped<QV4::QObjectWrapper> constWrapper( + scope, + scope.engine->m_multiplyWrappedQObjects->value( + static_cast<const QObject *>(o))); + + Q_ASSERT(constWrapper); + + if (This == constWrapper->d()) { + // We've got the const wrapper. Also mark the non-const one + if (ddata->jsEngineId == scope.engine->m_engineId) + ddata->jsWrapper.markOnce(markStack); + else + scope.engine->m_multiplyWrappedQObjects->mark(o, markStack); + } else { + // We've got the non-const wrapper. Also mark the const one. + constWrapper->mark(markStack); + } + } + } // 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 diff --git a/tests/auto/qml/qqmlecmascript/data/frozenQObject3.qml b/tests/auto/qml/qqmlecmascript/data/frozenQObject3.qml new file mode 100644 index 0000000000..51c321684e --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/frozenQObject3.qml @@ -0,0 +1,30 @@ +import QtQml +import test + +QtObject { + id: root + + property FrozenObjects a: FrozenObjects { objectName: "a" } + property FrozenObjects b: FrozenObjects { objectName: "b" } + + // Create wrappers and immediately discard them + objectName: a.getConst().objectName + "/" + b.getNonConst().objectName + + // Create a non-const wrapper and retain it + property var objNonConst: a.getNonConst() + + // Create a const wrapper and retain it + property var objConst: b.getConst() + + property int gcs: 0 + + property Timer t: Timer { + interval: 1 + running: true + repeat: true + onTriggered: { + gc(); + ++root.gcs; + } + } +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index c6d73dabb0..788e78b0f1 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -10079,6 +10079,9 @@ public: Q_INVOKABLE void triggerSignal() { emit fooMember2Emitted(&m_fooMember2); } + Q_INVOKABLE const FrozenFoo *getConst() { return createFloating(); } + Q_INVOKABLE FrozenFoo *getNonConst() { return createFloating(); } + FrozenFoo *fooMember() { return &m_fooMember; } FrozenFoo *fooMember2() { return &m_fooMember2; } @@ -10088,6 +10091,16 @@ signals: private: const FrozenFoo *fooMemberConst() const { return &m_fooMember; } + FrozenFoo *createFloating() + { + if (!m_floating) { + m_floating = new FrozenFoo; + m_floating->setObjectName(objectName()); + } + return m_floating; + } + + FrozenFoo *m_floating = nullptr; FrozenFoo m_fooMember; FrozenFoo m_fooMember2; }; @@ -10110,6 +10123,17 @@ void tst_qqmlecmascript::frozenQObject() QVERIFY(frozenObjects->property("caughtSignal").toBool()); QCOMPARE(frozenObjects->fooMember()->name(), QStringLiteral("Jane")); QCOMPARE(frozenObjects->fooMember2()->name(), QStringLiteral("Jane")); + + QQmlComponent component3(&engine, testFileUrl("frozenQObject3.qml")); + QScopedPointer<QObject> root3(component3.create()); + QCOMPARE(root3->objectName(), QLatin1String("a/b")); + QVERIFY(root3->property("objConst").value<QObject *>()); + QVERIFY(root3->property("objNonConst").value<QObject *>()); + + QTRY_VERIFY(root3->property("gcs").toInt() > 8); + + QVERIFY(root3->property("objConst").value<QObject *>()); + QVERIFY(root3->property("objNonConst").value<QObject *>()); } struct ConstPointer : QObject |
