diff options
author | Richard Weickelt <richard@weickelt.de> | 2019-04-21 13:27:05 +0200 |
---|---|---|
committer | Richard Weickelt <richard@weickelt.de> | 2019-04-24 08:43:00 +0000 |
commit | 4d098132421fe75492d61d270569c2d8a7acbdde (patch) | |
tree | a94712d523c82b88d7668b6f71879f88d33c682b /src/qml/qml/qqmltypewrapper.cpp | |
parent | 93818a359973003531e2a5ef2d55cf58b3d440d9 (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/qqmltypewrapper.cpp')
-rw-r--r-- | src/qml/qml/qqmltypewrapper.cpp | 171 |
1 files changed, 84 insertions, 87 deletions
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index b72d82ffbc..3e72f5b324 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -89,10 +89,8 @@ QObject* QQmlTypeWrapper::singletonObject() const if (!isSingleton()) return nullptr; - QQmlEngine *e = engine()->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = d()->type().singletonInstanceInfo(); - siinfo->init(e); - return siinfo->qobjectApi(e); + QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine()); + return e->singletonInstance<QObject*>(d()->type()); } QVariant QQmlTypeWrapper::toVariant() const @@ -101,13 +99,12 @@ QVariant QQmlTypeWrapper::toVariant() const if (!isSingleton()) return QVariant(); - QQmlEngine *e = engine()->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = d()->type().singletonInstanceInfo(); - siinfo->init(e); - if (QObject *qobjectSingleton = siinfo->qobjectApi(e)) - return QVariant::fromValue<QObject*>(qobjectSingleton); + QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine()); + const QQmlType type = d()->type(); + if (type.isQJSValueSingleton()) + return QVariant::fromValue<QJSValue>(e->singletonInstance<QJSValue>(type)); - return QVariant::fromValue<QJSValue>(siinfo->scriptApi(e)); + return QVariant::fromValue<QObject*>(e->singletonInstance<QObject*>(type)); } @@ -195,50 +192,51 @@ ReturnedValue QQmlTypeWrapper::virtualGet(const Managed *m, PropertyKey id, cons // singleton types are handled differently to other types. if (type.isSingleton()) { - QQmlEngine *e = v4->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo(); - siinfo->init(e); - - QObject *qobjectSingleton = siinfo->qobjectApi(e); - if (qobjectSingleton) { - - // check for enum value - const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums; - if (includeEnums && name->startsWithUpper()) { - bool ok = false; - int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok); - if (ok) - return QV4::Value::fromInt32(value).asReturnedValue(); - - value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); - if (ok) { - Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>()); - enumWrapper->d()->typePrivate = type.priv(); - QQmlType::refHandle(enumWrapper->d()->typePrivate); - enumWrapper->d()->scopeEnumIndex = value; - return enumWrapper.asReturnedValue(); + QQmlEnginePrivate *e = QQmlEnginePrivate::get(v4->qmlEngine()); + QJSValue scriptSingleton; + if (type.isQObjectSingleton() || type.isCompositeSingleton()) { + if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) { + // check for enum value + const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums; + if (includeEnums && name->startsWithUpper()) { + bool ok = false; + int value = enumForSingleton(v4, name, qobjectSingleton, type, &ok); + if (ok) + return QV4::Value::fromInt32(value).asReturnedValue(); + + value = type.scopedEnumIndex(QQmlEnginePrivate::get(v4->qmlEngine()), name, &ok); + if (ok) { + Scoped<QQmlScopedEnumWrapper> enumWrapper(scope, v4->memoryManager->allocate<QQmlScopedEnumWrapper>()); + enumWrapper->d()->typePrivate = type.priv(); + QQmlType::refHandle(enumWrapper->d()->typePrivate); + enumWrapper->d()->scopeEnumIndex = value; + return enumWrapper.asReturnedValue(); + } } - } - // check for property. - bool ok; - const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, &ok); - if (hasProperty) - *hasProperty = ok; - - // Warn when attempting to access a lowercased enum value, singleton case - if (!ok && includeEnums && !name->startsWithUpper()) { - enumForSingleton(v4, name, qobjectSingleton, type, &ok); - if (ok) - return throwLowercaseEnumError(v4, name, type); - } + // check for property. + bool ok; + const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, &ok); + if (hasProperty) + *hasProperty = ok; + + // Warn when attempting to access a lowercased enum value, singleton case + if (!ok && includeEnums && !name->startsWithUpper()) { + enumForSingleton(v4, name, qobjectSingleton, type, &ok); + if (ok) + return throwLowercaseEnumError(v4, name, type); + } - return result; - } else if (!siinfo->scriptApi(e).isUndefined()) { - // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable. - QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e))); - if (!!o) - return o->get(name); + return result; + } + } else if (type.isQJSValueSingleton()) { + QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type); + if (!scriptSingleton.isUndefined()) { + // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable. + QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, scriptSingleton)); + if (!!o) + return o->get(name); + } } // Fall through to base implementation @@ -343,21 +341,22 @@ bool QQmlTypeWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value); return false; } else if (type.isSingleton()) { - QQmlEngine *e = scope.engine->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo(); - siinfo->init(e); - - QObject *qobjectSingleton = siinfo->qobjectApi(e); - if (qobjectSingleton) { - return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value); - } else if (!siinfo->scriptApi(e).isUndefined()) { - QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(scope.engine, siinfo->scriptApi(e))); - if (!apiprivate) { - QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"'); - scope.engine->throwError(error); - return false; - } else { - return apiprivate->put(name, value); + QQmlEnginePrivate *e = QQmlEnginePrivate::get(scope.engine->qmlEngine()); + if (type.isQObjectSingleton() || type.isCompositeSingleton()) { + if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) + return QV4::QObjectWrapper::setQmlProperty(scope.engine, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value); + + } else { + QJSValue scriptSingleton = e->singletonInstance<QJSValue>(type); + if (!scriptSingleton.isUndefined()) { + QV4::ScopedObject apiprivate(scope, QJSValuePrivate::convertedToValue(scope.engine, scriptSingleton)); + if (!apiprivate) { + QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"'); + scope.engine->throwError(error); + return false; + } else { + return apiprivate->put(name, value); + } } } } @@ -449,27 +448,25 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object, if (type.isValid()) { if (type.isSingleton()) { - QQmlEngine *e = engine->qmlEngine(); - QQmlType::SingletonInstanceInfo *siinfo = type.singletonInstanceInfo(); - siinfo->init(e); - - QObject *qobjectSingleton = siinfo->qobjectApi(e); - if (qobjectSingleton) { - - const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums; - if (!includeEnums || !name->startsWithUpper()) { - QQmlData *ddata = QQmlData::get(qobjectSingleton, false); - if (ddata && ddata->propertyCache) { - ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton))); - QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext); - if (property) { - lookup->qobjectLookup.ic = This->internalClass(); - lookup->qobjectLookup.staticQObject = static_cast<Heap::QObjectWrapper *>(val->heapObject()); - lookup->qobjectLookup.propertyCache = ddata->propertyCache; - lookup->qobjectLookup.propertyCache->addref(); - lookup->qobjectLookup.propertyData = property; - lookup->getter = QV4::QObjectWrapper::lookupGetter; - return lookup->getter(lookup, engine, *This); + QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine->qmlEngine()); + if (type.isQObjectSingleton() || type.isCompositeSingleton()) { + if (QObject *qobjectSingleton = e->singletonInstance<QObject*>(type)) { + const bool includeEnums = w->d()->mode == Heap::QQmlTypeWrapper::IncludeEnums; + if (!includeEnums || !name->startsWithUpper()) { + QQmlData *ddata = QQmlData::get(qobjectSingleton, false); + if (ddata && ddata->propertyCache) { + ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton))); + QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext); + if (property) { + lookup->qobjectLookup.ic = This->internalClass(); + lookup->qobjectLookup.staticQObject = static_cast<Heap::QObjectWrapper *>(val->heapObject()); + lookup->qobjectLookup.propertyCache = ddata->propertyCache; + lookup->qobjectLookup.propertyCache->addref(); + lookup->qobjectLookup.propertyData = property; + lookup->getter = QV4::QObjectWrapper::lookupGetter; + return lookup->getter(lookup, engine, *This); + } + // Fall through to base implementation } // Fall through to base implementation } |