diff options
Diffstat (limited to 'src/qml/qml/qqmlengine_p.h')
-rw-r--r-- | src/qml/qml/qqmlengine_p.h | 363 |
1 files changed, 139 insertions, 224 deletions
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 04ed50b2ee..7c820679ba 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #ifndef QQMLENGINE_P_H #define QQMLENGINE_P_H @@ -53,63 +17,46 @@ #include "qqmlengine.h" -#include "qqmltypeloader_p.h" -#include "qqmlimport_p.h" -#include <private/qpodvector_p.h> -#include "qqml.h" -#include "qqmlvaluetype_p.h" -#include "qqmlcontext.h" -#include "qqmlcontextdata_p.h" -#include "qqmlexpression.h" -#include "qqmlproperty_p.h" -#include "qqmlmetatype_p.h" +#include <private/qfieldlist_p.h> #include <private/qintrusivelist_p.h> +#include <private/qjsengine_p.h> +#include <private/qjsvalue_p.h> +#include <private/qpodvector_p.h> +#include <private/qqmldirparser_p.h> +#include <private/qqmlimport_p.h> +#include <private/qqmlmetatype_p.h> +#include <private/qqmlnotifier_p.h> +#include <private/qqmlproperty_p.h> +#include <private/qqmltypeloader_p.h> +#include <private/qqmlvaluetype_p.h> #include <private/qrecyclepool_p.h> -#include <private/qfieldlist_p.h> #include <private/qv4engine_p.h> -#include <private/qjsvalue_p.h> + +#include <QtQml/qqml.h> +#include <QtQml/qqmlcontext.h> #include <QtCore/qlist.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qmutex.h> #include <QtCore/qpair.h> +#include <QtCore/qpointer.h> +#include <QtCore/qproperty.h> #include <QtCore/qstack.h> -#include <QtCore/qmutex.h> #include <QtCore/qstring.h> #include <QtCore/qthread.h> -#include <private/qobject_p.h> - -#include <private/qjsengine_p.h> -#include <private/qqmldirparser_p.h> - -#include <qproperty.h> +#include <atomic> QT_BEGIN_NAMESPACE -class QQmlContext; -class QQmlEngine; -class QQmlContextPrivate; -class QQmlExpression; -class QQmlImportDatabase; -class QNetworkReply; class QNetworkAccessManager; -class QQmlNetworkAccessManagerFactory; -class QQmlTypeNameCache; -class QQmlComponentAttached; class QQmlDelayedError; -class QQmlObjectCreator; -class QDir; class QQmlIncubator; +class QQmlMetaObject; +class QQmlNetworkAccessManagerFactory; +class QQmlObjectCreator; class QQmlProfiler; class QQmlPropertyCapture; -class QQmlMetaObject; - -struct QObjectForeign { - Q_GADGET - QML_FOREIGN(QObject) - QML_NAMED_ELEMENT(QtObject) - QML_ADDED_IN_VERSION(2, 0) - Q_CLASSINFO("QML.Root", "QML") -}; // This needs to be declared here so that the pool for it can live in QQmlEnginePrivate. // The inline method definitions are in qqmljavascriptexpression_p.h @@ -127,11 +74,20 @@ public: }; struct QPropertyChangeTrigger : QPropertyObserver { - QPropertyChangeTrigger(QQmlJavaScriptExpression *expression) : QPropertyObserver(&QPropertyChangeTrigger::trigger), m_expression(expression) {} - QQmlJavaScriptExpression * m_expression; - QObject *target = nullptr; + Q_DISABLE_COPY_MOVE(QPropertyChangeTrigger) + + QPropertyChangeTrigger(QQmlJavaScriptExpression *expression) + : QPropertyObserver(&QPropertyChangeTrigger::trigger) + , m_expression(expression) + { + } + + QPointer<QObject> target; + QQmlJavaScriptExpression *m_expression; int propertyIndex = 0; static void trigger(QPropertyObserver *, QUntypedPropertyData *); + + QMetaProperty property() const; }; struct TriggerList : QPropertyChangeTrigger { @@ -141,11 +97,11 @@ struct TriggerList : QPropertyChangeTrigger { TriggerList *next = nullptr; }; -class Q_QML_PRIVATE_EXPORT QQmlEnginePrivate : public QJSEnginePrivate +class Q_QML_EXPORT QQmlEnginePrivate : public QJSEnginePrivate { Q_DECLARE_PUBLIC(QQmlEngine) public: - QQmlEnginePrivate(QQmlEngine *); + explicit QQmlEnginePrivate(QQmlEngine *q) : importDatabase(q), typeLoader(q) {} ~QQmlEnginePrivate() override; void init(); @@ -153,49 +109,48 @@ public: // is just qmlClearTypeRegistrations (which can't be called while an engine exists) static bool baseModulesUninitialized; - QQmlPropertyCapture *propertyCapture; + QQmlPropertyCapture *propertyCapture = nullptr; QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool; QRecyclePool<TriggerList> qPropertyTriggerPool; - QQmlContext *rootContext; + QQmlContext *rootContext = nullptr; + Q_OBJECT_BINDABLE_PROPERTY(QQmlEnginePrivate, QString, translationLanguage); #if !QT_CONFIG(qml_debug) static const quintptr profiler = 0; #else - QQmlProfiler *profiler; + QQmlProfiler *profiler = nullptr; #endif - bool outputWarningsToMsgLog; + bool outputWarningsToMsgLog = true; // Bindings that have had errors during startup - QQmlDelayedError *erroredBindings; - int inProgressCreations; + QQmlDelayedError *erroredBindings = nullptr; + int inProgressCreations = 0; QV4::ExecutionEngine *v4engine() const { return q_func()->handle(); } #if QT_CONFIG(qml_worker_script) - QThread *workerScriptEngine; + QThread *workerScriptEngine = nullptr; #endif QUrl baseUrl; - typedef QPair<QPointer<QObject>,int> FinalizeCallback; - void registerFinalizeCallback(QObject *obj, int index); - - QQmlObjectCreator *activeObjectCreator; + QQmlObjectCreator *activeObjectCreator = nullptr; #if QT_CONFIG(qml_network) QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const; QNetworkAccessManager *getNetworkAccessManager() const; - mutable QNetworkAccessManager *networkAccessManager; - mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory; + mutable QNetworkAccessManager *networkAccessManager = nullptr; + mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory = nullptr; #endif + mutable QRecursiveMutex imageProviderMutex; QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders; QSharedPointer<QQmlImageProviderBase> imageProvider(const QString &providerId) const; QList<QQmlAbstractUrlInterceptor *> urlInterceptors; - int scarceResourcesRefCount; + int scarceResourcesRefCount = 0; void referenceScarceResources(); void dereferenceScarceResources(); @@ -204,52 +159,24 @@ public: QString offlineStoragePath; - mutable quint32 uniqueId; - inline quint32 getUniqueId() const { - return uniqueId++; - } - // Unfortunate workaround to avoid a circular dependency between // qqmlengine_p.h and qqmlincubator_p.h - struct Incubator : public QSharedData { + struct Incubator { QIntrusiveListNode next; - // Unfortunate workaround for MSVC - QIntrusiveListNode nextWaitingFor; }; QIntrusiveList<Incubator, &Incubator::next> incubatorList; - unsigned int incubatorCount; - QQmlIncubationController *incubationController; + unsigned int incubatorCount = 0; + QQmlIncubationController *incubationController = nullptr; void incubate(QQmlIncubator &, const QQmlRefPointer<QQmlContextData> &); // These methods may be called from any thread - inline bool isEngineThread() const; - inline static bool isEngineThread(const QQmlEngine *); - template<typename T> - inline void deleteInEngineThread(T *); - template<typename T> - inline static void deleteInEngineThread(QQmlEnginePrivate *, T *); QString offlineStorageDatabaseDirectory() const; - // These methods may be called from the loader thread - inline QQmlPropertyCache *cache(const QQmlType &, QTypeRevision version); - using QJSEnginePrivate::cache; - - // These methods may be called from the loader thread - QQmlMetaObject rawMetaObjectForType(int) const; - QQmlMetaObject metaObjectForType(int) const; - QQmlPropertyCache *propertyCacheForType(int); - QQmlPropertyCache *rawPropertyCacheForType(int); - QQmlPropertyCache *rawPropertyCacheForType(int, QTypeRevision version); - void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit); - void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit); - QV4::ExecutableCompilationUnit *obtainExecutableCompilationUnit(int typeId); - bool isTypeLoaded(const QUrl &url) const; bool isScriptLoaded(const QUrl &url) const; template <typename T> T singletonInstance(const QQmlType &type); - void destroySingletonInstance(const QQmlType &type); void sendQuit(); void sendExit(int retCode = 0); @@ -270,24 +197,22 @@ public: static QList<QQmlError> qmlErrorFromDiagnostics(const QString &fileName, const QList<QQmlJS::DiagnosticMessage> &diagnosticMessages); - static void defineModule(); - static bool designerMode(); static void activateDesignerMode(); - static bool qml_debugging_enabled; + static std::atomic<bool> qml_debugging_enabled; mutable QMutex networkAccessManagerMutex; QQmlGadgetPtrWrapper *valueTypeInstance(QMetaType type) { int typeIndex = type.id(); - auto it = cachedValueTypeInstances.find(typeIndex); - if (it != cachedValueTypeInstances.end()) + auto it = cachedValueTypeInstances.constFind(typeIndex); + if (it != cachedValueTypeInstances.cend()) return *it; if (QQmlValueType *valueType = QQmlMetaType::valueType(type)) { - QQmlGadgetPtrWrapper *instance = new QQmlGadgetPtrWrapper(valueType, q_func()); + QQmlGadgetPtrWrapper *instance = new QQmlGadgetPtrWrapper(valueType); cachedValueTypeInstances.insert(typeIndex, instance); return instance; } @@ -295,38 +220,81 @@ public: return nullptr; } - QJSValue executeRuntimeFunction(const QUrl &url, qsizetype functionIndex, QObject *thisObject, - int arcg=0, void **args = nullptr, QMetaType *types = nullptr); + void executeRuntimeFunction(const QUrl &url, qsizetype functionIndex, QObject *thisObject, + int argc = 0, void **args = nullptr, QMetaType *types = nullptr); + void executeRuntimeFunction(const QV4::ExecutableCompilationUnit *unit, qsizetype functionIndex, + QObject *thisObject, int argc = 0, void **args = nullptr, + QMetaType *types = nullptr); + QV4::ExecutableCompilationUnit *compilationUnitFromUrl(const QUrl &url); + QQmlRefPointer<QQmlContextData> + createInternalContext(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &unit, + const QQmlRefPointer<QQmlContextData> &parentContext, + int subComponentIndex, bool isComponentRoot); + static void setInternalContext(QObject *This, const QQmlRefPointer<QQmlContextData> &context, + QQmlContextData::QmlObjectKind kind) + { + Q_ASSERT(This); + QQmlData *ddata = QQmlData::get(This, /*create*/ true); + // NB: copied from QQmlObjectCreator::createInstance() + // + // the if-statement logic to determine the kind is: + // if (static_cast<quint32>(index) == 0 || ddata->rootObjectInCreation || isInlineComponent) + // then QQmlContextData::DocumentRoot. here, we pass this through qmltc + context->installContext(ddata, kind); + Q_ASSERT(qmlEngine(This)); + } private: - class SingletonInstances : private QHash<QQmlType, QJSValue> + class SingletonInstances : private QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue> { public: - void convertAndInsert(QV4::ExecutionEngine *engine, const QQmlType &type, QJSValue *value) + void convertAndInsert( + QV4::ExecutionEngine *engine, const QQmlType::SingletonInstanceInfo::ConstPtr &type, + QJSValue *value) { QJSValuePrivate::manageStringOnV4Heap(engine, value); insert(type, *value); } - using QHash<QQmlType, QJSValue>::value; - using QHash<QQmlType, QJSValue>::take; + void clear() + { + const auto canDelete = [](QObject *instance, const auto &siinfo) -> bool { + if (!instance) + return false; + + if (!siinfo->url.isEmpty()) + return true; + + const auto *ddata = QQmlData::get(instance, false); + return !(ddata && ddata->indestructible && ddata->explicitIndestructibleSet); + }; + + for (auto it = constBegin(), end = constEnd(); it != end; ++it) { + auto *instance = it.value().toQObject(); + if (canDelete(instance, it.key())) + QQmlData::markAsDeleted(instance); + } + + for (auto it = constBegin(), end = constEnd(); it != end; ++it) { + QObject *instance = it.value().toQObject(); + + if (canDelete(instance, it.key())) + delete instance; + } + + QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::clear(); + } + + using QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::value; + using QHash<QQmlType::SingletonInstanceInfo::ConstPtr, QJSValue>::take; }; SingletonInstances singletonInstances; QHash<int, QQmlGadgetPtrWrapper *> cachedValueTypeInstances; - // These members must be protected by a QQmlEnginePrivate::Locker as they are required by - // the threaded loader. Only access them through their respective accessor methods. - QHash<int, QV4::ExecutableCompilationUnit *> m_compositeTypes; static bool s_designerMode; - // These members is protected by the full QQmlEnginePrivate::mutex mutex - struct Deletable { Deletable():next(nullptr) {} virtual ~Deletable() {} Deletable *next; }; - QFieldList<Deletable, &Deletable::next> toDeleteInEngineThread; - void doDeleteInEngineThread(); - void cleanupScarceResources(); - QQmlPropertyCache *findPropertyCacheInCompositeTypes(int t) const; }; /* @@ -359,81 +327,6 @@ inline void QQmlEnginePrivate::dereferenceScarceResources() } } -/*! -Returns true if the calling thread is the QQmlEngine thread. -*/ -bool QQmlEnginePrivate::isEngineThread() const -{ - - return QThread::currentThread() == q_ptr->thread(); -} - -/*! -Returns true if the calling thread is the QQmlEngine \a engine thread. -*/ -bool QQmlEnginePrivate::isEngineThread(const QQmlEngine *engine) -{ - Q_ASSERT(engine); - return QQmlEnginePrivate::get(engine)->isEngineThread(); -} - -/*! -Delete \a value in the engine thread. If the calling thread is the engine -thread, \a value will be deleted immediately. - -This method should be used for *any* type that has resources that need to -be freed in the engine thread. This is generally types that use V8 handles. -As there is some small overhead in checking the current thread, it is best -practice to check if any V8 handles actually need to be freed and delete -the instance directly if not. -*/ -template<typename T> -void QQmlEnginePrivate::deleteInEngineThread(T *value) -{ - Q_ASSERT(value); - if (isEngineThread()) { - delete value; - } else { - struct I : public Deletable { - I(T *value) : value(value) {} - ~I() override { delete value; } - T *value; - }; - I *i = new I(value); - mutex.lock(); - bool wasEmpty = toDeleteInEngineThread.isEmpty(); - toDeleteInEngineThread.append(i); - mutex.unlock(); - if (wasEmpty) - QCoreApplication::postEvent(q_ptr, new QEvent(QEvent::User)); - } -} - -/*! -Delete \a value in the \a engine thread. If the calling thread is the engine -thread, \a value will be deleted immediately. -*/ -template<typename T> -void QQmlEnginePrivate::deleteInEngineThread(QQmlEnginePrivate *engine, T *value) -{ - Q_ASSERT(engine); - engine->deleteInEngineThread<T>(value); -} - -/*! -Returns a QQmlPropertyCache for \a type with \a minorVersion. - -The returned cache is not referenced, so if it is to be stored, call addref(). -*/ -QQmlPropertyCache *QQmlEnginePrivate::cache(const QQmlType &type, QTypeRevision version) -{ - Q_ASSERT(type.isValid()); - Q_ASSERT(type.containsRevisionedAttributes()); - - Locker locker(this); - return QQmlMetaType::propertyCache(type, version); -} - QV4::ExecutionEngine *QQmlEnginePrivate::getV4Engine(QQmlEngine *e) { Q_ASSERT(e); @@ -491,13 +384,35 @@ QQmlEnginePrivate *QQmlEnginePrivate::get(QV4::ExecutionEngine *e) } template<> -Q_QML_PRIVATE_EXPORT QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type); +Q_QML_EXPORT QJSValue QQmlEnginePrivate::singletonInstance<QJSValue>(const QQmlType &type); template<typename T> T QQmlEnginePrivate::singletonInstance(const QQmlType &type) { return qobject_cast<T>(singletonInstance<QJSValue>(type).toQObject()); } +struct LoadHelper final : QQmlTypeLoader::Blob +{ + LoadHelper(QQmlTypeLoader *loader, QAnyStringView uri); + + struct ResolveTypeResult + { + enum Status { NoSuchModule, ModuleFound } status; + QQmlType type; + }; + + ResolveTypeResult resolveType(QAnyStringView typeName); + +protected: + void dataReceived(const SourceCodeData &) final { Q_UNREACHABLE(); } + void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) final { Q_UNREACHABLE(); } + +private: + bool couldFindModule() const; + QString m_uri; +}; + + QT_END_NAMESPACE #endif // QQMLENGINE_P_H |