diff options
Diffstat (limited to 'src/qml/qml/qqmlpropertycache.cpp')
-rw-r--r-- | src/qml/qml/qqmlpropertycache.cpp | 771 |
1 files changed, 472 insertions, 299 deletions
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 9c535b8ce8..2610a807b5 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -45,12 +45,12 @@ #include <private/qv8engine_p.h> #include <private/qmetaobject_p.h> -#include <private/qqmlaccessors_p.h> #include <private/qmetaobjectbuilder_p.h> #include <private/qv4value_p.h> #include <QtCore/qdebug.h> +#include <QtCore/QCryptographicHash> #include <ctype.h> // for toupper #include <limits.h> @@ -85,51 +85,45 @@ static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p) { QQmlPropertyData::Flags flags; - if (p.isConstant()) - flags |= QQmlPropertyData::IsConstant; - if (p.isWritable()) - flags |= QQmlPropertyData::IsWritable; - if (p.isResettable()) - flags |= QQmlPropertyData::IsResettable; - if (p.isFinal()) - flags |= QQmlPropertyData::IsFinal; + flags.isConstant = p.isConstant(); + flags.isWritable = p.isWritable(); + flags.isResettable = p.isResettable(); + flags.isFinal = p.isFinal(); + if (p.isEnumType()) - flags |= QQmlPropertyData::IsEnumType; + flags.type = QQmlPropertyData::Flags::EnumType; return flags; } // Flags that do depend on the property's QMetaProperty::userType() and thus are slow to // load -static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *engine) +static void flagsForPropertyType(int propType, QQmlEngine *engine, QQmlPropertyData::Flags &flags) { Q_ASSERT(propType != -1); - QQmlPropertyData::Flags flags; - if (propType == QMetaType::QObjectStar) { - flags |= QQmlPropertyData::IsQObjectDerived; + flags.type = QQmlPropertyData::Flags::QObjectDerivedType; } else if (propType == QMetaType::QVariant) { - flags |= QQmlPropertyData::IsQVariant; - } else if (propType < (int)QVariant::UserType) { + flags.type = QQmlPropertyData::Flags::QVariantType; + } else if (propType < static_cast<int>(QVariant::UserType)) { + // nothing to do } else if (propType == qMetaTypeId<QQmlBinding *>()) { - flags |= QQmlPropertyData::IsQmlBinding; + flags.type = QQmlPropertyData::Flags::QmlBindingType; } else if (propType == qMetaTypeId<QJSValue>()) { - flags |= QQmlPropertyData::IsQJSValue; + flags.type = QQmlPropertyData::Flags::QJSValueType; } else if (propType == qMetaTypeId<QQmlV4Handle>()) { - flags |= QQmlPropertyData::IsV4Handle; + flags.type = QQmlPropertyData::Flags::V4HandleType; } else { QQmlMetaType::TypeCategory cat = engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType) : QQmlMetaType::typeCategory(propType); if (cat == QQmlMetaType::Object || QMetaType::typeFlags(propType) & QMetaType::PointerToQObject) - flags |= QQmlPropertyData::IsQObjectDerived; + flags.type = QQmlPropertyData::Flags::QObjectDerivedType; else if (cat == QQmlMetaType::List) - flags |= QQmlPropertyData::IsQList; + flags.type = QQmlPropertyData::Flags::QListType; } - - return flags; } static int metaObjectSignalCount(const QMetaObject *metaObject) @@ -143,95 +137,107 @@ static int metaObjectSignalCount(const QMetaObject *metaObject) QQmlPropertyData::Flags QQmlPropertyData::flagsForProperty(const QMetaProperty &p, QQmlEngine *engine) { - return fastFlagsForProperty(p) | flagsForPropertyType(p.userType(), engine); + auto flags = fastFlagsForProperty(p); + flagsForPropertyType(p.userType(), engine, flags); + return flags; } void QQmlPropertyData::lazyLoad(const QMetaProperty &p) { - coreIndex = p.propertyIndex(); - notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal()); + setCoreIndex(p.propertyIndex()); + setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal())); Q_ASSERT(p.revision() <= Q_INT16_MAX); - revision = p.revision(); + setRevision(p.revision()); - flags = fastFlagsForProperty(p); + setFlags(fastFlagsForProperty(p)); - int type = p.type(); + int type = static_cast<int>(p.type()); if (type == QMetaType::QObjectStar) { - propType = type; - flags |= QQmlPropertyData::IsQObjectDerived; + setPropType(type); + _flags.type = Flags::QObjectDerivedType; } else if (type == QMetaType::QVariant) { - propType = type; - flags |= QQmlPropertyData::IsQVariant; + setPropType(type); + _flags.type = Flags::QVariantType; } else if (type == QVariant::UserType || type == -1) { - propTypeName = p.typeName(); - flags |= QQmlPropertyData::NotFullyResolved; + _flags.notFullyResolved = true; } else { - propType = type; + setPropType(type); } } void QQmlPropertyData::load(const QMetaProperty &p, QQmlEngine *engine) { - propType = p.userType(); - coreIndex = p.propertyIndex(); - notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal()); - flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine); + setPropType(p.userType()); + setCoreIndex(p.propertyIndex()); + setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal())); + setFlags(fastFlagsForProperty(p)); + flagsForPropertyType(propType(), engine, _flags); Q_ASSERT(p.revision() <= Q_INT16_MAX); - revision = p.revision(); + setRevision(p.revision()); } void QQmlPropertyData::load(const QMetaMethod &m) { - coreIndex = m.methodIndex(); - arguments = 0; - flags |= IsFunction; + setCoreIndex(m.methodIndex()); + setArguments(nullptr); + + setPropType(m.returnType()); + + _flags.type = Flags::FunctionType; if (m.methodType() == QMetaMethod::Signal) - flags |= IsSignal; - propType = m.returnType(); + _flags.isSignal = true; + else if (m.methodType() == QMetaMethod::Constructor) { + _flags.isConstructor = true; + setPropType(QMetaType::QObjectStar); + } if (m.parameterCount()) { - flags |= HasArguments; + _flags.hasArguments = true; if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) { - flags |= IsV4Function; + _flags.isV4Function = true; } } if (m.attributes() & QMetaMethod::Cloned) - flags |= IsCloned; + _flags.isCloned = true; Q_ASSERT(m.revision() <= Q_INT16_MAX); - revision = m.revision(); + setRevision(m.revision()); } void QQmlPropertyData::lazyLoad(const QMetaMethod &m) { - coreIndex = m.methodIndex(); - arguments = 0; - flags |= IsFunction; + setCoreIndex(m.methodIndex()); + setPropType(QMetaType::Void); + setArguments(nullptr); + _flags.type = Flags::FunctionType; if (m.methodType() == QMetaMethod::Signal) - flags |= IsSignal; - propType = QMetaType::Void; + _flags.isSignal = true; + else if (m.methodType() == QMetaMethod::Constructor) { + _flags.isConstructor = true; + setPropType(QMetaType::QObjectStar); + } const char *returnType = m.typeName(); if (!returnType) returnType = "\0"; if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) { - propTypeName = returnType; - flags |= NotFullyResolved; + _flags.notFullyResolved = true; } - if (m.parameterCount()) { - flags |= HasArguments; - if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) { - flags |= IsV4Function; + const int paramCount = m.parameterCount(); + if (paramCount) { + _flags.hasArguments = true; + if ((paramCount == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) { + _flags.isV4Function = true; } } if (m.attributes() & QMetaMethod::Cloned) - flags |= IsCloned; + _flags.isCloned = true; Q_ASSERT(m.revision() <= Q_INT16_MAX); - revision = m.revision(); + setRevision(m.revision()); } /*! @@ -249,11 +255,8 @@ QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e) Creates a new QQmlPropertyCache of \a metaObject. */ QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e, const QMetaObject *metaObject) - : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), - signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), - _metaObject(0), argumentsCache(0), _jsFactoryMethodIndex(-1) + : QQmlPropertyCache(e) { - Q_ASSERT(engine); Q_ASSERT(metaObject); update(metaObject); @@ -333,14 +336,14 @@ QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(int propertyCount, int meth \a notifyIndex MUST be in the signal index range (see QObjectPrivate::signalIndex()). This is different from QMetaMethod::methodIndex(). */ -void QQmlPropertyCache::appendProperty(const QString &name, - quint32 flags, int coreIndex, int propType, int notifyIndex) +void QQmlPropertyCache::appendProperty(const QString &name, QQmlPropertyData::Flags flags, + int coreIndex, int propType, int notifyIndex) { QQmlPropertyData data; - data.propType = propType; - data.coreIndex = coreIndex; - data.notifyIndex = notifyIndex; - data.flags = flags; + data.setPropType(propType); + data.setCoreIndex(coreIndex); + data.setNotifyIndex(notifyIndex); + data.setFlags(flags); QQmlPropertyData *old = findNamedProperty(name); if (old) @@ -352,24 +355,25 @@ void QQmlPropertyCache::appendProperty(const QString &name, setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0)); } -void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int coreIndex, - const int *types, const QList<QByteArray> &names) +void QQmlPropertyCache::appendSignal(const QString &name, QQmlPropertyData::Flags flags, + int coreIndex, const int *types, + const QList<QByteArray> &names) { QQmlPropertyData data; - data.propType = QVariant::Invalid; - data.coreIndex = coreIndex; - data.flags = flags; - data.arguments = 0; + data.setPropType(QVariant::Invalid); + data.setCoreIndex(coreIndex); + data.setFlags(flags); + data.setArguments(nullptr); QQmlPropertyData handler = data; - handler.flags |= QQmlPropertyData::IsSignalHandler; + handler._flags.isSignalHandler = true; if (types) { int argumentCount = *types; QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names); ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int)); args->argumentsValid = true; - data.arguments = args; + data.setArguments(args); } QQmlPropertyData *old = findNamedProperty(name); @@ -383,28 +387,28 @@ void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int cor signalHandlerIndexCache.append(handler); QString handlerName = QLatin1String("on") + name; - handlerName[2] = handlerName[2].toUpper(); + handlerName[2] = handlerName.at(2).toUpper(); setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0)); setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != 0)); } -void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int coreIndex, - const QList<QByteArray> &names) +void QQmlPropertyCache::appendMethod(const QString &name, QQmlPropertyData::Flags flags, + int coreIndex, const QList<QByteArray> &names) { int argumentCount = names.count(); QQmlPropertyData data; - data.propType = QMetaType::QVariant; - data.coreIndex = coreIndex; + data.setPropType(QMetaType::QVariant); + data.setCoreIndex(coreIndex); QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names); for (int ii = 0; ii < argumentCount; ++ii) args->arguments[ii + 1] = QMetaType::QVariant; args->argumentsValid = true; - data.arguments = args; + data.setArguments(args); - data.flags = flags; + data.setFlags(flags); QQmlPropertyData *old = findNamedProperty(name); if (old) @@ -416,12 +420,6 @@ void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int cor setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0)); } -// Returns this property cache's metaObject. May be null if it hasn't been created yet. -const QMetaObject *QQmlPropertyCache::metaObject() const -{ - return _metaObject; -} - // Returns this property cache's metaObject, creating it if necessary. const QMetaObject *QQmlPropertyCache::createMetaObject() { @@ -437,51 +435,36 @@ const QMetaObject *QQmlPropertyCache::createMetaObject() return _metaObject; } -// Returns the name of the default property for this cache -QString QQmlPropertyCache::defaultPropertyName() const -{ - return _defaultPropertyName; -} - QQmlPropertyData *QQmlPropertyCache::defaultProperty() const { return property(defaultPropertyName(), 0, 0); } -QQmlPropertyCache *QQmlPropertyCache::parent() const -{ - return _parent; -} - void QQmlPropertyCache::setParent(QQmlPropertyCache *newParent) { + if (_parent == newParent) + return; + if (_parent) + _parent->release(); _parent = newParent; -} - -// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by -// QML -const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const -{ - while (_parent && (_metaObject == 0 || _ownMetaObject)) - return _parent->firstCppMetaObject(); - return _metaObject; + _parent->addref(); } QQmlPropertyCache * QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject, - QQmlPropertyData::Flag propertyFlags, - QQmlPropertyData::Flag methodFlags, - QQmlPropertyData::Flag signalFlags) + QQmlPropertyData::Flags propertyFlags, + QQmlPropertyData::Flags methodFlags, + QQmlPropertyData::Flags signalFlags) { return copyAndAppend(metaObject, -1, propertyFlags, methodFlags, signalFlags); } QQmlPropertyCache * QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject, - int revision, - QQmlPropertyData::Flag propertyFlags, - QQmlPropertyData::Flag methodFlags, - QQmlPropertyData::Flag signalFlags) + int revision, + QQmlPropertyData::Flags propertyFlags, + QQmlPropertyData::Flags methodFlags, + QQmlPropertyData::Flags signalFlags) { Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4); @@ -498,10 +481,10 @@ QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject, } void QQmlPropertyCache::append(const QMetaObject *metaObject, - int revision, - QQmlPropertyData::Flag propertyFlags, - QQmlPropertyData::Flag methodFlags, - QQmlPropertyData::Flag signalFlags) + int revision, + QQmlPropertyData::Flags propertyFlags, + QQmlPropertyData::Flags methodFlags, + QQmlPropertyData::Flags signalFlags) { Q_UNUSED(revision); @@ -516,40 +499,21 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, int signalCount = metaObjectSignalCount(metaObject); int classInfoCount = QMetaObjectPrivate::get(metaObject)->classInfoCount; - QQmlAccessorProperties::Properties accessorProperties; - if (classInfoCount) { int classInfoOffset = metaObject->classInfoOffset(); - bool hasFastProperty = false; for (int ii = 0; ii < classInfoCount; ++ii) { int idx = ii + classInfoOffset; - - const char * const classInfoName = metaObject->classInfo(idx).name(); - if (0 == qstrcmp(classInfoName, "qt_HasQmlAccessors")) { - hasFastProperty = true; - } else if (0 == qstrcmp(classInfoName, "DefaultProperty")) { - _defaultPropertyName = QString::fromUtf8(metaObject->classInfo(idx).value()); - } else if (0 == qstrcmp(classInfoName, "qt_QmlJSWrapperFactoryMethod")) { - const char * const factoryMethod = metaObject->classInfo(idx).value(); + QMetaClassInfo mci = metaObject->classInfo(idx); + const char *name = mci.name(); + if (0 == qstrcmp(name, "DefaultProperty")) { + _defaultPropertyName = QString::fromUtf8(mci.value()); + } else if (0 == qstrcmp(name, "qt_QmlJSWrapperFactoryMethod")) { + const char * const factoryMethod = mci.value(); _jsFactoryMethodIndex = metaObject->indexOfSlot(factoryMethod); if (_jsFactoryMethodIndex != -1) _jsFactoryMethodIndex -= metaObject->methodOffset(); } } - - if (hasFastProperty) { - accessorProperties = QQmlAccessorProperties::properties(metaObject); - if (accessorProperties.count == 0) - qFatal("QQmlPropertyCache: %s has FastProperty class info, but has not " - "installed property accessors", metaObject->className()); - } else { -#ifndef QT_NO_DEBUG - accessorProperties = QQmlAccessorProperties::properties(metaObject); - if (accessorProperties.count != 0) - qFatal("QQmlPropertyCache: %s has fast property accessors, but is missing " - "FastProperty class info", metaObject->className()); -#endif - } } //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML @@ -588,23 +552,21 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, QQmlPropertyData *data = &methodIndexCache[ii - methodIndexCacheStart]; QQmlPropertyData *sigdata = 0; - data->lazyLoad(m); - - if (data->isSignal()) - data->flags |= signalFlags; + if (m.methodType() == QMetaMethod::Signal) + data->setFlags(signalFlags); else - data->flags |= methodFlags; + data->setFlags(methodFlags); - if (!dynamicMetaObject) - data->flags |= QQmlPropertyData::IsDirect; + data->lazyLoad(m); + data->_flags.isDirect = !dynamicMetaObject; Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX); - data->metaObjectOffset = allowedRevisionCache.count() - 1; + data->setMetaObjectOffset(allowedRevisionCache.count() - 1); if (data->isSignal()) { sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart]; *sigdata = *data; - sigdata->flags |= QQmlPropertyData::IsSignalHandler; + sigdata->_flags.isSignalHandler = true; } QQmlPropertyData *old = 0; @@ -616,7 +578,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, setNamedProperty(methodName, ii, data, (old != 0)); if (data->isSignal()) { - QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1)); + QHashedString on(QLatin1String("on") % methodName.at(0).toUpper() % methodName.midRef(1)); setNamedProperty(on, ii, sigdata, (old != 0)); ++signalHandlerIndex; } @@ -645,8 +607,8 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, if (old) { // We only overload methods in the same class, exactly like C++ - if (old->isFunction() && old->coreIndex >= methodOffset) - data->flags |= QQmlPropertyData::IsOverload; + if (old->isFunction() && old->coreIndex() >= methodOffset) + data->_flags.isOverload = true; data->markAsOverrideOf(old); } @@ -673,14 +635,13 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart]; + data->setFlags(propertyFlags); data->lazyLoad(p); - data->flags |= propertyFlags; - if (!dynamicMetaObject) - data->flags |= QQmlPropertyData::IsDirect; + data->_flags.isDirect = !dynamicMetaObject; Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX); - data->metaObjectOffset = allowedRevisionCache.count() - 1; + data->setMetaObjectOffset(allowedRevisionCache.count() - 1); QQmlPropertyData *old = 0; @@ -696,29 +657,40 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, setNamedProperty(propName, ii, data, (old != 0)); } - QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str); - - // Fast properties may not be overrides or revisioned - Q_ASSERT(accessorProperty == 0 || (old == 0 && data->revision == 0)); + bool isGadget = true; + for (const QMetaObject *it = metaObject; it != nullptr; it = it->superClass()) { + if (it == &QObject::staticMetaObject) + isGadget = false; + } - if (accessorProperty) { - data->flags |= QQmlPropertyData::HasAccessors; - data->accessors = accessorProperty->accessors; - } else if (old) { + if (isGadget) // always dispatch over a 'normal' meta-call so the QQmlValueType can intercept + data->_flags.isDirect = false; + else + data->trySetStaticMetaCallFunction(metaObject->d.static_metacall, ii - propOffset); + if (old) data->markAsOverrideOf(old); - } } } void QQmlPropertyCache::resolve(QQmlPropertyData *data) const { Q_ASSERT(data->notFullyResolved()); - - data->propType = QMetaType::type(data->propTypeName); + data->_flags.notFullyResolved = false; + + const QMetaObject *mo = firstCppMetaObject(); + if (data->isFunction()) { + auto metaMethod = mo->method(data->coreIndex()); + const char *retTy = metaMethod.typeName(); + if (!retTy) + retTy = "\0"; + data->setPropType(QMetaType::type(retTy)); + } else { + auto metaProperty = mo->property(data->coreIndex()); + data->setPropType(QMetaType::type(metaProperty.typeName())); + } if (!data->isFunction()) { - if (data->propType == QMetaType::UnknownType) { - const QMetaObject *mo = _metaObject; + if (data->propType() == QMetaType::UnknownType) { QQmlPropertyCache *p = _parent; while (p && (!mo || _ownMetaObject)) { mo = p->_metaObject; @@ -726,22 +698,20 @@ void QQmlPropertyCache::resolve(QQmlPropertyData *data) const } int propOffset = mo->propertyOffset(); - if (mo && data->coreIndex < propOffset + mo->propertyCount()) { - while (data->coreIndex < propOffset) { + if (mo && data->coreIndex() < propOffset + mo->propertyCount()) { + while (data->coreIndex() < propOffset) { mo = mo->superClass(); propOffset = mo->propertyOffset(); } int registerResult = -1; void *argv[] = { ®isterResult }; - mo->static_metacall(QMetaObject::RegisterPropertyMetaType, data->coreIndex - propOffset, argv); - data->propType = registerResult == -1 ? QMetaType::UnknownType : registerResult; + mo->static_metacall(QMetaObject::RegisterPropertyMetaType, data->coreIndex() - propOffset, argv); + data->setPropType(registerResult == -1 ? QMetaType::UnknownType : registerResult); } } - data->flags |= flagsForPropertyType(data->propType, engine->qmlEngine()); + flagsForPropertyType(data->propType(), engine->qmlEngine(), data->_flags); } - - data->flags &= ~QQmlPropertyData::NotFullyResolved; } void QQmlPropertyCache::updateRecur(const QMetaObject *metaObject) @@ -808,48 +778,6 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject) } } -/*! \internal - \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()). - This is different from QMetaMethod::methodIndex(). -*/ -QQmlPropertyData * -QQmlPropertyCache::signal(int index) const -{ - if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count())) - return 0; - - if (index < signalHandlerIndexCacheStart) - return _parent->signal(index); - - QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart)); - Q_ASSERT(rv->isSignal() || rv->coreIndex == -1); - return ensureResolved(rv); -} - -int QQmlPropertyCache::methodIndexToSignalIndex(int index) const -{ - if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count())) - return index; - - if (index < methodIndexCacheStart) - return _parent->methodIndexToSignalIndex(index); - - return index - methodIndexCacheStart + signalHandlerIndexCacheStart; -} - -QQmlPropertyData * -QQmlPropertyCache::method(int index) const -{ - if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count())) - return 0; - - if (index < methodIndexCacheStart) - return _parent->method(index); - - QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart)); - return ensureResolved(rv); -} - QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, QObject *object, QQmlContextData *context) const { QQmlData *data = (object ? QQmlData::get(object) : 0); @@ -866,11 +794,11 @@ inline bool contextHasNoExtensions(QQmlContextData *context) return (!context->parent || !context->parent->imports); } -inline int maximumIndexForProperty(QQmlPropertyData *prop, const QQmlVMEMetaObject *vmemo) +inline int maximumIndexForProperty(QQmlPropertyData *prop, const int methodCount, const int signalCount, const int propertyCount) { - return (prop->isFunction() ? vmemo->methodCount() - : prop->isSignalHandler() ? vmemo->signalCount() - : vmemo->propertyCount()); + return prop->isFunction() ? methodCount + : prop->isSignalHandler() ? signalCount + : propertyCount; } } @@ -897,11 +825,15 @@ QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, } if (vmemo) { + const int methodCount = vmemo->methodCount(); + const int signalCount = vmemo->signalCount(); + const int propertyCount = vmemo->propertyCount(); + // Ensure that the property we resolve to is accessible from this meta-object do { const StringCache::mapped_type &property(it.value()); - if (property.first < maximumIndexForProperty(property.second, vmemo)) { + if (property.first < maximumIndexForProperty(property.second, methodCount, signalCount, propertyCount)) { // This property is available in the specified context if (property.second->isFunction() || property.second->isSignalHandler()) { // Prefer the earlier resolution @@ -933,33 +865,25 @@ QString QQmlPropertyData::name(QObject *object) const QString QQmlPropertyData::name(const QMetaObject *metaObject) const { - if (!metaObject || coreIndex == -1) + if (!metaObject || coreIndex() == -1) return QString(); - if (flags & IsFunction) { - QMetaMethod m = metaObject->method(coreIndex); + if (isFunction()) { + QMetaMethod m = metaObject->method(coreIndex()); return QString::fromUtf8(m.name().constData()); } else { - QMetaProperty p = metaObject->property(coreIndex); + QMetaProperty p = metaObject->property(coreIndex()); return QString::fromUtf8(p.name()); } } void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor) { - overrideIndexIsProperty = !predecessor->isFunction(); - overrideIndex = predecessor->coreIndex; + setOverrideIndexIsProperty(!predecessor->isFunction()); + setOverrideIndex(predecessor->coreIndex()); - predecessor->flags |= QQmlPropertyData::IsOverridden; -} - -QStringList QQmlPropertyCache::propertyNames() const -{ - QStringList keys; - for (StringCache::ConstIterator iter = stringCache.begin(), cend = stringCache.end(); iter != cend; ++iter) - keys.append(iter.key()); - return keys; + predecessor->_flags.isOverridden = true; } struct StaticQtMetaObject : public QObject @@ -1010,7 +934,6 @@ QString QQmlPropertyCache::signalParameterStringForJS(QV4::ExecutionEngine *engi { bool unnamedParameter = false; const QSet<QString> &illegalNames = engine->v8Engine->illegalNames(); - QString error; QString parameters; for (int i = 0; i < parameterNameList.count(); ++i) { @@ -1173,9 +1096,21 @@ QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, return qQmlPropertyCacheProperty<const QString &>(engine, obj, name, context, local); } +// these two functions are copied from qmetaobject.cpp static inline const QMetaObjectPrivate *priv(const uint* data) { return reinterpret_cast<const QMetaObjectPrivate*>(data); } +static inline const QByteArray stringData(const QMetaObject *mo, int index) +{ + Q_ASSERT(priv(mo->d.data)->revision >= 7); + const QByteArrayDataPtr data = { const_cast<QByteArrayData*>(&mo->d.stringdata[index]) }; + Q_ASSERT(data.ptr->ref.isStatic()); + Q_ASSERT(data.ptr->alloc == 0); + Q_ASSERT(data.ptr->capacityReserved == 0); + Q_ASSERT(data.ptr->size >= 0); + return data; +} + bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo) { return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject; @@ -1193,7 +1128,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) { struct Sort { static bool lt(const QPair<QString, QQmlPropertyData *> &lhs, const QPair<QString, QQmlPropertyData *> &rhs) { - return lhs.second->coreIndex < rhs.second->coreIndex; + return lhs.second->coreIndex() < rhs.second->coreIndex(); } }; struct Insert { static void in(QQmlPropertyCache *This, @@ -1204,7 +1139,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) return; if (data->isFunction()) { - if (data->coreIndex < This->methodIndexCacheStart) + if (data->coreIndex() < This->methodIndexCacheStart) return; QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data); @@ -1214,7 +1149,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) data = This->overrideData(data); if (data && !data->isFunction()) Insert::in(This, properties, methods, iter, data); } else { - if (data->coreIndex < This->propertyIndexCacheStart) + if (data->coreIndex() < This->propertyIndexCacheStart) return; QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data); @@ -1245,11 +1180,11 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) QQmlPropertyData *data = properties.at(ii).second; int notifierId = -1; - if (data->notifyIndex != -1) - notifierId = data->notifyIndex - signalHandlerIndexCacheStart; + if (data->notifyIndex() != -1) + notifierId = data->notifyIndex() - signalHandlerIndexCacheStart; QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(), - QMetaType::typeName(data->propType), + QMetaType::typeName(data->propType()), notifierId); property.setReadable(true); @@ -1261,14 +1196,16 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) QQmlPropertyData *data = methods.at(ii).second; QByteArray returnType; - if (data->propType != 0) - returnType = QMetaType::typeName(data->propType); + if (data->propType() != 0) + returnType = QMetaType::typeName(data->propType()); - QByteArray signature = methods.at(ii).first.toUtf8() + '('; + QByteArray signature; + // '+=' reserves extra capacity. Follow-up appending will be probably free. + signature += methods.at(ii).first.toUtf8() + '('; QQmlPropertyCacheMethodArguments *arguments = 0; if (data->hasArguments()) { - arguments = (QQmlPropertyCacheMethodArguments *)data->arguments; + arguments = (QQmlPropertyCacheMethodArguments *)data->arguments(); Q_ASSERT(arguments->argumentsValid); for (int ii = 0; ii < arguments->arguments[0]; ++ii) { if (ii != 0) signature.append(','); @@ -1295,13 +1232,227 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) if (!_defaultPropertyName.isEmpty()) { QQmlPropertyData *dp = property(_defaultPropertyName, 0, 0); - if (dp && dp->coreIndex >= propertyIndexCacheStart) { + if (dp && dp->coreIndex() >= propertyIndexCacheStart) { Q_ASSERT(!dp->isFunction()); builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8()); } } } +namespace { +template <typename StringVisitor, typename TypeInfoVisitor> +int visitMethods(const QMetaObject &mo, int methodOffset, int methodCount, + StringVisitor visitString, TypeInfoVisitor visitTypeInfo) +{ + const int intsPerMethod = 5; + + int fieldsForParameterData = 0; + + bool hasRevisionedMethods = false; + + for (int i = 0; i < methodCount; ++i) { + const int handle = methodOffset + i * intsPerMethod; + + const uint flags = mo.d.data[handle + 4]; + if (flags & MethodRevisioned) + hasRevisionedMethods = true; + + visitString(mo.d.data[handle + 0]); // name + visitString(mo.d.data[handle + 3]); // tag + + const int argc = mo.d.data[handle + 1]; + const int paramIndex = mo.d.data[handle + 2]; + + fieldsForParameterData += argc * 2; // type and name + fieldsForParameterData += 1; // + return type + + // return type + args + for (int i = 0; i < 1 + argc; ++i) { + // type name (maybe) + visitTypeInfo(mo.d.data[paramIndex + i]); + + // parameter name + if (i > 0) + visitString(mo.d.data[paramIndex + argc + i]); + } + } + + int fieldsForRevisions = 0; + if (hasRevisionedMethods) + fieldsForRevisions = methodCount; + + return methodCount * intsPerMethod + fieldsForRevisions + fieldsForParameterData; +} + +template <typename StringVisitor, typename TypeInfoVisitor> +int visitProperties(const QMetaObject &mo, StringVisitor visitString, TypeInfoVisitor visitTypeInfo) +{ + const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); + const int intsPerProperty = 3; + + bool hasRevisionedProperties = false; + bool hasNotifySignals = false; + + for (int i = 0; i < priv->propertyCount; ++i) { + const int handle = priv->propertyData + i * intsPerProperty; + + const auto flags = mo.d.data[handle + 2]; + if (flags & Revisioned) { + hasRevisionedProperties = true; + } + if (flags & Notify) + hasNotifySignals = true; + + visitString(mo.d.data[handle]); // name + visitTypeInfo(mo.d.data[handle + 1]); + } + + int fieldsForPropertyRevisions = 0; + if (hasRevisionedProperties) + fieldsForPropertyRevisions = priv->propertyCount; + + int fieldsForNotifySignals = 0; + if (hasNotifySignals) + fieldsForNotifySignals = priv->propertyCount; + + return priv->propertyCount * intsPerProperty + fieldsForPropertyRevisions + + fieldsForNotifySignals; +} + +template <typename StringVisitor> +int visitClassInfo(const QMetaObject &mo, StringVisitor visitString) +{ + const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); + const int intsPerClassInfo = 2; + + for (int i = 0; i < priv->classInfoCount; ++i) { + const int handle = priv->classInfoData + i * intsPerClassInfo; + + visitString(mo.d.data[handle]); // key + visitString(mo.d.data[handle + 1]); // value + } + + return priv->classInfoCount * intsPerClassInfo; +} + +template <typename StringVisitor> +int visitEnumerations(const QMetaObject &mo, StringVisitor visitString) +{ + const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); + const int intsPerEnumerator = 4; + + int fieldCount = priv->enumeratorCount * intsPerEnumerator; + + for (int i = 0; i < priv->enumeratorCount; ++i) { + const uint *enumeratorData = mo.d.data + priv->enumeratorData + i * intsPerEnumerator; + + const uint keyCount = enumeratorData[2]; + fieldCount += keyCount * 2; + + visitString(enumeratorData[0]); // name + + const uint keyOffset = enumeratorData[3]; + + for (uint j = 0; j < keyCount; ++j) { + visitString(mo.d.data[keyOffset + 2 * j]); + } + } + + return fieldCount; +} + +template <typename StringVisitor> +int countMetaObjectFields(const QMetaObject &mo, StringVisitor stringVisitor) +{ + const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); + + const auto typeInfoVisitor = [&stringVisitor](uint typeInfo) { + if (typeInfo & IsUnresolvedType) + stringVisitor(typeInfo & TypeNameIndexMask); + }; + + int fieldCount = MetaObjectPrivateFieldCount; + + fieldCount += visitMethods(mo, priv->methodData, priv->methodCount, stringVisitor, + typeInfoVisitor); + fieldCount += visitMethods(mo, priv->constructorData, priv->constructorCount, stringVisitor, + typeInfoVisitor); + + fieldCount += visitProperties(mo, stringVisitor, typeInfoVisitor); + fieldCount += visitClassInfo(mo, stringVisitor); + fieldCount += visitEnumerations(mo, stringVisitor); + + return fieldCount; +} + +} // anonymous namespace + +bool QQmlPropertyCache::determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, + int *stringCount) +{ + const QMetaObjectPrivate *priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); + if (priv->revision != 7) { + return false; + } + + uint highestStringIndex = 0; + const auto stringIndexVisitor = [&highestStringIndex](uint index) { + highestStringIndex = qMax(highestStringIndex, index); + }; + + *fieldCount = countMetaObjectFields(mo, stringIndexVisitor); + *stringCount = highestStringIndex + 1; + + return true; +} + +bool QQmlPropertyCache::addToHash(QCryptographicHash &hash, const QMetaObject &mo) +{ + int fieldCount = 0; + int stringCount = 0; + if (!determineMetaObjectSizes(mo, &fieldCount, &stringCount)) { + return false; + } + + hash.addData(reinterpret_cast<const char *>(mo.d.data), fieldCount * sizeof(uint)); + for (int i = 0; i < stringCount; ++i) { + hash.addData(stringData(&mo, i)); + } + + return true; +} + +QByteArray QQmlPropertyCache::checksum(bool *ok) +{ + if (!_checksum.isEmpty()) { + *ok = true; + return _checksum; + } + + // Generate a checksum on the meta-object data only on C++ types. + if (!_metaObject || _ownMetaObject) { + *ok = false; + return _checksum; + } + + QCryptographicHash hash(QCryptographicHash::Md5); + + if (_parent) { + hash.addData(_parent->checksum(ok)); + if (!*ok) + return QByteArray(); + } + + if (!addToHash(hash, *createMetaObject())) { + *ok = false; + return QByteArray(); + } + + _checksum = hash.result(); + *ok = !_checksum.isEmpty(); + return _checksum; +} + /*! \internal \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()). This is different from QMetaMethod::methodIndex(). @@ -1310,7 +1461,7 @@ QList<QByteArray> QQmlPropertyCache::signalParameterNames(int index) const { QQmlPropertyData *signalData = signal(index); if (signalData && signalData->hasArguments()) { - QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments; + QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments(); if (args && args->names) return *args->names; const QMetaMethod &method = QMetaObjectPrivate::signal(firstCppMetaObject(), index); @@ -1412,9 +1563,9 @@ QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const int QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const { - Q_ASSERT(!_m.isNull() && data.coreIndex >= 0); + Q_ASSERT(!_m.isNull() && data.coreIndex() >= 0); - int type = data.propType; + int type = data.propType(); const char *propTypeName = 0; @@ -1424,16 +1575,16 @@ int QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *u if (_m.isT1()) { QQmlPropertyCache *c = _m.asT1(); - Q_ASSERT(data.coreIndex < c->methodIndexCacheStart + c->methodIndexCache.count()); + Q_ASSERT(data.coreIndex() < c->methodIndexCacheStart + c->methodIndexCache.count()); - while (data.coreIndex < c->methodIndexCacheStart) + while (data.coreIndex() < c->methodIndexCacheStart) c = c->_parent; const QMetaObject *metaObject = c->createMetaObject(); Q_ASSERT(metaObject); - m = metaObject->method(data.coreIndex); + m = metaObject->method(data.coreIndex()); } else { - m = _m.asT2()->method(data.coreIndex); + m = _m.asT2()->method(data.coreIndex()); } type = m.returnType(); @@ -1457,7 +1608,8 @@ int QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *u return type; } -int *QQmlMetaObject::methodParameterTypes(int index, QVarLengthArray<int, 9> &dummy, QByteArray *unknownTypeError) const +int *QQmlMetaObject::methodParameterTypes(int index, ArgTypeStorage *argStorage, + QByteArray *unknownTypeError) const { Q_ASSERT(!_m.isNull() && index >= 0); @@ -1472,19 +1624,19 @@ int *QQmlMetaObject::methodParameterTypes(int index, QVarLengthArray<int, 9> &du QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart)); - if (rv->arguments && static_cast<A *>(rv->arguments)->argumentsValid) - return static_cast<A *>(rv->arguments)->arguments; + if (rv->arguments() && static_cast<A *>(rv->arguments())->argumentsValid) + return static_cast<A *>(rv->arguments())->arguments; const QMetaObject *metaObject = c->createMetaObject(); Q_ASSERT(metaObject); QMetaMethod m = metaObject->method(index); int argc = m.parameterCount(); - if (!rv->arguments) { + if (!rv->arguments()) { A *args = c->createArgumentsObject(argc, m.parameterNames()); - rv->arguments = args; + rv->setArguments(args); } - A *args = static_cast<A *>(rv->arguments); + A *args = static_cast<A *>(rv->arguments()); QList<QByteArray> argTypeNames; // Only loaded if needed @@ -1508,43 +1660,57 @@ int *QQmlMetaObject::methodParameterTypes(int index, QVarLengthArray<int, 9> &du args->arguments[ii + 1] = type; } args->argumentsValid = true; - return static_cast<A *>(rv->arguments)->arguments; + return static_cast<A *>(rv->arguments())->arguments; } else { QMetaMethod m = _m.asT2()->method(index); - int argc = m.parameterCount(); - dummy.resize(argc + 1); - dummy[0] = argc; - QList<QByteArray> argTypeNames; // Only loaded if needed + return methodParameterTypes(m, argStorage, unknownTypeError); - for (int ii = 0; ii < argc; ++ii) { - int type = m.parameterType(ii); - QMetaType::TypeFlags flags = QMetaType::typeFlags(type); - if (flags & QMetaType::IsEnumeration) - type = QVariant::Int; - else if (type == QMetaType::UnknownType || - (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) && - type != qMetaTypeId<QJSValue>())) { - //the UserType clause is to catch registered QFlags) - if (argTypeNames.isEmpty()) - argTypeNames = m.parameterTypes(); - type = EnumType(_m.asT2(), argTypeNames.at(ii), type); - } - if (type == QMetaType::UnknownType) { - if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii); - return 0; - } - dummy[ii + 1] = type; - } + } +} - return dummy.data(); +int *QQmlMetaObject::methodParameterTypes(const QMetaMethod &m, ArgTypeStorage *argStorage, + QByteArray *unknownTypeError) const +{ + Q_ASSERT(argStorage); + + int argc = m.parameterCount(); + argStorage->resize(argc + 1); + argStorage->operator[](0) = argc; + QList<QByteArray> argTypeNames; // Only loaded if needed + + for (int ii = 0; ii < argc; ++ii) { + int type = m.parameterType(ii); + QMetaType::TypeFlags flags = QMetaType::typeFlags(type); + if (flags & QMetaType::IsEnumeration) + type = QVariant::Int; + else if (type == QMetaType::UnknownType || + (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) && + type != qMetaTypeId<QJSValue>())) { + //the UserType clause is to catch registered QFlags) + if (argTypeNames.isEmpty()) + argTypeNames = m.parameterTypes(); + type = EnumType(_m.asT2(), argTypeNames.at(ii), type); + } + if (type == QMetaType::UnknownType) { + if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii); + return 0; + } + argStorage->operator[](ii + 1) = type; } + + return argStorage->data(); } void QQmlObjectOrGadget::metacall(QMetaObject::Call type, int index, void **argv) const { - if (ptr.isT1()) + if (ptr.isNull()) { + const QMetaObject *metaObject = _m.asT2(); + metaObject->d.static_metacall(0, type, index, argv); + } + else if (ptr.isT1()) { QMetaObject::metacall(ptr.asT1(), type, index, argv); + } else { const QMetaObject *metaObject = _m.asT1()->metaObject(); QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &metaObject, &index); @@ -1552,4 +1718,11 @@ void QQmlObjectOrGadget::metacall(QMetaObject::Call type, int index, void **argv } } +int *QQmlStaticMetaObject::constructorParameterTypes(int index, ArgTypeStorage *dummy, + QByteArray *unknownTypeError) const +{ + QMetaMethod m = _m.asT2()->constructor(index); + return methodParameterTypes(m, dummy, unknownTypeError); +} + QT_END_NAMESPACE |