aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlengine.cpp
diff options
context:
space:
mode:
authorRichard Weickelt <richard@weickelt.de>2019-04-21 13:27:05 +0200
committerRichard Weickelt <richard@weickelt.de>2019-04-24 08:43:00 +0000
commit4d098132421fe75492d61d270569c2d8a7acbdde (patch)
treea94712d523c82b88d7668b6f71879f88d33c682b /src/qml/qml/qqmlengine.cpp
parent93818a359973003531e2a5ef2d55cf58b3d440d9 (diff)
Move creation and management of singletons to QQmlEnginePrivate
Singleton object instances were previously managed by QQmlType::SingletonInstanceInfo and kept in a shared storage. This caused concurrency problems when instantiating singleton instances from different QML engines in different threads. This patch moves the singleton house-keeping infrastructure to QQmlEnginePrivate and makes SingletonInstanceInfo immutable. Singleton objects are stored in a QHash with QQmlType as the key because the qml type id might be 0 for composite singletons. The public API of QQmlType is extended to provide more information about singleton types so that access to SingletonInstanceInfo is not needed. All internal accesses of singleton objects must now take the same code path via QQmlEnginePrivate::singletonInstance<T>() which simplifies overall usage of singletons and scatters less implementation details throughout the code base. Task-number: QTBUG-75007 Change-Id: I13c5fd21cac2eb7291f2cbcf2c2b504f0f51a07c Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/qml/qml/qqmlengine.cpp')
-rw-r--r--src/qml/qml/qqmlengine.cpp77
1 files changed, 64 insertions, 13 deletions
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 840aeb534d..19c3469682 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -1057,7 +1057,7 @@ QQmlEngine::~QQmlEngine()
// XXX TODO: performance -- store list of singleton types separately?
QList<QQmlType> singletonTypes = QQmlMetaType::qmlSingletonTypes();
for (const QQmlType &currType : singletonTypes)
- currType.singletonInstanceInfo()->destroy(this);
+ d->destroySingletonInstance(currType);
delete d->rootContext;
d->rootContext = nullptr;
@@ -1402,23 +1402,13 @@ void QQmlEngine::setOutputWarningsToStandardError(bool enabled)
template<>
QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
{
+ Q_D(QQmlEngine);
QQmlType type = QQmlMetaType::qmlType(qmlTypeId, QQmlMetaType::TypeIdCategory::QmlType);
if (!type.isValid() || !type.isSingleton())
return QJSValue();
- QQmlType::SingletonInstanceInfo* info = type.singletonInstanceInfo();
- info->init(this);
-
- if (QObject* o = info->qobjectApi(this))
- return this->newQObject(o);
- else {
- QJSValue value = info->scriptApi(this);
- if (!value.isUndefined())
- return value;
- }
-
- return QJSValue();
+ return d->singletonInstance<QJSValue>(type);
}
/*!
@@ -2445,6 +2435,67 @@ void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::CompiledData::Compi
m_compositeTypes.remove(compilationUnit->metaTypeId);
}
+template<>
+QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type)
+{
+ Q_Q(QQmlEngine);
+
+ QJSValue value = singletonInstances.value(type);
+ if (!value.isUndefined()) {
+ return value;
+ }
+
+ QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo();
+ Q_ASSERT(siinfo != nullptr);
+
+ if (siinfo->scriptCallback) {
+ value = siinfo->scriptCallback(q, q);
+ if (value.isQObject()) {
+ QObject *o = value.toQObject();
+ // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
+ // should behave identically to QML singleton types.
+ q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
+ }
+ singletonInstances.insert(type, value);
+
+ } else if (siinfo->qobjectCallback) {
+ QObject *o = siinfo->qobjectCallback(q, q);
+ if (!o) {
+ qFatal("qmlRegisterSingletonType(): \"%s\" is not available because the callback function returns a null pointer.",
+ qPrintable(QString::fromUtf8(type.typeName())));
+ }
+ // if this object can use a property cache, create it now
+ QQmlData::ensurePropertyCache(q, o);
+ // even though the object is defined in C++, qmlContext(obj) and qmlEngine(obj)
+ // should behave identically to QML singleton types.
+ q->setContextForObject(o, new QQmlContext(q->rootContext(), q));
+ value = q->newQObject(o);
+ singletonInstances.insert(type, value);
+
+ } else if (!siinfo->url.isEmpty()) {
+ QQmlComponent component(q, siinfo->url, QQmlComponent::PreferSynchronous);
+ QObject *o = component.beginCreate(q->rootContext());
+ value = q->newQObject(o);
+ singletonInstances.insert(type, value);
+ component.completeCreate();
+ }
+
+ return value;
+}
+
+void QQmlEnginePrivate::destroySingletonInstance(const QQmlType &type)
+{
+ Q_ASSERT(type.isSingleton() || type.isCompositeSingleton());
+
+ QObject* o = singletonInstances.take(type).toQObject();
+ if (o) {
+ QQmlData *ddata = QQmlData::get(o, false);
+ if (type.singletonInstanceInfo()->url.isEmpty() && ddata && ddata->indestructible && ddata->explicitIndestructibleSet)
+ return;
+ delete o;
+ }
+}
+
bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const
{
return typeLoader.isTypeLoaded(url);