diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2013-05-24 17:12:57 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@digia.com> | 2013-05-24 19:48:37 +0200 |
commit | de6642b1a97840e204f9d45275ca29a859a890d0 (patch) | |
tree | 5936ca3fa90ce9199459e16c0379424923a6ae46 | |
parent | 788252a2e80ef7e27ab1347d998b482091f93863 (diff) |
Implement JS ownership policy for var and variant properties
Instead of a GC callback, let's keep the lifecycle of the var properties and
the QObject wrapped variants in sync with the lifecycle of the JS QObject
wrapper, through a markObjects re-implementation.
handleReferenceManagement test passes now, fixed a few incorrect gc() calls
in there.
Change-Id: I78e8ca700e41bba788b61d3816a77cfb3a7c5e58
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r-- | src/qml/qml/qqmlvmemetaobject.cpp | 76 | ||||
-rw-r--r-- | src/qml/qml/qqmlvmemetaobject_p.h | 11 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4value.cpp | 9 | ||||
-rw-r--r-- | src/qml/qml/v4/qv4value_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/v8/qv8qobjectwrapper.cpp | 11 | ||||
-rw-r--r-- | src/qml/qml/v8/qv8qobjectwrapper_p.h | 1 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 18 |
7 files changed, 66 insertions, 62 deletions
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 995b01264f..cec50ddd5b 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -554,7 +554,7 @@ QAbstractDynamicMetaObject *QQmlVMEMetaObject::toDynamicMetaObject(QObject *o) QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, const QQmlVMEMetaData *meta) -: QV8GCCallback::Node(GcPrologueCallback), object(obj), +: object(obj), ctxt(QQmlData::get(obj, true)->outerContext), cache(cache), metaData(meta), hasAssignedMetaObjectData(false), data(0), aliasEndpoints(0), firstVarPropertyIndex(-1), varPropertiesInitialized(false), interceptors(0), v8methods(0) @@ -577,7 +577,10 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, int list_type = qMetaTypeId<QQmlListProperty<QObject> >(); int qobject_type = qMetaTypeId<QObject*>(); int variant_type = qMetaTypeId<QVariant>(); - bool needsGcCallback = (metaData->varPropertyCount > 0); + // Need JS wrapper to ensure variant and var properties are marked. + // ### FIXME: I hope that this can be removed once we have the proper scope chain + // set up and the JS wrappers always exist. + bool needsJSWrapper = (metaData->varPropertyCount > 0); // ### Optimize for (int ii = 0; ii < metaData->propertyCount - metaData->varPropertyCount; ++ii) { @@ -585,20 +588,15 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, if (t == list_type) { listProperties.append(List(methodOffset() + ii, this)); data[ii].setValue(listProperties.count() - 1); - } else if (!needsGcCallback && (t == qobject_type || t == variant_type)) { - needsGcCallback = true; + } else if (!needsJSWrapper && (t == qobject_type || t == variant_type)) { + needsJSWrapper = true; } } firstVarPropertyIndex = metaData->propertyCount - metaData->varPropertyCount; - // both var properties and variant properties can keep references to - // other QObjects, and var properties can also keep references to - // JavaScript objects. If we have any properties, we need to hook - // the gc() to ensure that references keep objects alive as needed. - if (needsGcCallback) { - QV8GCCallback::addGcCallbackNode(this); - } + if (needsJSWrapper) + ensureQObjectWrapper(); } QQmlVMEMetaObject::~QQmlVMEMetaObject() @@ -1207,57 +1205,39 @@ bool QQmlVMEMetaObject::ensureVarPropertiesAllocated() return !varProperties.isEmpty(); } -// see also: QV8GCCallback::garbageCollectorPrologueCallback() -void QQmlVMEMetaObject::allocateVarPropertiesArray() +void QQmlVMEMetaObject::ensureQObjectWrapper() { - varProperties = v8::Array::New(metaData->varPropertyCount)->v4Value(); - // ### FIXME -// varProperties.MakeWeak(static_cast<void*>(this), VarPropertiesWeakReferenceCallback); - varPropertiesInitialized = true; -} - -/* - The "var" properties are stored in a v8::Array which will be strong persistent if the object has cpp-ownership - and the root QObject in the parent chain does not have JS-ownership. In the weak persistent handle case, - this callback will dispose the handle when the v8object which owns the lifetime of the var properties array - is cleared as a result of all other handles to that v8object being released. - See QV8GCCallback::garbageCollectorPrologueCallback() for more information. - */ -void QQmlVMEMetaObject::VarPropertiesWeakReferenceCallback(QV4::PersistentValue &object, void* parameter) -{ - // ### FIXME - QQmlVMEMetaObject *vmemo = static_cast<QQmlVMEMetaObject*>(parameter); - Q_ASSERT(vmemo); - object.clear(); - vmemo->varProperties.clear(); + QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine); + QV8Engine *v8e = (ep == 0) ? 0 : ep->v8engine(); + v8e->newQObject(object); } -void QQmlVMEMetaObject::GcPrologueCallback(QV8GCCallback::Node *node) +void QQmlVMEMetaObject::mark() { - QQmlVMEMetaObject *vmemo = static_cast<QQmlVMEMetaObject*>(node); - Q_ASSERT(vmemo); - - if (!vmemo->ctxt || !vmemo->ctxt->engine) - return; - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(vmemo->ctxt->engine); + varProperties.markOnce(); // add references created by VMEVariant properties - int maxDataIdx = vmemo->metaData->propertyCount - vmemo->metaData->varPropertyCount; + int maxDataIdx = metaData->propertyCount - metaData->varPropertyCount; for (int ii = 0; ii < maxDataIdx; ++ii) { // XXX TODO: optimize? - if (vmemo->data[ii].dataType() == QMetaType::QObjectStar) { + if (data[ii].dataType() == QMetaType::QObjectStar) { // possible QObject reference. - QObject *ref = vmemo->data[ii].asQObject(); + QObject *ref = data[ii].asQObject(); if (ref) { - ep->v8engine()->addRelationshipForGC(vmemo->object, ref); + QQmlData *ddata = QQmlData::get(ref); + if (ddata) + ddata->v8object.markOnce(); } } } +} - // add references created by var properties - if (!vmemo->varPropertiesInitialized || vmemo->varProperties.isEmpty()) - return; +// see also: QV8GCCallback::garbageCollectorPrologueCallback() +void QQmlVMEMetaObject::allocateVarPropertiesArray() +{ + varProperties = v8::Array::New(metaData->varPropertyCount)->v4Value(); // ### FIXME - // ep->v8engine()->addRelationshipForGC(vmemo->object, vmemo->varProperties); +// varProperties.MakeWeak(static_cast<void*>(this), VarPropertiesWeakReferenceCallback); + varPropertiesInitialized = true; } bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h index cb437683e5..d0e86a1e6d 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -159,8 +159,7 @@ class QV8QObjectWrapper; class QQmlVMEVariant; class QQmlRefCount; class QQmlVMEMetaObjectEndpoint; -class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QAbstractDynamicMetaObject, - public QV8GCCallback::Node +class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QAbstractDynamicMetaObject { public: QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, const QQmlVMEMetaData *data); @@ -205,14 +204,16 @@ public: QQmlVMEVariant *data; QQmlVMEMetaObjectEndpoint *aliasEndpoints; - QV4::PersistentValue varProperties; + QV4::WeakValue varProperties; int firstVarPropertyIndex; bool varPropertiesInitialized; - static void VarPropertiesWeakReferenceCallback(QV4::PersistentValue &object, void* parameter); - static void GcPrologueCallback(QV8GCCallback::Node *node); inline void allocateVarPropertiesArray(); inline bool ensureVarPropertiesAllocated(); + void ensureQObjectWrapper(); + + void mark(); + void connectAlias(int aliasId); QBitArray aConnected; diff --git a/src/qml/qml/v4/qv4value.cpp b/src/qml/qml/v4/qv4value.cpp index a86e886c6c..a6f5beb99f 100644 --- a/src/qml/qml/v4/qv4value.cpp +++ b/src/qml/qml/v4/qv4value.cpp @@ -345,6 +345,15 @@ WeakValue::~WeakValue() d->deref(); } +void WeakValue::markOnce() +{ + if (!d) + return; + Managed *m = d->value.asManaged(); + if (!m) + return; + m->mark(); +} PersistentValuePrivate::PersistentValuePrivate(const Value &v, bool weak) : value(v) diff --git a/src/qml/qml/v4/qv4value_p.h b/src/qml/qml/v4/qv4value_p.h index 673fa7c91d..cc0f1c2ea7 100644 --- a/src/qml/qml/v4/qv4value_p.h +++ b/src/qml/qml/v4/qv4value_p.h @@ -634,6 +634,8 @@ public: *this = WeakValue(); } + void markOnce(); + private: PersistentValuePrivate *d; }; diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp index 2457fb81d5..5e69ba208a 100644 --- a/src/qml/qml/v8/qv8qobjectwrapper.cpp +++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp @@ -255,6 +255,17 @@ QV4::Value QObjectWrapper::enumerateProperties(Object *object) return QV4::Value::fromObject(that->engine()->newArrayObject(result)); } +void QObjectWrapper::markObjects(Managed *that) +{ + QObjectWrapper *This = static_cast<QObjectWrapper*>(that); + + QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(This->object); + if (vme) + vme->mark(); + + QV4::Object::markObjects(that); +} + DEFINE_MANAGED_VTABLE(QObjectWrapper); // XXX TODO: Need to review all calls to QQmlEngine *engine() to confirm QObjects work diff --git a/src/qml/qml/v8/qv8qobjectwrapper_p.h b/src/qml/qml/v8/qv8qobjectwrapper_p.h index bde2018693..5819000abd 100644 --- a/src/qml/qml/v8/qv8qobjectwrapper_p.h +++ b/src/qml/qml/v8/qv8qobjectwrapper_p.h @@ -96,6 +96,7 @@ private: static Value get(Managed *m, ExecutionContext *ctx, String *name, bool *hasProperty); static void put(Managed *m, ExecutionContext *ctx, String *name, const Value &value); + static void markObjects(Managed *that); static Value enumerateProperties(Object *object); diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 60a087ec72..4e50184930 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -5052,11 +5052,11 @@ void tst_qqmlecmascript::handleReferenceManagement() QObject *object = component.create(); QVERIFY(object != 0); QMetaObject::invokeMethod(object, "createReference"); - gc(engine); + gc(hrmEngine); QMetaObject::invokeMethod(object, "ensureReference"); - gc(engine); + gc(hrmEngine); QMetaObject::invokeMethod(object, "removeReference"); - gc(engine); + gc(hrmEngine); QMetaObject::invokeMethod(object, "ensureDeletion"); QCOMPARE(object->property("success").toBool(), true); delete object; @@ -5069,11 +5069,11 @@ void tst_qqmlecmascript::handleReferenceManagement() QObject *object = component.create(); QVERIFY(object != 0); QMetaObject::invokeMethod(object, "createReference"); - gc(engine); + gc(hrmEngine); QMetaObject::invokeMethod(object, "ensureReference"); - gc(engine); + gc(hrmEngine); QMetaObject::invokeMethod(object, "removeReference"); - gc(engine); + gc(hrmEngine); QMetaObject::invokeMethod(object, "ensureDeletion"); QCOMPARE(object->property("success").toBool(), true); delete object; @@ -5086,11 +5086,11 @@ void tst_qqmlecmascript::handleReferenceManagement() QObject *object = component.create(); QVERIFY(object != 0); QMetaObject::invokeMethod(object, "createReference"); - gc(engine); + gc(hrmEngine); QMetaObject::invokeMethod(object, "ensureReference"); - gc(engine); + gc(hrmEngine); QMetaObject::invokeMethod(object, "manuallyDelete"); - gc(engine); + gc(hrmEngine); QMetaObject::invokeMethod(object, "ensureDeleted"); QCOMPARE(object->property("success").toBool(), true); delete object; |