diff options
author | Simon Hausmann <simon.hausmann@theqtcompany.com> | 2014-11-20 09:07:52 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2014-12-29 14:39:22 +0100 |
commit | efc3cc717ac1a62965465e909cc99acef627cdb1 (patch) | |
tree | 9d181ca8e9e299fa99b9b7598bfb83bc53056dde | |
parent | 65953304a2775e69c7edd46b780aa39f769d32ac (diff) |
Make QQmlPropertyCache available in QJSEngine
The QQmlEngine has two containers for property caches, one for QML types and
one for all-purpose meta-objects. The latter is rather useful and now being
moved to QJSEngine to be available there.
Change-Id: Ieab65c400b8a2e410e5f9eee6d603162dbb864d9
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r-- | src/qml/jsapi/qjsengine.cpp | 21 | ||||
-rw-r--r-- | src/qml/jsapi/qjsengine_p.h | 125 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4script.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlboundsignal.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 20 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine_p.h | 108 | ||||
-rw-r--r-- | src/qml/qml/qqmlopenmetaobject.cpp | 1 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycache.cpp | 13 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycache_p.h | 10 |
9 files changed, 161 insertions, 141 deletions
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index e4daa64674..04ed341a50 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -539,6 +539,27 @@ bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr) \sa toScriptValue() */ + +QJSEnginePrivate::~QJSEnginePrivate() +{ + for (QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter) + (*iter)->release(); +} + +QQmlPropertyCache *QJSEnginePrivate::createCache(const QMetaObject *mo) +{ + if (!mo->superClass()) { + QQmlPropertyCache *rv = new QQmlPropertyCache(q_func(), mo); + propertyCache.insert(mo, rv); + return rv; + } else { + QQmlPropertyCache *super = cache(mo->superClass()); + QQmlPropertyCache *rv = super->copyAndAppend(mo); + propertyCache.insert(mo, rv); + return rv; + } +} + QT_END_NAMESPACE #include "moc_qjsengine.cpp" diff --git a/src/qml/jsapi/qjsengine_p.h b/src/qml/jsapi/qjsengine_p.h index 654d0dee56..eba8ffb4be 100644 --- a/src/qml/jsapi/qjsengine_p.h +++ b/src/qml/jsapi/qjsengine_p.h @@ -46,11 +46,13 @@ // #include <QtCore/private/qobject_p.h> +#include <QtCore/qmutex.h> #include "qjsengine.h" QT_BEGIN_NAMESPACE +class QQmlPropertyCache; class QJSEnginePrivate : public QObjectPrivate { @@ -58,10 +60,131 @@ class QJSEnginePrivate : public QObjectPrivate public: static QJSEnginePrivate* get(QJSEngine*e) { return e->d_func(); } + static const QJSEnginePrivate* get(const QJSEngine*e) { return e->d_func(); } - QJSEnginePrivate() {} + QJSEnginePrivate() : mutex(QMutex::Recursive) {} + ~QJSEnginePrivate(); + + // Locker locks the QQmlEnginePrivate data structures for read and write, if necessary. + // Currently, locking is only necessary if the threaded loader is running concurrently. If it is + // either idle, or is running with the main thread blocked, no locking is necessary. This way + // we only pay for locking when we have to. + // Consequently, this class should only be used to protect simple accesses or modifications of the + // QQmlEnginePrivate structures or operations that can be guaranteed not to start activity + // on the loader thread. + // The Locker API is identical to QMutexLocker. Locker reuses the QQmlEnginePrivate::mutex + // QMutex instance and multiple Lockers are recursive in the same thread. + class Locker + { + public: + inline Locker(const QJSEngine *); + inline Locker(const QJSEnginePrivate *); + inline ~Locker(); + + inline void unlock(); + inline void relock(); + + private: + const QJSEnginePrivate *m_ep; + quint32 m_locked:1; + }; + + // Shared by QQmlEngine + mutable QMutex mutex; + + + // These methods may be called from the QML loader thread + inline QQmlPropertyCache *cache(QObject *obj); + inline QQmlPropertyCache *cache(const QMetaObject *); + +private: + // Must be called locked + QQmlPropertyCache *createCache(const QMetaObject *); + + // These members must be protected by a QJSEnginePrivate::Locker as they are required by + // the threaded loader. Only access them through their respective accessor methods. + QHash<const QMetaObject *, QQmlPropertyCache *> propertyCache; }; +QJSEnginePrivate::Locker::Locker(const QJSEngine *e) +: m_ep(QJSEnginePrivate::get(e)) +{ + relock(); +} + +QJSEnginePrivate::Locker::Locker(const QJSEnginePrivate *e) +: m_ep(e), m_locked(false) +{ + relock(); +} + +QJSEnginePrivate::Locker::~Locker() +{ + unlock(); +} + +void QJSEnginePrivate::Locker::unlock() +{ + if (m_locked) { + m_ep->mutex.unlock(); + m_locked = false; + } +} + +void QJSEnginePrivate::Locker::relock() +{ + Q_ASSERT(!m_locked); + m_ep->mutex.lock(); + m_locked = true; +} + +/*! +Returns a QQmlPropertyCache for \a obj if one is available. + +If \a obj is null, being deleted or contains a dynamic meta object 0 +is returned. + +The returned cache is not referenced, so if it is to be stored, call addref(). + +XXX thread There is a potential future race condition in this and all the cache() +functions. As the QQmlPropertyCache is returned unreferenced, when called +from the loader thread, it is possible that the cache will have been dereferenced +and deleted before the loader thread has a chance to use or reference it. This +can't currently happen as the cache holds a reference to the +QQmlPropertyCache until the QQmlEngine is destroyed. +*/ +QQmlPropertyCache *QJSEnginePrivate::cache(QObject *obj) +{ + if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted) + return 0; + + Locker locker(this); + const QMetaObject *mo = obj->metaObject(); + QQmlPropertyCache *rv = propertyCache.value(mo); + if (!rv) rv = createCache(mo); + return rv; +} + +/*! +Returns a QQmlPropertyCache for \a metaObject. + +As the cache is persisted for the life of the engine, \a metaObject must be +a static "compile time" meta-object, or a meta-object that is otherwise known to +exist for the lifetime of the QQmlEngine. + +The returned cache is not referenced, so if it is to be stored, call addref(). +*/ +QQmlPropertyCache *QJSEnginePrivate::cache(const QMetaObject *metaObject) +{ + Q_ASSERT(metaObject); + + Locker locker(this); + QQmlPropertyCache *rv = propertyCache.value(metaObject); + if (!rv) rv = createCache(metaObject); + return rv; +} + + QT_END_NAMESPACE #endif // QJSENGINE_P_H diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 088e9616ce..38d2c12cfb 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -176,7 +176,7 @@ Heap::FunctionObject *QmlBindingWrapper::createQmlCallableForFunction(QQmlContex if (!signalParameters.isEmpty()) { if (error) - QQmlPropertyCache::signalParameterStringForJS(qmlContext->engine, signalParameters, error); + QQmlPropertyCache::signalParameterStringForJS(engine, signalParameters, error); QV4::ScopedProperty p(valueScope); QV4::ScopedString s(valueScope); int index = 0; diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index f8718ad0ee..8baeefe62b 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -217,7 +217,7 @@ void QQmlBoundSignalExpression::evaluate(void **a) //TODO: look at using the property cache here (as in the compiler) // for further optimization QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index); - expression += QQmlPropertyCache::signalParameterStringForJS(engine(), signal.parameterNames(), &error); + expression += QQmlPropertyCache::signalParameterStringForJS(scope.engine, signal.parameterNames(), &error); if (!error.isEmpty()) { qmlInfo(scopeObject()) << error; diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index f9de7adc93..8f2c554a7e 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -559,7 +559,7 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e) activeObjectCreator(0), networkAccessManager(0), networkAccessManagerFactory(0), urlInterceptor(0), scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1), - incubatorCount(0), incubationController(0), mutex(QMutex::Recursive) + incubatorCount(0), incubationController(0) { } @@ -582,8 +582,6 @@ QQmlEnginePrivate::~QQmlEnginePrivate() if (incubationController) incubationController->d = 0; incubationController = 0; - for(QHash<const QMetaObject *, QQmlPropertyCache *>::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter) - (*iter)->release(); for(QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::Iterator iter = typePropertyCache.begin(); iter != typePropertyCache.end(); ++iter) (*iter)->release(); for (QHash<int, QQmlCompiledData *>::Iterator iter = m_compositeTypes.begin(); iter != m_compositeTypes.end(); ++iter) @@ -2043,22 +2041,6 @@ QString QQmlEngine::offlineStoragePath() const return d->offlineStoragePath; } -QQmlPropertyCache *QQmlEnginePrivate::createCache(const QMetaObject *mo) -{ - Q_Q(QQmlEngine); - - if (!mo->superClass()) { - QQmlPropertyCache *rv = new QQmlPropertyCache(q, mo); - propertyCache.insert(mo, rv); - return rv; - } else { - QQmlPropertyCache *super = cache(mo->superClass()); - QQmlPropertyCache *rv = super->copyAndAppend(mo); - propertyCache.insert(mo, rv); - return rv; - } -} - QQmlPropertyCache *QQmlEnginePrivate::createCache(QQmlType *type, int minorVersion, QQmlError &error) { diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index a1935b854b..de2a2d3e1d 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -208,9 +208,8 @@ public: inline static void deleteInEngineThread(QQmlEngine *, T *); // These methods may be called from the loader thread - inline QQmlPropertyCache *cache(QObject *obj); - inline QQmlPropertyCache *cache(const QMetaObject *); inline QQmlPropertyCache *cache(QQmlType *, int, QQmlError &error); + using QJSEnginePrivate::cache; // These methods may be called from the loader thread bool isQObject(int); @@ -260,40 +259,13 @@ public: static bool qml_debugging_enabled; mutable QMutex networkAccessManagerMutex; - mutable QMutex mutex; private: - // Locker locks the QQmlEnginePrivate data structures for read and write, if necessary. - // Currently, locking is only necessary if the threaded loader is running concurrently. If it is - // either idle, or is running with the main thread blocked, no locking is necessary. This way - // we only pay for locking when we have to. - // Consequently, this class should only be used to protect simple accesses or modifications of the - // QQmlEnginePrivate structures or operations that can be guaranteed not to start activity - // on the loader thread. - // The Locker API is identical to QMutexLocker. Locker reuses the QQmlEnginePrivate::mutex - // QMutex instance and multiple Lockers are recursive in the same thread. - class Locker - { - public: - inline Locker(const QQmlEngine *); - inline Locker(const QQmlEnginePrivate *); - inline ~Locker(); - - inline void unlock(); - inline void relock(); - - private: - const QQmlEnginePrivate *m_ep; - quint32 m_locked:1; - }; - // Must be called locked - QQmlPropertyCache *createCache(const QMetaObject *); QQmlPropertyCache *createCache(QQmlType *, int, QQmlError &error); // 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<const QMetaObject *, QQmlPropertyCache *> propertyCache; QHash<QPair<QQmlType *, int>, QQmlPropertyCache *> typePropertyCache; QHash<int, int> m_qmlLists; QHash<int, QQmlCompiledData *> m_compositeTypes; @@ -306,38 +278,6 @@ private: void doDeleteInEngineThread(); }; -QQmlEnginePrivate::Locker::Locker(const QQmlEngine *e) -: m_ep(QQmlEnginePrivate::get(e)) -{ - relock(); -} - -QQmlEnginePrivate::Locker::Locker(const QQmlEnginePrivate *e) -: m_ep(e), m_locked(false) -{ - relock(); -} - -QQmlEnginePrivate::Locker::~Locker() -{ - unlock(); -} - -void QQmlEnginePrivate::Locker::unlock() -{ - if (m_locked) { - m_ep->mutex.unlock(); - m_locked = false; - } -} - -void QQmlEnginePrivate::Locker::relock() -{ - Q_ASSERT(!m_locked); - m_ep->mutex.lock(); - m_locked = true; -} - /*! Returns true if the calling thread is the QQmlEngine thread. */ @@ -402,52 +342,6 @@ void QQmlEnginePrivate::deleteInEngineThread(QQmlEngine *engine, T *value) } /*! -Returns a QQmlPropertyCache for \a obj if one is available. - -If \a obj is null, being deleted or contains a dynamic meta object 0 -is returned. - -The returned cache is not referenced, so if it is to be stored, call addref(). - -XXX thread There is a potential future race condition in this and all the cache() -functions. As the QQmlPropertyCache is returned unreferenced, when called -from the loader thread, it is possible that the cache will have been dereferenced -and deleted before the loader thread has a chance to use or reference it. This -can't currently happen as the cache holds a reference to the -QQmlPropertyCache until the QQmlEngine is destroyed. -*/ -QQmlPropertyCache *QQmlEnginePrivate::cache(QObject *obj) -{ - if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted) - return 0; - - Locker locker(this); - const QMetaObject *mo = obj->metaObject(); - QQmlPropertyCache *rv = propertyCache.value(mo); - if (!rv) rv = createCache(mo); - return rv; -} - -/*! -Returns a QQmlPropertyCache for \a metaObject. - -As the cache is persisted for the life of the engine, \a metaObject must be -a static "compile time" meta-object, or a meta-object that is otherwise known to -exist for the lifetime of the QQmlEngine. - -The returned cache is not referenced, so if it is to be stored, call addref(). -*/ -QQmlPropertyCache *QQmlEnginePrivate::cache(const QMetaObject *metaObject) -{ - Q_ASSERT(metaObject); - - Locker locker(this); - QQmlPropertyCache *rv = propertyCache.value(metaObject); - if (!rv) rv = createCache(metaObject); - return rv; -} - -/*! Returns a QQmlPropertyCache for \a type with \a minorVersion. The returned cache is not referenced, so if it is to be stored, call addref(). diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp index 9715fdc85d..e234a0bfbe 100644 --- a/src/qml/qml/qqmlopenmetaobject.cpp +++ b/src/qml/qml/qqmlopenmetaobject.cpp @@ -35,6 +35,7 @@ #include <private/qqmlpropertycache_p.h> #include <private/qqmldata_p.h> #include <private/qmetaobjectbuilder_p.h> +#include <qqmlengine.h> #include <qdebug.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 363fce4375..b5bc29aaa6 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -231,7 +231,7 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m) /*! Creates a new empty QQmlPropertyCache. */ -QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e) +QQmlPropertyCache::QQmlPropertyCache(QJSEngine *e) : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), _metaObject(0), argumentsCache(0) @@ -242,7 +242,7 @@ QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e) /*! Creates a new QQmlPropertyCache of \a metaObject. */ -QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e, const QMetaObject *metaObject) +QQmlPropertyCache::QQmlPropertyCache(QJSEngine *e, const QMetaObject *metaObject) : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), _metaObject(0), argumentsCache(0) @@ -818,7 +818,7 @@ void QQmlPropertyCache::resolve(QQmlPropertyData *data) const data->propType = registerResult == -1 ? QMetaType::UnknownType : registerResult; } } - data->flags |= flagsForPropertyType(data->propType, engine); + data->flags |= flagsForPropertyType(data->propType, qobject_cast<QQmlEngine*>(engine)); } data->flags &= ~QQmlPropertyData::NotFullyResolved; @@ -1135,7 +1135,7 @@ QString QQmlPropertyCache::signalParameterStringForJS(int index, QString *errorS } QString error; - QString parameters = signalParameterStringForJS(engine, parameterNameList, &error); + QString parameters = signalParameterStringForJS(QV8Engine::getV4(engine), parameterNameList, &error); A *arguments = static_cast<A *>(signalData->arguments); arguments->signalParameterStringForJS = new QString(!error.isEmpty() ? error : parameters); @@ -1148,11 +1148,10 @@ QString QQmlPropertyCache::signalParameterStringForJS(int index, QString *errorS return *arguments->signalParameterStringForJS; } -QString QQmlPropertyCache::signalParameterStringForJS(QQmlEngine *engine, const QList<QByteArray> ¶meterNameList, QString *errorString) +QString QQmlPropertyCache::signalParameterStringForJS(QV4::ExecutionEngine *engine, const QList<QByteArray> ¶meterNameList, QString *errorString) { - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); bool unnamedParameter = false; - const QSet<QString> &illegalNames = ep->v8engine()->illegalNames(); + const QSet<QString> &illegalNames = engine->v8Engine->illegalNames(); QString error; QString parameters; diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index d3ea336885..224de948eb 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -61,6 +61,7 @@ QT_BEGIN_NAMESPACE class QV8Engine; class QMetaProperty; class QQmlEngine; +class QJSEngine; class QQmlPropertyData; class QQmlAccessors; class QMetaObjectBuilder; @@ -242,8 +243,8 @@ class QQmlPropertyCacheMethodArguments; class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount, public QQmlCleanup { public: - QQmlPropertyCache(QQmlEngine *); - QQmlPropertyCache(QQmlEngine *, const QMetaObject *); + QQmlPropertyCache(QJSEngine *); + QQmlPropertyCache(QJSEngine *, const QMetaObject *); virtual ~QQmlPropertyCache(); void update(const QMetaObject *); @@ -311,7 +312,7 @@ public: QList<QByteArray> signalParameterNames(int index) const; QString signalParameterStringForJS(int index, QString *errorString = 0); - static QString signalParameterStringForJS(QQmlEngine *engine, const QList<QByteArray> ¶meterNameList, QString *errorString = 0); + static QString signalParameterStringForJS(QV4::ExecutionEngine *engine, const QList<QByteArray> ¶meterNameList, QString *errorString = 0); const char *className() const; @@ -374,8 +375,7 @@ private: _hasPropertyOverrides |= isOverride; } - // Optional! Only used for calling flagsForPropertyType, in which it is also optional. - QQmlEngine *engine; + QJSEngine *engine; QQmlPropertyCache *_parent; int propertyIndexCacheStart; |