diff options
author | Lars Knoll <lars.knoll@digia.com> | 2013-10-14 16:48:30 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-10-15 06:43:34 +0200 |
commit | df267e50195c00f2085ed93ceb5f59ed81f89206 (patch) | |
tree | 2f8eb9115b4b1620028b795e52d2d96a460c9446 | |
parent | 1be51cc3e7c9ca5256a52136d6fcc9c22c997625 (diff) |
Fix GC issue with incubators
Never use multiple inheritance with Managed subclasses,
as this can easily mess up garbage collection. In this
case the vtable from the QQmlIncubator would be added
before the start of the Managed pointer. That would
not work correctly for the memory manager that casts
void pointers to Managed pointers.
Change-Id: I1c1ebc6c44bd9cb77eea49738e86ce3374c7ef80
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
-rw-r--r-- | src/qml/qml/qqmlcomponent.cpp | 64 |
1 files changed, 45 insertions, 19 deletions
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index c4bc242bd9..1e9dbdfaf1 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1105,11 +1105,13 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context, enginePriv->incubate(incubator, forContextData); } -class QmlIncubatorObject : public QV4::Object, public QQmlIncubator +class WrapperIncubator; + +class QmlIncubatorObject : public QV4::Object { Q_MANAGED public: - QmlIncubatorObject(QV8Engine *engine, IncubationMode = Asynchronous); + QmlIncubatorObject(QV8Engine *engine, QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous); static QV4::ReturnedValue method_get_statusChanged(QV4::SimpleCallContext *ctx); static QV4::ReturnedValue method_set_statusChanged(QV4::SimpleCallContext *ctx); @@ -1120,18 +1122,38 @@ public: static void destroy(Managed *that); static void markObjects(Managed *that); + QScopedPointer<WrapperIncubator> incubator; QV8Engine *v8; QPointer<QObject> parent; QV4::SafeValue valuemap; QV4::SafeValue qmlGlobal; QV4::SafeValue m_statusChanged; -protected: - virtual void statusChanged(Status); - virtual void setInitialState(QObject *); + + void statusChanged(QQmlIncubator::Status); + void setInitialState(QObject *); }; DEFINE_MANAGED_VTABLE(QmlIncubatorObject); +class WrapperIncubator : public QQmlIncubator +{ +public: + WrapperIncubator(QmlIncubatorObject *inc, IncubationMode mode) + : QQmlIncubator(mode) + , incubatorObject(inc) + {} + virtual void statusChanged(Status s) { + incubatorObject->statusChanged(s); + } + + virtual void setInitialState(QObject *o) { + incubatorObject->setInitialState(o); + } + + QmlIncubatorObject *incubatorObject; +}; + + static void QQmlComponent_setQmlParent(QObject *me, QObject *parent) { if (parent) { @@ -1375,9 +1397,10 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) } r->parent = parent; - create(*r.getPointer(), creationContext()); + QQmlIncubator *incubator = r.getPointer()->incubator.data(); + create(*incubator, creationContext()); - if (r->status() == QQmlIncubator::Null) { + if (incubator->status() == QQmlIncubator::Null) { args->setReturnValue(QV4::Encode::null()); } else { args->setReturnValue(r.asReturnedValue()); @@ -1429,7 +1452,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_get_object(QV4::SimpleCallContext if (!o) ctx->throwTypeError(); - return QV4::QObjectWrapper::wrap(ctx->engine, o->object()); + return QV4::QObjectWrapper::wrap(ctx->engine, o->incubator->object()); } QV4::ReturnedValue QmlIncubatorObject::method_forceCompletion(QV4::SimpleCallContext *ctx) @@ -1439,7 +1462,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_forceCompletion(QV4::SimpleCallCon if (!o) ctx->throwTypeError(); - o->forceCompletion(); + o->incubator->forceCompletion(); return QV4::Encode::undefined(); } @@ -1451,7 +1474,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_get_status(QV4::SimpleCallContext if (!o) ctx->throwTypeError(); - return QV4::Encode(o->status()); + return QV4::Encode(o->incubator->status()); } QV4::ReturnedValue QmlIncubatorObject::method_get_statusChanged(QV4::SimpleCallContext *ctx) @@ -1471,6 +1494,7 @@ QV4::ReturnedValue QmlIncubatorObject::method_set_statusChanged(QV4::SimpleCallC if (!o || ctx->callData->argc < 1) ctx->throwTypeError(); + o->m_statusChanged = ctx->callData->args[0]; return QV4::Encode::undefined(); } @@ -1479,9 +1503,10 @@ QQmlComponentExtension::~QQmlComponentExtension() { } -QmlIncubatorObject::QmlIncubatorObject(QV8Engine *engine, IncubationMode m) - : Object(QV8Engine::getV4(engine)), QQmlIncubator(m) +QmlIncubatorObject::QmlIncubatorObject(QV8Engine *engine, QQmlIncubator::IncubationMode m) + : Object(QV8Engine::getV4(engine)) { + incubator.reset(new WrapperIncubator(this, m)); v8 = engine; vtbl = &static_vtbl; @@ -1512,25 +1537,26 @@ void QmlIncubatorObject::setInitialState(QObject *o) void QmlIncubatorObject::destroy(Managed *that) { QmlIncubatorObject *o = that->as<QmlIncubatorObject>(); - assert(o); + Q_ASSERT(o); o->~QmlIncubatorObject(); } void QmlIncubatorObject::markObjects(QV4::Managed *that) { QmlIncubatorObject *o = that->as<QmlIncubatorObject>(); - assert(o); + Q_ASSERT(o); o->valuemap.mark(); o->qmlGlobal.mark(); o->m_statusChanged.mark(); + Object::markObjects(that); } -void QmlIncubatorObject::statusChanged(Status s) +void QmlIncubatorObject::statusChanged(QQmlIncubator::Status s) { - if (s == Ready) { - Q_ASSERT(QQmlData::get(object())); - QQmlData::get(object())->explicitIndestructibleSet = false; - QQmlData::get(object())->indestructible = false; + if (s == QQmlIncubator::Ready) { + Q_ASSERT(QQmlData::get(incubator->object())); + QQmlData::get(incubator->object())->explicitIndestructibleSet = false; + QQmlData::get(incubator->object())->indestructible = false; } QV4::Scope scope(QV8Engine::getV4(v8)); |