diff options
Diffstat (limited to 'src/qml/qml/qqmlpropertycache_p.h')
-rw-r--r-- | src/qml/qml/qqmlpropertycache_p.h | 943 |
1 files changed, 213 insertions, 730 deletions
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index c3c818eb77..7ff499460d 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_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 QQMLPROPERTYCACHE_P_H #define QQMLPROPERTYCACHE_P_H @@ -51,419 +15,193 @@ // We mean it. // +#include <private/qlinkedstringhash_p.h> +#include <private/qqmlenumdata_p.h> +#include <private/qqmlenumvalue_p.h> +#include <private/qqmlpropertydata_p.h> #include <private/qqmlrefcount_p.h> -#include <private/qflagpointer_p.h> -#include "qqmlcleanup_p.h" -#include "qqmlnotifier_p.h" -#include <private/qqmlpropertyindex_p.h> -#include <private/qhashedstring_p.h> #include <QtCore/qvarlengtharray.h> #include <QtCore/qvector.h> - -#include <private/qv4value_p.h> +#include <QtCore/qversionnumber.h> #include <limits> QT_BEGIN_NAMESPACE class QCryptographicHash; -class QMetaProperty; -class QQmlEngine; class QJSEngine; -class QQmlPropertyData; class QMetaObjectBuilder; +class QQmlContextData; +class QQmlPropertyCache; class QQmlPropertyCacheMethodArguments; class QQmlVMEMetaObject; -template <typename T> class QQmlPropertyCacheCreator; -template <typename T> class QQmlPropertyCacheAliasCreator; - -// We have this somewhat awful split between RawData and Data so that RawData can be -// used in unions. In normal code, you should always use Data which initializes RawData -// to an invalid state on construction. -// ### We should be able to remove this split nowadays -class QQmlPropertyRawData + +class QQmlMetaObjectPointer { public: - typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction; - - struct Flags { - enum Types { - OtherType = 0, - FunctionType = 1, // Is an invokable - QObjectDerivedType = 2, // Property type is a QObject* derived type - EnumType = 3, // Property type is an enum - QListType = 4, // Property type is a QML list - QmlBindingType = 5, // Property type is a QQmlBinding* - QJSValueType = 6, // Property type is a QScriptValue - V4HandleType = 7, // Property type is a QQmlV4Handle - VarPropertyType = 8, // Property type is a "var" property of VMEMO - QVariantType = 9 // Property is a QVariant - }; - - // The _otherBits (which "pad" the Flags struct to align it nicely) are used - // to store the relative property index. It will only get used when said index fits. See - // trySetStaticMetaCallFunction for details. - // (Note: this padding is done here, because certain compilers have surprising behavior - // when an enum is declared in-between two bit fields.) - enum { BitsLeftInFlags = 10 }; - unsigned _otherBits : BitsLeftInFlags; // align to 32 bits - - // Can apply to all properties, except IsFunction - unsigned isConstant : 1; // Has CONST flag - unsigned isWritable : 1; // Has WRITE function - unsigned isResettable : 1; // Has RESET function - unsigned isAlias : 1; // Is a QML alias to another property - unsigned isFinal : 1; // Has FINAL flag - unsigned isOverridden : 1; // Is overridden by a extension property - unsigned isDirect : 1; // Exists on a C++ QMetaObject - - unsigned type : 4; // stores an entry of Types - - // Apply only to IsFunctions - unsigned isVMEFunction : 1; // Function was added by QML - unsigned hasArguments : 1; // Function takes arguments - unsigned isSignal : 1; // Function is a signal - unsigned isVMESignal : 1; // Signal was added by QML - unsigned isV4Function : 1; // Function takes QQmlV4Function* args - unsigned isSignalHandler : 1; // Function is a signal handler - unsigned isOverload : 1; // Function is an overload of another function - unsigned isCloned : 1; // The function was marked as cloned - unsigned isConstructor : 1; // The function was marked is a constructor - - // Internal QQmlPropertyCache flags - unsigned notFullyResolved : 1; // True if the type data is to be lazily resolved - unsigned overrideIndexIsProperty: 1; - - inline Flags(); - inline bool operator==(const Flags &other) const; - inline void copyPropertyTypeFlags(Flags from); - }; + Q_NODISCARD_CTOR QQmlMetaObjectPointer() = default; - Flags flags() const { return _flags; } - void setFlags(Flags f) + Q_NODISCARD_CTOR QQmlMetaObjectPointer(const QMetaObject *staticMetaObject) + : d(quintptr(staticMetaObject)) { - unsigned otherBits = _flags._otherBits; - _flags = f; - _flags._otherBits = otherBits; + Q_ASSERT((d.loadRelaxed() & Shared) == 0); } - bool isValid() const { return coreIndex() != -1; } - - bool isConstant() const { return _flags.isConstant; } - bool isWritable() const { return _flags.isWritable; } - void setWritable(bool onoff) { _flags.isWritable = onoff; } - bool isResettable() const { return _flags.isResettable; } - bool isAlias() const { return _flags.isAlias; } - bool isFinal() const { return _flags.isFinal; } - bool isOverridden() const { return _flags.isOverridden; } - bool isDirect() const { return _flags.isDirect; } - bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; } - bool isFunction() const { return _flags.type == Flags::FunctionType; } - bool isQObject() const { return _flags.type == Flags::QObjectDerivedType; } - bool isEnum() const { return _flags.type == Flags::EnumType; } - bool isQList() const { return _flags.type == Flags::QListType; } - bool isQmlBinding() const { return _flags.type == Flags::QmlBindingType; } - bool isQJSValue() const { return _flags.type == Flags::QJSValueType; } - bool isV4Handle() const { return _flags.type == Flags::V4HandleType; } - bool isVarProperty() const { return _flags.type == Flags::VarPropertyType; } - bool isQVariant() const { return _flags.type == Flags::QVariantType; } - bool isVMEFunction() const { return _flags.isVMEFunction; } - bool hasArguments() const { return _flags.hasArguments; } - bool isSignal() const { return _flags.isSignal; } - bool isVMESignal() const { return _flags.isVMESignal; } - bool isV4Function() const { return _flags.isV4Function; } - bool isSignalHandler() const { return _flags.isSignalHandler; } - bool isOverload() const { return _flags.isOverload; } - void setOverload(bool onoff) { _flags.isOverload = onoff; } - bool isCloned() const { return _flags.isCloned; } - bool isConstructor() const { return _flags.isConstructor; } - - bool hasOverride() const { return overrideIndex() >= 0; } - bool hasRevision() const { return revision() != 0; } - - bool isFullyResolved() const { return !_flags.notFullyResolved; } - - int propType() const { Q_ASSERT(isFullyResolved()); return _propType; } - void setPropType(int pt) + ~QQmlMetaObjectPointer() { - Q_ASSERT(pt >= 0); - Q_ASSERT(pt <= std::numeric_limits<qint16>::max()); - _propType = quint16(pt); + const auto dd = d.loadAcquire(); + if (dd & Shared) + reinterpret_cast<SharedHolder *>(dd ^ Shared)->release(); } - int notifyIndex() const { return _notifyIndex; } - void setNotifyIndex(int idx) +private: + friend class QQmlPropertyCache; + Q_NODISCARD_CTOR QQmlMetaObjectPointer(const QQmlMetaObjectPointer &other) + : d(other.d.loadRelaxed()) { - Q_ASSERT(idx >= std::numeric_limits<qint16>::min()); - Q_ASSERT(idx <= std::numeric_limits<qint16>::max()); - _notifyIndex = qint16(idx); + // other has to survive until this ctor is done. So d cannot disappear before. + const auto od = other.d.loadRelaxed(); + if (od & Shared) + reinterpret_cast<SharedHolder *>(od ^ Shared)->addref(); } - bool overrideIndexIsProperty() const { return _flags.overrideIndexIsProperty; } - void setOverrideIndexIsProperty(bool onoff) { _flags.overrideIndexIsProperty = onoff; } - - int overrideIndex() const { return _overrideIndex; } - void setOverrideIndex(int idx) - { - Q_ASSERT(idx >= std::numeric_limits<qint16>::min()); - Q_ASSERT(idx <= std::numeric_limits<qint16>::max()); - _overrideIndex = qint16(idx); - } + QQmlMetaObjectPointer(QQmlMetaObjectPointer &&other) = delete; + QQmlMetaObjectPointer &operator=(QQmlMetaObjectPointer &&other) = delete; + QQmlMetaObjectPointer &operator=(const QQmlMetaObjectPointer &other) = delete; - int coreIndex() const { return _coreIndex; } - void setCoreIndex(int idx) +public: + void setSharedOnce(QMetaObject *shared) const { - Q_ASSERT(idx >= std::numeric_limits<qint16>::min()); - Q_ASSERT(idx <= std::numeric_limits<qint16>::max()); - _coreIndex = qint16(idx); + SharedHolder *holder = new SharedHolder(shared); + if (!d.testAndSetRelease(0, quintptr(holder) | Shared)) + holder->release(); } - quint8 revision() const { return _revision; } - void setRevision(quint8 rev) + const QMetaObject *metaObject() const { - Q_ASSERT(rev <= std::numeric_limits<quint8>::max()); - _revision = quint8(rev); + const auto dd = d.loadAcquire(); + if (dd & Shared) + return reinterpret_cast<SharedHolder *>(dd ^ Shared)->metaObject; + return reinterpret_cast<const QMetaObject *>(dd); } - /* If a property is a C++ type, then we store the minor - * version of this type. - * This is required to resolve property or signal revisions - * if this property is used as a grouped property. - * - * Test.qml - * property TextEdit someTextEdit: TextEdit {} - * - * Test { - * someTextEdit.preeditText: "test" //revision 7 - * someTextEdit.onEditingFinished: console.log("test") //revision 6 - * } - * - * To determine if these properties with revisions are available we need - * the minor version of TextEdit as imported in Test.qml. - * - */ - - quint8 typeMinorVersion() const { return _typeMinorVersion; } - void setTypeMinorVersion(quint8 rev) + bool isShared() const { - Q_ASSERT(rev <= std::numeric_limits<quint8>::max()); - _typeMinorVersion = quint8(rev); + // This works because static metaobjects need to be set in the ctor and once a shared + // metaobject has been set, it cannot be removed anymore. + const auto dd = d.loadRelaxed(); + return !dd || (dd & Shared); } - QQmlPropertyCacheMethodArguments *arguments() const { return _arguments; } - void setArguments(QQmlPropertyCacheMethodArguments *args) { _arguments = args; } - - int metaObjectOffset() const { return _metaObjectOffset; } - void setMetaObjectOffset(int off) + bool isNull() const { - Q_ASSERT(off >= std::numeric_limits<qint16>::min()); - Q_ASSERT(off <= std::numeric_limits<qint16>::max()); - _metaObjectOffset = qint16(off); + return d.loadRelaxed() == 0; } - StaticMetaCallFunction staticMetaCallFunction() const { return _staticMetaCallFunction; } - void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex) - { - if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) { - _flags._otherBits = relativePropertyIndex; - _staticMetaCallFunction = f; - } - } - quint16 relativePropertyIndex() const { Q_ASSERT(hasStaticMetaCallFunction()); return _flags._otherBits; } - private: - Flags _flags; - qint16 _coreIndex = 0; - quint16 _propType = 0; - - // The notify index is in the range returned by QObjectPrivate::signalIndex(). - // This is different from QMetaMethod::methodIndex(). - qint16 _notifyIndex = 0; - qint16 _overrideIndex = 0; - - quint8 _revision = 0; - quint8 _typeMinorVersion = 0; - qint16 _metaObjectOffset = 0; + enum Tag { + Static = 0, + Shared = 1 + }; - QQmlPropertyCacheMethodArguments *_arguments = nullptr; - StaticMetaCallFunction _staticMetaCallFunction = nullptr; + struct SharedHolder final : public QQmlRefCounted<SharedHolder> + { + Q_DISABLE_COPY_MOVE(SharedHolder) + SharedHolder(QMetaObject *shared) : metaObject(shared) {} + ~SharedHolder() { free(metaObject); } + QMetaObject *metaObject; + }; - friend class QQmlPropertyData; - friend class QQmlPropertyCache; + mutable QBasicAtomicInteger<quintptr> d = 0; }; -#if QT_POINTER_SIZE == 4 -Q_STATIC_ASSERT(sizeof(QQmlPropertyRawData) == 24); -#else // QT_POINTER_SIZE == 8 -Q_STATIC_ASSERT(sizeof(QQmlPropertyRawData) == 32); -#endif - -class QQmlPropertyData : public QQmlPropertyRawData +class Q_QML_EXPORT QQmlPropertyCache final + : public QQmlRefCounted<QQmlPropertyCache> { public: - enum WriteFlag { - BypassInterceptor = 0x01, - DontRemoveBinding = 0x02, - RemoveBindingOnAliasWrite = 0x04 - }; - Q_DECLARE_FLAGS(WriteFlags, WriteFlag) - - inline QQmlPropertyData(); - inline QQmlPropertyData(const QQmlPropertyRawData &); + using Ptr = QQmlRefPointer<QQmlPropertyCache>; - inline bool operator==(const QQmlPropertyRawData &); - - static Flags flagsForProperty(const QMetaProperty &); - void load(const QMetaProperty &); - void load(const QMetaMethod &); - QString name(QObject *) const; - QString name(const QMetaObject *) const; - - void markAsOverrideOf(QQmlPropertyData *predecessor); - - inline void readProperty(QObject *target, void *property) const - { - void *args[] = { property, nullptr }; - readPropertyWithArgs(target, args); - } - - inline void readPropertyWithArgs(QObject *target, void *args[]) const + struct ConstPtr : public QQmlRefPointer<const QQmlPropertyCache> { - if (hasStaticMetaCallFunction()) - staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args); - else if (isDirect()) - target->qt_metacall(QMetaObject::ReadProperty, coreIndex(), args); - else - QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex(), args); - } - - bool writeProperty(QObject *target, void *value, WriteFlags flags) const - { - int status = -1; - void *argv[] = { value, nullptr, &status, &flags }; - if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction()) - staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv); - else if (flags.testFlag(BypassInterceptor) && isDirect()) - target->qt_metacall(QMetaObject::WriteProperty, coreIndex(), argv); - else - QMetaObject::metacall(target, QMetaObject::WriteProperty, coreIndex(), argv); - return true; - } + using QQmlRefPointer<const QQmlPropertyCache>::QQmlRefPointer; - static Flags defaultSignalFlags() - { - Flags f; - f.isSignal = true; - f.type = Flags::FunctionType; - f.isVMESignal = true; - return f; - } + ConstPtr(const Ptr &ptr) : ConstPtr(ptr.data(), AddRef) {} + ConstPtr(Ptr &&ptr) : ConstPtr(ptr.take(), Adopt) {} + ConstPtr &operator=(const Ptr &ptr) { return operator=(ConstPtr(ptr)); } + ConstPtr &operator=(Ptr &&ptr) { return operator=(ConstPtr(std::move(ptr))); } + }; - static Flags defaultSlotFlags() - { - Flags f; - f.type = Flags::FunctionType; - f.isVMEFunction = true; - return f; - } + static Ptr createStandalone( + const QMetaObject *, QTypeRevision metaObjectRevision = QTypeRevision::zero()); -private: - friend class QQmlPropertyCache; - void lazyLoad(const QMetaProperty &); - void lazyLoad(const QMetaMethod &); - bool notFullyResolved() const { return _flags.notFullyResolved; } -}; + QQmlPropertyCache() = default; + ~QQmlPropertyCache(); -struct QQmlEnumValue -{ - QQmlEnumValue() {} - QQmlEnumValue(const QString &n, int v) : namedValue(n), value(v) {} - QString namedValue; - int value = -1; -}; + void update(const QMetaObject *); + void invalidate(const QMetaObject *); -struct QQmlEnumData -{ - QString name; - QVector<QQmlEnumValue> values; -}; + QQmlPropertyCache::Ptr copy() const; -class QQmlPropertyCacheMethodArguments; -class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount -{ -public: - QQmlPropertyCache(); - QQmlPropertyCache(const QMetaObject *, int metaObjectRevision = 0); - ~QQmlPropertyCache() override; + QQmlPropertyCache::Ptr copyAndAppend( + const QMetaObject *, QTypeRevision typeVersion, + QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(), + QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(), + QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags()) const; - void update(const QMetaObject *); - void invalidate(const QMetaObject *); - // Used by qmlpuppet. Remove as soon Creator requires Qt 5.5. - void invalidate(void *, const QMetaObject *mo) { invalidate(mo); } - - QQmlPropertyCache *copy(); - - QQmlPropertyCache *copyAndAppend(const QMetaObject *, - QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyData::Flags(), - QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(), - QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags()); - QQmlPropertyCache *copyAndAppend(const QMetaObject *, int typeMinorVersion, - QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyData::Flags(), - QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(), - QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags()); - - QQmlPropertyCache *copyAndReserve(int propertyCount, - int methodCount, int signalCount, int enumCount); - void appendProperty(const QString &, QQmlPropertyRawData::Flags flags, int coreIndex, - int propType, int revision, int notifyIndex); - void appendSignal(const QString &, QQmlPropertyRawData::Flags, int coreIndex, - const int *types = nullptr, const QList<QByteArray> &names = QList<QByteArray>()); - void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex, + QQmlPropertyCache::Ptr copyAndReserve( + int propertyCount, int methodCount, int signalCount, int enumCount) const; + void appendProperty(const QString &, QQmlPropertyData::Flags flags, int coreIndex, + QMetaType propType, QTypeRevision revision, int notifyIndex); + void appendSignal(const QString &, QQmlPropertyData::Flags, int coreIndex, + const QMetaType *types = nullptr, const QList<QByteArray> &names = QList<QByteArray>()); + void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex, + QMetaType returnType, const QList<QByteArray> &names, + const QVector<QMetaType> ¶meterTypes); void appendEnum(const QString &, const QVector<QQmlEnumValue> &); const QMetaObject *metaObject() const; - const QMetaObject *createMetaObject(); + const QMetaObject *createMetaObject() const; const QMetaObject *firstCppMetaObject() const; template<typename K> - QQmlPropertyData *property(const K &key, QObject *object, QQmlContextData *context) const + const QQmlPropertyData *property(const K &key, QObject *object, + const QQmlRefPointer<QQmlContextData> &context) const { return findProperty(stringCache.find(key), object, context); } - QQmlPropertyData *property(int) const; - QQmlPropertyData *method(int) const; - QQmlPropertyData *signal(int index) const; + const QQmlPropertyData *property(int) const; + const QQmlPropertyData *maybeUnresolvedProperty(int) const; + const QQmlPropertyData *method(int) const; + const QQmlPropertyData *signal(int index) const; QQmlEnumData *qmlEnum(int) const; int methodIndexToSignalIndex(int) const; QString defaultPropertyName() const; - QQmlPropertyData *defaultProperty() const; - QQmlPropertyCache *parent() const; - // is used by the Qml Designer - void setParent(QQmlPropertyCache *newParent); + const QQmlPropertyData *defaultProperty() const; - inline QQmlPropertyData *overrideData(QQmlPropertyData *) const; - inline bool isAllowedInRevision(QQmlPropertyData *) const; + // Return a reference here so that we don't have to addref/release all the time + inline const QQmlPropertyCache::ConstPtr &parent() const; - static QQmlPropertyData *property(QJSEngine *, QObject *, const QStringRef &, - QQmlContextData *, QQmlPropertyData &); - static QQmlPropertyData *property(QJSEngine *, QObject *, const QLatin1String &, - QQmlContextData *, QQmlPropertyData &); - static QQmlPropertyData *property(QJSEngine *, QObject *, const QV4::String *, - QQmlContextData *, QQmlPropertyData &); + // is used by the Qml Designer + void setParent(QQmlPropertyCache::ConstPtr newParent); - static QQmlPropertyData *property(QJSEngine *engine, QObject *obj, const QString &name, - QQmlContextData *context, QQmlPropertyData &local) - { - return property(engine, obj, QStringRef(&name), context, local); - } + inline const QQmlPropertyData *overrideData(const QQmlPropertyData *) const; + inline bool isAllowedInRevision(const QQmlPropertyData *) const; + + static const QQmlPropertyData *property( + QObject *, QStringView, const QQmlRefPointer<QQmlContextData> &, + QQmlPropertyData *); + static const QQmlPropertyData *property(QObject *, const QLatin1String &, const QQmlRefPointer<QQmlContextData> &, + QQmlPropertyData *); + static const QQmlPropertyData *property(QObject *, const QV4::String *, const QQmlRefPointer<QQmlContextData> &, + QQmlPropertyData *); //see QMetaObjectPrivate::originalClone - int originalClone(int index); - static int originalClone(QObject *, int index); + int originalClone(int index) const; + static int originalClone(const QObject *, int index); QList<QByteArray> signalParameterNames(int index) const; static QString signalParameterStringForJS(QV4::ExecutionEngine *engine, const QList<QByteArray> ¶meterNameList, QString *errorString = nullptr); @@ -478,45 +216,45 @@ public: inline int signalOffset() const; inline int qmlEnumCount() const; - static bool isDynamicMetaObject(const QMetaObject *); - - void toMetaObjectBuilder(QMetaObjectBuilder &); + void toMetaObjectBuilder(QMetaObjectBuilder &) const; inline bool callJSFactoryMethod(QObject *object, void **args) const; static bool determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, int *stringCount); static bool addToHash(QCryptographicHash &hash, const QMetaObject &mo); - QByteArray checksum(bool *ok); + QByteArray checksum(QHash<quintptr, QByteArray> *checksums, bool *ok) const; + + QTypeRevision allowedRevision(int index) const { return allowedRevisionCache[index]; } + void setAllowedRevision(int index, QTypeRevision allowed) { allowedRevisionCache[index] = allowed; } + private: friend class QQmlEnginePrivate; friend class QQmlCompiler; template <typename T> friend class QQmlPropertyCacheCreator; template <typename T> friend class QQmlPropertyCacheAliasCreator; - friend class QQmlComponentAndAliasResolver; + template <typename T> friend class QQmlComponentAndAliasResolver; friend class QQmlMetaObject; - friend struct QQmlMetaTypeData; - inline QQmlPropertyCache *copy(int reserve); + QQmlPropertyCache(const QQmlMetaObjectPointer &metaObject) : _metaObject(metaObject) {} + + inline QQmlPropertyCache::Ptr copy(const QQmlMetaObjectPointer &mo, int reserve) const; - void append(const QMetaObject *, int typeMinorVersion, - QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyRawData::Flags(), - QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(), - QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags()); + void append(const QMetaObject *, QTypeRevision typeVersion, + QQmlPropertyData::Flags propertyFlags = QQmlPropertyData::Flags(), + QQmlPropertyData::Flags methodFlags = QQmlPropertyData::Flags(), + QQmlPropertyData::Flags signalFlags = QQmlPropertyData::Flags()); QQmlPropertyCacheMethodArguments *createArgumentsObject(int count, const QList<QByteArray> &names); typedef QVector<QQmlPropertyData> IndexCache; - typedef QStringMultiHash<QPair<int, QQmlPropertyData *> > StringCache; - typedef QVector<int> AllowedRevisionCache; + typedef QLinkedStringMultiHash<QPair<int, QQmlPropertyData *> > StringCache; + typedef QVector<QTypeRevision> AllowedRevisionCache; - QQmlPropertyData *findProperty(StringCache::ConstIterator it, QObject *, QQmlContextData *) const; - QQmlPropertyData *findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *, QQmlContextData *) const; - - QQmlPropertyData *ensureResolved(QQmlPropertyData*) const; - - Q_NEVER_INLINE void resolve(QQmlPropertyData *) const; - void updateRecur(const QMetaObject *); + const QQmlPropertyData *findProperty(StringCache::ConstIterator it, QObject *, + const QQmlRefPointer<QQmlContextData> &) const; + const QQmlPropertyData *findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *, + const QQmlRefPointer<QQmlContextData> &) const; template<typename K> QQmlPropertyData *findNamedProperty(const K &key) const @@ -526,17 +264,36 @@ private: } template<typename K> - void setNamedProperty(const K &key, int index, QQmlPropertyData *data, bool isOverride) + void setNamedProperty(const K &key, int index, QQmlPropertyData *data) { stringCache.insert(key, qMakePair(index, data)); - _hasPropertyOverrides |= isOverride; } private: - QQmlPropertyCache *_parent; - int propertyIndexCacheStart; - int methodIndexCacheStart; - int signalHandlerIndexCacheStart; + enum OverrideResult { NoOverride, InvalidOverride, ValidOverride }; + + template<typename String> + OverrideResult handleOverride(const String &name, QQmlPropertyData *data, QQmlPropertyData *old) + { + if (!old) + return NoOverride; + + if (data->markAsOverrideOf(old)) + return ValidOverride; + + qWarning("Final member %s is overridden in class %s. The override won't be used.", + qPrintable(name), className()); + return InvalidOverride; + } + + template<typename String> + OverrideResult handleOverride(const String &name, QQmlPropertyData *data) + { + return handleOverride(name, data, findNamedProperty(name)); + } + + int propertyIndexCacheStart = 0; // placed here to avoid gap between QQmlRefCount and _parent + QQmlPropertyCache::ConstPtr _parent; IndexCache propertyIndexCache; IndexCache methodIndexCache; @@ -545,250 +302,75 @@ private: AllowedRevisionCache allowedRevisionCache; QVector<QQmlEnumData> enumCache; - bool _hasPropertyOverrides : 1; - bool _ownMetaObject : 1; - const QMetaObject *_metaObject; + QQmlMetaObjectPointer _metaObject; QByteArray _dynamicClassName; QByteArray _dynamicStringData; + QByteArray _listPropertyAssignBehavior; QString _defaultPropertyName; - QQmlPropertyCacheMethodArguments *argumentsCache; - int _jsFactoryMethodIndex; - QByteArray _checksum; -}; - -typedef QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCachePtr; - -// QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache. -// This is necessary as we delay creation of QMetaObject for synthesized QObjects, but -// we don't want to needlessly generate QQmlPropertyCaches every time we encounter a -// QObject type used in assignment or when we don't have a QQmlEngine etc. -// -// This class does NOT reference the propertycache. -class QQmlEnginePrivate; -class Q_QML_EXPORT QQmlMetaObject -{ -public: - typedef QVarLengthArray<int, 9> ArgTypeStorage; - - inline QQmlMetaObject(); - inline QQmlMetaObject(QObject *); - inline QQmlMetaObject(const QMetaObject *); - inline QQmlMetaObject(QQmlPropertyCache *); - inline QQmlMetaObject(const QQmlMetaObject &); - - inline QQmlMetaObject &operator=(const QQmlMetaObject &); - - inline bool isNull() const; - - inline const char *className() const; - inline int propertyCount() const; - - inline bool hasMetaObject() const; - inline const QMetaObject *metaObject() const; - - QQmlPropertyCache *propertyCache(QQmlEnginePrivate *) const; - - int methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const; - int *methodParameterTypes(int index, ArgTypeStorage *argStorage, - QByteArray *unknownTypeError) const; - - static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to); - - // static_metacall (on Gadgets) doesn't call the base implementation and therefore - // we need a helper to find the correct meta object and property/method index. - static void resolveGadgetMethodOrPropertyIndex(QMetaObject::Call type, const QMetaObject **metaObject, int *index); - -protected: - QBiPointer<QQmlPropertyCache, const QMetaObject> _m; - int *methodParameterTypes(const QMetaMethod &method, ArgTypeStorage *argStorage, - QByteArray *unknownTypeError) const; - -}; - -class QQmlObjectOrGadget: public QQmlMetaObject -{ -public: - QQmlObjectOrGadget(QObject *obj) - : QQmlMetaObject(obj), - ptr(obj) - {} - QQmlObjectOrGadget(QQmlPropertyCache *propertyCache, void *gadget) - : QQmlMetaObject(propertyCache) - , ptr(gadget) - {} - - void metacall(QMetaObject::Call type, int index, void **argv) const; - -private: - QBiPointer<QObject, void> ptr; - -protected: - QQmlObjectOrGadget(const QMetaObject* metaObject) - : QQmlMetaObject(metaObject) - {} - + QQmlPropertyCacheMethodArguments *argumentsCache = nullptr; + int methodIndexCacheStart = 0; + int signalHandlerIndexCacheStart = 0; + int _jsFactoryMethodIndex = -1; }; -class QQmlStaticMetaObject : public QQmlObjectOrGadget { -public: - QQmlStaticMetaObject(const QMetaObject* metaObject) - : QQmlObjectOrGadget(metaObject) - {} - int *constructorParameterTypes(int index, ArgTypeStorage *dummy, QByteArray *unknownTypeError) const; -}; - -QQmlPropertyRawData::Flags::Flags() - : _otherBits(0) - , isConstant(false) - , isWritable(false) - , isResettable(false) - , isAlias(false) - , isFinal(false) - , isOverridden(false) - , isDirect(false) - , type(OtherType) - , isVMEFunction(false) - , hasArguments(false) - , isSignal(false) - , isVMESignal(false) - , isV4Function(false) - , isSignalHandler(false) - , isOverload(false) - , isCloned(false) - , isConstructor(false) - , notFullyResolved(false) - , overrideIndexIsProperty(false) -{} - -bool QQmlPropertyRawData::Flags::operator==(const QQmlPropertyRawData::Flags &other) const -{ - return isConstant == other.isConstant && - isWritable == other.isWritable && - isResettable == other.isResettable && - isAlias == other.isAlias && - isFinal == other.isFinal && - isOverridden == other.isOverridden && - type == other.type && - isVMEFunction == other.isVMEFunction && - hasArguments == other.hasArguments && - isSignal == other.isSignal && - isVMESignal == other.isVMESignal && - isV4Function == other.isV4Function && - isSignalHandler == other.isSignalHandler && - isOverload == other.isOverload && - isCloned == other.isCloned && - isConstructor == other.isConstructor && - notFullyResolved == other.notFullyResolved && - overrideIndexIsProperty == other.overrideIndexIsProperty; -} - -void QQmlPropertyRawData::Flags::copyPropertyTypeFlags(QQmlPropertyRawData::Flags from) -{ - switch (from.type) { - case QObjectDerivedType: - case EnumType: - case QListType: - case QmlBindingType: - case QJSValueType: - case V4HandleType: - case QVariantType: - type = from.type; - } -} - -QQmlPropertyData::QQmlPropertyData() -{ - setCoreIndex(-1); - setPropType(0); - setNotifyIndex(-1); - setOverrideIndex(-1); - setRevision(0); - setMetaObjectOffset(-1); - setArguments(nullptr); - trySetStaticMetaCallFunction(nullptr, 0); -} - -QQmlPropertyData::QQmlPropertyData(const QQmlPropertyRawData &d) -{ - *(static_cast<QQmlPropertyRawData *>(this)) = d; -} - -bool QQmlPropertyData::operator==(const QQmlPropertyRawData &other) -{ - return flags() == other.flags() && - propType() == other.propType() && - coreIndex() == other.coreIndex() && - notifyIndex() == other.notifyIndex() && - revision() == other.revision(); -} - -inline QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) const -{ - if (p && Q_UNLIKELY(p->notFullyResolved())) - resolve(p); - - return p; -} - // Returns this property cache's metaObject. May be null if it hasn't been created yet. inline const QMetaObject *QQmlPropertyCache::metaObject() const { - return _metaObject; + return _metaObject.metaObject(); } // Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by // QML inline const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const { - while (_parent && (_metaObject == nullptr || _ownMetaObject)) - return _parent->firstCppMetaObject(); - return _metaObject; + const QQmlPropertyCache *p = this; + while (p->_metaObject.isShared()) + p = p->parent().data(); + return p->_metaObject.metaObject(); } -inline QQmlPropertyData *QQmlPropertyCache::property(int index) const +inline const QQmlPropertyData *QQmlPropertyCache::property(int index) const { - if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count())) + if (index < 0 || index >= propertyCount()) return nullptr; if (index < propertyIndexCacheStart) return _parent->property(index); - QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart)); - return ensureResolved(rv); + return &propertyIndexCache.at(index - propertyIndexCacheStart); } -inline QQmlPropertyData *QQmlPropertyCache::method(int index) const +inline const QQmlPropertyData *QQmlPropertyCache::method(int index) const { - if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count())) + if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.size())) return nullptr; if (index < methodIndexCacheStart) return _parent->method(index); - QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart)); - return ensureResolved(rv); + return const_cast<const QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart)); } /*! \internal \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()). This is different from QMetaMethod::methodIndex(). */ -inline QQmlPropertyData *QQmlPropertyCache::signal(int index) const +inline const QQmlPropertyData *QQmlPropertyCache::signal(int index) const { - if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count())) + if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.size())) return nullptr; if (index < signalHandlerIndexCacheStart) return _parent->signal(index); - QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart)); + const QQmlPropertyData *rv = const_cast<const QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart)); Q_ASSERT(rv->isSignal() || rv->coreIndex() == -1); - return ensureResolved(rv); + return rv; } inline QQmlEnumData *QQmlPropertyCache::qmlEnum(int index) const { - if (index < 0 || index >= enumCache.count()) + if (index < 0 || index >= enumCache.size()) return nullptr; return const_cast<QQmlEnumData *>(&enumCache.at(index)); @@ -796,7 +378,7 @@ inline QQmlEnumData *QQmlPropertyCache::qmlEnum(int index) const inline int QQmlPropertyCache::methodIndexToSignalIndex(int index) const { - if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count())) + if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.size())) return index; if (index < methodIndexCacheStart) @@ -811,13 +393,13 @@ inline QString QQmlPropertyCache::defaultPropertyName() const return _defaultPropertyName; } -inline QQmlPropertyCache *QQmlPropertyCache::parent() const +inline const QQmlPropertyCache::ConstPtr &QQmlPropertyCache::parent() const { return _parent; } -QQmlPropertyData * -QQmlPropertyCache::overrideData(QQmlPropertyData *data) const +const QQmlPropertyData * +QQmlPropertyCache::overrideData(const QQmlPropertyData *data) const { if (!data->hasOverride()) return nullptr; @@ -828,15 +410,30 @@ QQmlPropertyCache::overrideData(QQmlPropertyData *data) const return method(data->overrideIndex()); } -bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const +bool QQmlPropertyCache::isAllowedInRevision(const QQmlPropertyData *data) const { - return (data->metaObjectOffset() == -1 && data->revision() == 0) || - (allowedRevisionCache[data->metaObjectOffset()] >= data->revision()); + const QTypeRevision requested = data->revision(); + const int offset = data->metaObjectOffset(); + if (offset == -1 && requested == QTypeRevision::zero()) + return true; + + Q_ASSERT(offset >= 0); + Q_ASSERT(offset < allowedRevisionCache.size()); + const QTypeRevision allowed = allowedRevisionCache[offset]; + + if (requested.hasMajorVersion()) { + if (requested.majorVersion() > allowed.majorVersion()) + return false; + if (requested.majorVersion() < allowed.majorVersion()) + return true; + } + + return !requested.hasMinorVersion() || requested.minorVersion() <= allowed.minorVersion(); } int QQmlPropertyCache::propertyCount() const { - return propertyIndexCacheStart + propertyIndexCache.count(); + return propertyIndexCacheStart + int(propertyIndexCache.size()); } int QQmlPropertyCache::propertyOffset() const @@ -846,7 +443,7 @@ int QQmlPropertyCache::propertyOffset() const int QQmlPropertyCache::methodCount() const { - return methodIndexCacheStart + methodIndexCache.count(); + return methodIndexCacheStart + int(methodIndexCache.size()); } int QQmlPropertyCache::methodOffset() const @@ -856,7 +453,7 @@ int QQmlPropertyCache::methodOffset() const int QQmlPropertyCache::signalCount() const { - return signalHandlerIndexCacheStart + signalHandlerIndexCache.count(); + return signalHandlerIndexCacheStart + int(signalHandlerIndexCache.size()); } int QQmlPropertyCache::signalOffset() const @@ -866,138 +463,24 @@ int QQmlPropertyCache::signalOffset() const int QQmlPropertyCache::qmlEnumCount() const { - return enumCache.count(); + return int(enumCache.size()); } bool QQmlPropertyCache::callJSFactoryMethod(QObject *object, void **args) const { if (_jsFactoryMethodIndex != -1) { - _metaObject->d.static_metacall(object, QMetaObject::InvokeMetaMethod, _jsFactoryMethodIndex, args); - return true; + if (const QMetaObject *mo = _metaObject.metaObject()) { + mo->d.static_metacall(object, QMetaObject::InvokeMetaMethod, + _jsFactoryMethodIndex, args); + return true; + } + return false; } if (_parent) return _parent->callJSFactoryMethod(object, args); return false; } -QQmlMetaObject::QQmlMetaObject() -{ -} - -QQmlMetaObject::QQmlMetaObject(QObject *o) -{ - if (o) { - QQmlData *ddata = QQmlData::get(o, false); - if (ddata && ddata->propertyCache) _m = ddata->propertyCache; - else _m = o->metaObject(); - } -} - -QQmlMetaObject::QQmlMetaObject(const QMetaObject *m) -: _m(m) -{ -} - -QQmlMetaObject::QQmlMetaObject(QQmlPropertyCache *m) -: _m(m) -{ -} - -QQmlMetaObject::QQmlMetaObject(const QQmlMetaObject &o) -: _m(o._m) -{ -} - -QQmlMetaObject &QQmlMetaObject::operator=(const QQmlMetaObject &o) -{ - _m = o._m; - return *this; -} - -bool QQmlMetaObject::isNull() const -{ - return _m.isNull(); -} - -const char *QQmlMetaObject::className() const -{ - if (_m.isNull()) { - return nullptr; - } else if (_m.isT1()) { - return _m.asT1()->className(); - } else { - return _m.asT2()->className(); - } -} - -int QQmlMetaObject::propertyCount() const -{ - if (_m.isNull()) { - return 0; - } else if (_m.isT1()) { - return _m.asT1()->propertyCount(); - } else { - return _m.asT2()->propertyCount(); - } -} - -bool QQmlMetaObject::hasMetaObject() const -{ - return _m.isT2() || (!_m.isNull() && _m.asT1()->metaObject()); -} - -const QMetaObject *QQmlMetaObject::metaObject() const -{ - if (_m.isNull()) return nullptr; - if (_m.isT1()) return _m.asT1()->createMetaObject(); - else return _m.asT2(); -} - -class QQmlPropertyCacheVector -{ -public: - QQmlPropertyCacheVector() {} - QQmlPropertyCacheVector(QQmlPropertyCacheVector &&other) - : data(std::move(other.data)) {} - QQmlPropertyCacheVector &operator=(QQmlPropertyCacheVector &&other) { - QVector<QFlagPointer<QQmlPropertyCache>> moved(std::move(other.data)); - data.swap(moved); - return *this; - } - - ~QQmlPropertyCacheVector() { clear(); } - void resize(int size) { return data.resize(size); } - int count() const { return data.count(); } - void clear() - { - for (int i = 0; i < data.count(); ++i) { - if (QQmlPropertyCache *cache = data.at(i).data()) - cache->release(); - } - data.clear(); - } - - void append(QQmlPropertyCache *cache) { cache->addref(); data.append(cache); } - QQmlPropertyCache *at(int index) const { return data.at(index).data(); } - void set(int index, const QQmlRefPointer<QQmlPropertyCache> &replacement) { - if (QQmlPropertyCache *oldCache = data.at(index).data()) { - if (replacement.data() == oldCache) - return; - oldCache->release(); - } - data[index] = replacement.data(); - replacement->addref(); - } - - void setNeedsVMEMetaObject(int index) { data[index].setFlag(); } - bool needsVMEMetaObject(int index) const { return data.at(index).flag(); } -private: - Q_DISABLE_COPY(QQmlPropertyCacheVector) - QVector<QFlagPointer<QQmlPropertyCache>> data; -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags) - QT_END_NAMESPACE #endif // QQMLPROPERTYCACHE_P_H |