X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fdeclarative%2Fqml%2Fqdeclarativepropertycache.cpp;h=c8bfd9836371d9842f9feb466fb4b72a122c8a5a;hb=6a42a6e0a9a1abdda0d07a5a20b4ac7e45348684;hp=6ff47d7b5735a0f17406c4005e16e7a13d6236d5;hpb=c500bd41751ca253fe40868fe54557749736d109;p=profile%2Fivi%2Fqtdeclarative.git diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp index 6ff47d7..c8bfd98 100644 --- a/src/declarative/qml/qdeclarativepropertycache.cpp +++ b/src/declarative/qml/qdeclarativepropertycache.cpp @@ -1,8 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ ** ** This file is part of the QtDeclarative module of the Qt Toolkit. ** @@ -35,84 +34,110 @@ ** ** ** +** ** $QT_END_LICENSE$ ** ****************************************************************************/ -#include "private/qdeclarativepropertycache_p.h" +#include "qdeclarativepropertycache_p.h" -#include "private/qdeclarativeengine_p.h" -#include "private/qdeclarativebinding_p.h" -#include "private/qv8engine_p.h" +#include "qdeclarativeengine_p.h" +#include "qdeclarativebinding_p.h" +#include #include +#include #include -Q_DECLARE_METATYPE(QScriptValue) +Q_DECLARE_METATYPE(QJSValue) Q_DECLARE_METATYPE(QDeclarativeV8Handle); QT_BEGIN_NAMESPACE +#define Q_INT16_MAX 32767 + +class QDeclarativePropertyCacheMethodArguments +{ +public: + QDeclarativePropertyCacheMethodArguments *next; + int arguments[0]; +}; + // Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick // to load -static QDeclarativePropertyCache::Data::Flags fastFlagsForProperty(const QMetaProperty &p) +static QDeclarativePropertyData::Flags fastFlagsForProperty(const QMetaProperty &p) { - QDeclarativePropertyCache::Data::Flags flags; + QDeclarativePropertyData::Flags flags; if (p.isConstant()) - flags |= QDeclarativePropertyCache::Data::IsConstant; + flags |= QDeclarativePropertyData::IsConstant; if (p.isWritable()) - flags |= QDeclarativePropertyCache::Data::IsWritable; + flags |= QDeclarativePropertyData::IsWritable; if (p.isResettable()) - flags |= QDeclarativePropertyCache::Data::IsResettable; + flags |= QDeclarativePropertyData::IsResettable; if (p.isFinal()) - flags |= QDeclarativePropertyCache::Data::IsFinal; + flags |= QDeclarativePropertyData::IsFinal; if (p.isEnumType()) - flags |= QDeclarativePropertyCache::Data::IsEnumType; + flags |= QDeclarativePropertyData::IsEnumType; return flags; } // Flags that do depend on the property's QMetaProperty::userType() and thus are slow to // load -static QDeclarativePropertyCache::Data::Flags flagsForPropertyType(int propType, QDeclarativeEngine *engine) +static QDeclarativePropertyData::Flags flagsForPropertyType(int propType, QDeclarativeEngine *engine) { - QDeclarativePropertyCache::Data::Flags flags; + Q_ASSERT(propType != -1); - if (propType < QMetaType::User && propType != QMetaType::QObjectStar && propType != QMetaType::QWidgetStar) { + QDeclarativePropertyData::Flags flags; + + if (propType == QMetaType::QObjectStar || propType == QMetaType::QWidgetStar) { + flags |= QDeclarativePropertyData::IsQObjectDerived; + } else if (propType == QMetaType::QVariant) { + flags |= QDeclarativePropertyData::IsQVariant; + } else if (propType < (int)QVariant::UserType) { } else if (propType == qMetaTypeId()) { - flags |= QDeclarativePropertyCache::Data::IsQmlBinding; - } else if (propType == qMetaTypeId()) { - flags |= QDeclarativePropertyCache::Data::IsQScriptValue; + flags |= QDeclarativePropertyData::IsQmlBinding; + } else if (propType == qMetaTypeId()) { + flags |= QDeclarativePropertyData::IsQJSValue; } else if (propType == qMetaTypeId()) { - flags |= QDeclarativePropertyCache::Data::IsV8Handle; + flags |= QDeclarativePropertyData::IsV8Handle; } else { QDeclarativeMetaType::TypeCategory cat = engine ? QDeclarativeEnginePrivate::get(engine)->typeCategory(propType) : QDeclarativeMetaType::typeCategory(propType); if (cat == QDeclarativeMetaType::Object) - flags |= QDeclarativePropertyCache::Data::IsQObjectDerived; + flags |= QDeclarativePropertyData::IsQObjectDerived; else if (cat == QDeclarativeMetaType::List) - flags |= QDeclarativePropertyCache::Data::IsQList; + flags |= QDeclarativePropertyData::IsQList; } return flags; } -QDeclarativePropertyCache::Data::Flags -QDeclarativePropertyCache::Data::flagsForProperty(const QMetaProperty &p, QDeclarativeEngine *engine) +static int metaObjectSignalCount(const QMetaObject *metaObject) +{ + int signalCount = 0; + for (const QMetaObject *obj = metaObject; obj; obj = obj->superClass()) + signalCount += QMetaObjectPrivate::get(obj)->signalCount; + return signalCount; +} + +QDeclarativePropertyData::Flags +QDeclarativePropertyData::flagsForProperty(const QMetaProperty &p, QDeclarativeEngine *engine) { return fastFlagsForProperty(p) | flagsForPropertyType(p.userType(), engine); } -void QDeclarativePropertyCache::Data::lazyLoad(const QMetaProperty &p, QDeclarativeEngine *engine) +void QDeclarativePropertyData::lazyLoad(const QMetaProperty &p, QDeclarativeEngine *engine) { Q_UNUSED(engine); coreIndex = p.propertyIndex(); notifyIndex = p.notifySignalIndex(); + Q_ASSERT(p.revision() <= Q_INT16_MAX); revision = p.revision(); flags = fastFlagsForProperty(p); @@ -120,33 +145,35 @@ void QDeclarativePropertyCache::Data::lazyLoad(const QMetaProperty &p, QDeclarat int type = p.type(); if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) { propType = type; - flags |= QDeclarativePropertyCache::Data::IsQObjectDerived; + flags |= QDeclarativePropertyData::IsQObjectDerived; + } else if (type == QMetaType::QVariant) { + propType = type; + flags |= QDeclarativePropertyData::IsQVariant; } else if (type == QVariant::UserType || type == -1) { propTypeName = p.typeName(); - flags |= QDeclarativePropertyCache::Data::NotFullyResolved; + flags |= QDeclarativePropertyData::NotFullyResolved; } else { propType = type; } } -void QDeclarativePropertyCache::Data::load(const QMetaProperty &p, QDeclarativeEngine *engine) +void QDeclarativePropertyData::load(const QMetaProperty &p, QDeclarativeEngine *engine) { propType = p.userType(); - if (QVariant::Type(propType) == QVariant::LastType) - propType = qMetaTypeId(); coreIndex = p.propertyIndex(); notifyIndex = p.notifySignalIndex(); flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine); + Q_ASSERT(p.revision() <= Q_INT16_MAX); revision = p.revision(); } -void QDeclarativePropertyCache::Data::load(const QMetaMethod &m) +void QDeclarativePropertyData::load(const QMetaMethod &m) { coreIndex = m.methodIndex(); - relatedIndex = -1; - flags |= Data::IsFunction; + arguments = 0; + flags |= IsFunction; if (m.methodType() == QMetaMethod::Signal) - flags |= Data::IsSignal; + flags |= IsSignal; propType = QVariant::Invalid; const char *returnType = m.typeName(); @@ -158,28 +185,29 @@ void QDeclarativePropertyCache::Data::load(const QMetaMethod &m) ++signature; if (*signature != ')') { - flags |= Data::HasArguments; + flags |= HasArguments; if (0 == ::strcmp(signature, "QDeclarativeV8Function*)")) { - flags |= Data::IsV8Function; + flags |= IsV8Function; } } + Q_ASSERT(m.revision() <= Q_INT16_MAX); revision = m.revision(); } -void QDeclarativePropertyCache::Data::lazyLoad(const QMetaMethod &m) +void QDeclarativePropertyData::lazyLoad(const QMetaMethod &m) { coreIndex = m.methodIndex(); - relatedIndex = -1; - flags |= Data::IsFunction; + arguments = 0; + flags |= IsFunction; if (m.methodType() == QMetaMethod::Signal) - flags |= Data::IsSignal; + flags |= IsSignal; propType = QVariant::Invalid; const char *returnType = m.typeName(); if (returnType && *returnType) { propTypeName = returnType; - flags |= Data::NotFullyResolved; + flags |= NotFullyResolved; } const char *signature = m.signature(); @@ -187,12 +215,13 @@ void QDeclarativePropertyCache::Data::lazyLoad(const QMetaMethod &m) ++signature; if (*signature != ')') { - flags |= Data::HasArguments; + flags |= HasArguments; if (0 == ::strcmp(signature, "QDeclarativeV8Function*)")) { - flags |= Data::IsV8Function; + flags |= IsV8Function; } } + Q_ASSERT(m.revision() <= Q_INT16_MAX); revision = m.revision(); } @@ -200,7 +229,8 @@ void QDeclarativePropertyCache::Data::lazyLoad(const QMetaMethod &m) Creates a new empty QDeclarativePropertyCache. */ QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e) -: QDeclarativeCleanup(e), engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0) +: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), + signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0) { Q_ASSERT(engine); } @@ -209,7 +239,8 @@ QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e) Creates a new QDeclarativePropertyCache of \a metaObject. */ QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e, const QMetaObject *metaObject) -: QDeclarativeCleanup(e), engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0) +: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), + signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0) { Q_ASSERT(engine); Q_ASSERT(metaObject); @@ -221,8 +252,28 @@ QDeclarativePropertyCache::~QDeclarativePropertyCache() { clear(); + QDeclarativePropertyCacheMethodArguments *args = argumentsCache; + while (args) { + QDeclarativePropertyCacheMethodArguments *next = args->next; + free(args); + args = next; + } + + // We must clear this prior to releasing the parent incase it is a + // linked hash + stringCache.clear(); if (parent) parent->release(); parent = 0; + engine = 0; +} + +void QDeclarativePropertyCache::destroy() +{ + Q_ASSERT(engine || constructor.IsEmpty()); + if (constructor.IsEmpty()) + delete this; + else + QDeclarativeEnginePrivate::deleteInEngineThread(engine, this); } // This is inherited from QDeclarativeCleanup, so it should only clear the things @@ -233,89 +284,128 @@ void QDeclarativePropertyCache::clear() engine = 0; } -QDeclarativePropertyCache::Data QDeclarativePropertyCache::create(const QMetaObject *metaObject, - const QString &property) -{ - Q_ASSERT(metaObject); - - QDeclarativePropertyCache::Data rv; - { - const QMetaObject *cmo = metaObject; - while (cmo) { - int idx = metaObject->indexOfProperty(property.toUtf8()); - if (idx != -1) { - QMetaProperty p = metaObject->property(idx); - if (p.isScriptable()) { - rv.load(metaObject->property(idx)); - return rv; - } else { - while (cmo && cmo->propertyOffset() >= idx) - cmo = cmo->superClass(); - } - } else { - cmo = 0; - } - } - } - - int methodCount = metaObject->methodCount(); - for (int ii = methodCount - 1; ii >= 3; --ii) { // >=3 to block the destroyed signal and deleteLater() slot - QMetaMethod m = metaObject->method(ii); - if (m.access() == QMetaMethod::Private) - continue; - QString methodName = QString::fromUtf8(m.signature()); - - int parenIdx = methodName.indexOf(QLatin1Char('(')); - Q_ASSERT(parenIdx != -1); - QStringRef methodNameRef = methodName.leftRef(parenIdx); - - if (methodNameRef == property) { - rv.load(m); - return rv; - } - } - - return rv; -} - -QDeclarativePropertyCache *QDeclarativePropertyCache::copy() +QDeclarativePropertyCache *QDeclarativePropertyCache::copy(int reserve) { QDeclarativePropertyCache *cache = new QDeclarativePropertyCache(engine); cache->parent = this; cache->parent->addref(); cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart; cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart; - cache->stringCache = stringCache; + cache->signalHanderIndexCacheStart = signalHandlerIndexCache.count() + signalHanderIndexCacheStart; + cache->stringCache.linkAndReserve(stringCache, reserve); cache->allowedRevisionCache = allowedRevisionCache; + cache->metaObject = metaObject; // We specifically do *NOT* copy the constructor return cache; } +QDeclarativePropertyCache *QDeclarativePropertyCache::copy() +{ + return copy(0); +} + +QDeclarativePropertyCache * +QDeclarativePropertyCache::copyAndAppend(QDeclarativeEngine *engine, const QMetaObject *metaObject, + QDeclarativePropertyData::Flag propertyFlags, + QDeclarativePropertyData::Flag methodFlags, + QDeclarativePropertyData::Flag signalFlags) +{ + return copyAndAppend(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags); +} + +QDeclarativePropertyCache * +QDeclarativePropertyCache::copyAndAppend(QDeclarativeEngine *engine, const QMetaObject *metaObject, + int revision, + QDeclarativePropertyData::Flag propertyFlags, + QDeclarativePropertyData::Flag methodFlags, + QDeclarativePropertyData::Flag signalFlags) +{ + Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4); + + // Reserve enough space in the name hash for all the methods (including signals), all the + // signal handlers and all the properties. This assumes no name clashes, but this is the + // common case. + QDeclarativePropertyCache *rv = copy(QMetaObjectPrivate::get(metaObject)->methodCount + + QMetaObjectPrivate::get(metaObject)->signalCount + + QMetaObjectPrivate::get(metaObject)->propertyCount); + + rv->append(engine, metaObject, revision, propertyFlags, methodFlags, signalFlags); + + return rv; +} + void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaObject *metaObject, - Data::Flag propertyFlags, Data::Flag methodFlags, Data::Flag signalFlags) + QDeclarativePropertyData::Flag propertyFlags, + QDeclarativePropertyData::Flag methodFlags, + QDeclarativePropertyData::Flag signalFlags) { append(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags); } void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaObject *metaObject, int revision, - Data::Flag propertyFlags, Data::Flag methodFlags, Data::Flag signalFlags) + QDeclarativePropertyData::Flag propertyFlags, + QDeclarativePropertyData::Flag methodFlags, + QDeclarativePropertyData::Flag signalFlags) { Q_UNUSED(revision); + Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache - qPersistentDispose(constructor); // Now invalid + this->metaObject = metaObject; bool dynamicMetaObject = isDynamicMetaObject(metaObject); allowedRevisionCache.append(0); int methodCount = metaObject->methodCount(); - // 3 to block the destroyed signal and the deleteLater() slot - int methodOffset = qMax(3, metaObject->methodOffset()); + Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4); + int signalCount = metaObjectSignalCount(metaObject); + int classInfoCount = QMetaObjectPrivate::get(metaObject)->classInfoCount; + + QDeclarativeAccessorProperties::Properties accessorProperties; + + // Special case QObject as we don't want to add a qt_HasQmlAccessors classinfo to it + if (metaObject == &QObject::staticMetaObject) { + accessorProperties = QDeclarativeAccessorProperties::properties(metaObject); + } else if (classInfoCount) { + int classInfoOffset = metaObject->classInfoOffset(); + bool hasFastProperty = false; + for (int ii = 0; ii < classInfoCount; ++ii) { + int idx = ii + classInfoOffset; + + if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) { + hasFastProperty = true; + break; + } + } + + if (hasFastProperty) { + accessorProperties = QDeclarativeAccessorProperties::properties(metaObject); + if (accessorProperties.count == 0) + qFatal("QDeclarativePropertyCache: %s has FastProperty class info, but has not " + "installed property accessors", metaObject->className()); + } else { +#ifndef QT_NO_DEBUG + accessorProperties = QDeclarativeAccessorProperties::properties(metaObject); + if (accessorProperties.count != 0) + qFatal("QDeclarativePropertyCache: %s has fast property accessors, but is missing " + "FastProperty class info", metaObject->className()); +#endif + } + } + + // qMax(defaultMethods, methodOffset) to block the signals and slots of QObject::staticMetaObject + // incl. destroyed signals, objectNameChanged signal, deleteLater slot, _q_reregisterTimers slot. + int methodOffset = qMax(QObject::staticMetaObject.methodCount(), metaObject->methodOffset()); + int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount; + // update() should have reserved enough space in the vector that this doesn't cause a realloc + // and invalidate the stringCache. methodIndexCache.resize(methodCount - methodIndexCacheStart); + signalHandlerIndexCache.resize(signalCount - signalHanderIndexCacheStart); + int signalHandlerIndex = signalOffset; for (int ii = methodOffset; ii < methodCount; ++ii) { QMetaMethod m = metaObject->method(ii); if (m.access() == QMetaMethod::Private) @@ -324,80 +414,150 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb // Extract method name const char *signature = m.signature(); const char *cptr = signature; - while (*cptr != '(') { Q_ASSERT(*cptr != 0); ++cptr; } - QString str = dynamicMetaObject?QString::fromUtf8(signature, cptr - signature): - QString::fromLatin1(signature, cptr - signature); - QHashedString methodName(str); + char utf8 = 0; + while (*cptr != '(') { + Q_ASSERT(*cptr != 0); + utf8 |= *cptr & 0x80; + ++cptr; + } - Data *data = &methodIndexCache[ii - methodIndexCacheStart]; + QDeclarativePropertyData *data = &methodIndexCache[ii - methodIndexCacheStart]; + QDeclarativePropertyData *sigdata = 0; data->lazyLoad(m); + if (data->isSignal()) data->flags |= signalFlags; else data->flags |= methodFlags; if (!dynamicMetaObject) - data->flags |= Data::IsDirect; + data->flags |= QDeclarativePropertyData::IsDirect; + Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX); data->metaObjectOffset = allowedRevisionCache.count() - 1; - if (Data **old = stringCache.value(methodName)) { - // We only overload methods in the same class, exactly like C++ - if ((*old)->flags & Data::IsFunction && (*old)->coreIndex >= methodOffset) - data->relatedIndex = (*old)->coreIndex; - data->overrideIndexIsProperty = !bool((*old)->flags & Data::IsFunction); - data->overrideIndex = (*old)->coreIndex; + if (data->isSignal()) { + sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHanderIndexCacheStart]; + *sigdata = *data; + sigdata->flags |= QDeclarativePropertyData::IsSignalHandler; + } + + QDeclarativePropertyData *old = 0; + + if (utf8) { + QHashedString methodName(QString::fromUtf8(signature, cptr - signature)); + if (QDeclarativePropertyData **it = stringCache.value(methodName)) + old = *it; + stringCache.insert(methodName, data); + + if (data->isSignal()) { + QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1)); + stringCache.insert(on, sigdata); + ++signalHandlerIndex; + } + } else { + QHashedCStringRef methodName(signature, cptr - signature); + if (QDeclarativePropertyData **it = stringCache.value(methodName)) + old = *it; + stringCache.insert(methodName, data); + + if (data->isSignal()) { + int length = methodName.length(); + + QVarLengthArray str(length+3); + str[0] = 'o'; + str[1] = 'n'; + str[2] = toupper(signature[0]); + if (length > 1) + memcpy(&str[3], &signature[1], length - 1); + str[length + 2] = '\0'; + + QHashedString on(QString::fromLatin1(str.data())); + stringCache.insert(on, sigdata); + ++signalHandlerIndex; + } } - stringCache.insert(methodName, data); + if (old) { + // We only overload methods in the same class, exactly like C++ + if (old->isFunction() && old->coreIndex >= methodOffset) + data->flags |= QDeclarativePropertyData::IsOverload; + data->overrideIndexIsProperty = !old->isFunction(); + data->overrideIndex = old->coreIndex; + } } int propCount = metaObject->propertyCount(); int propOffset = metaObject->propertyOffset(); + // update() should have reserved enough space in the vector that this doesn't cause a realloc + // and invalidate the stringCache. propertyIndexCache.resize(propCount - propertyIndexCacheStart); for (int ii = propOffset; ii < propCount; ++ii) { QMetaProperty p = metaObject->property(ii); if (!p.isScriptable()) continue; - QString str = dynamicMetaObject?QString::fromUtf8(p.name()): - QString::fromLatin1(p.name()); - QHashedString propName(str); + const char *str = p.name(); + char utf8 = 0; + const char *cptr = str; + while (*cptr != 0) { + utf8 |= *cptr & 0x80; + ++cptr; + } - Data *data = &propertyIndexCache[ii - propertyIndexCacheStart]; + QDeclarativePropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart]; data->lazyLoad(p, engine); data->flags |= propertyFlags; if (!dynamicMetaObject) - data->flags |= Data::IsDirect; + data->flags |= QDeclarativePropertyData::IsDirect; + Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX); data->metaObjectOffset = allowedRevisionCache.count() - 1; - if (Data **old = stringCache.value(propName)) { - data->overrideIndexIsProperty = !bool((*old)->flags & Data::IsFunction); - data->overrideIndex = (*old)->coreIndex; + QDeclarativePropertyData *old = 0; + + if (utf8) { + QHashedString propName(QString::fromUtf8(str, cptr - str)); + if (QDeclarativePropertyData **it = stringCache.value(propName)) + old = *it; + stringCache.insert(propName, data); + } else { + QHashedCStringRef propName(str, cptr - str); + if (QDeclarativePropertyData **it = stringCache.value(propName)) + old = *it; + stringCache.insert(propName, data); } - stringCache.insert(propName, data); + QDeclarativeAccessorProperties::Property *accessorProperty = accessorProperties.property(str); + + // Fast properties may not be overrides or revisioned + Q_ASSERT(accessorProperty == 0 || (old == 0 && data->revision == 0)); + + if (accessorProperty) { + data->flags |= QDeclarativePropertyData::HasAccessors; + data->accessors = accessorProperty->accessors; + data->accessorData = accessorProperty->data; + } else if (old) { + data->overrideIndexIsProperty = !old->isFunction(); + data->overrideIndex = old->coreIndex; + } } } -void QDeclarativePropertyCache::resolve(Data *data) const +void QDeclarativePropertyCache::resolve(QDeclarativePropertyData *data) const { Q_ASSERT(data->notFullyResolved()); data->propType = QMetaType::type(data->propTypeName); - if (QVariant::Type(data->propType) == QVariant::LastType) - data->propType = qMetaTypeId(); - - if (!(data->flags & Data::IsFunction)) + if (!data->isFunction()) data->flags |= flagsForPropertyType(data->propType, engine); - data->flags &= ~Data::NotFullyResolved; + data->flags &= ~QDeclarativePropertyData::NotFullyResolved; } void QDeclarativePropertyCache::updateRecur(QDeclarativeEngine *engine, const QMetaObject *metaObject) @@ -416,14 +576,24 @@ void QDeclarativePropertyCache::update(QDeclarativeEngine *engine, const QMetaOb Q_ASSERT(metaObject); Q_ASSERT(stringCache.isEmpty()); - // Optimization to prevent unnecessary reallocation of lists - propertyIndexCache.reserve(metaObject->propertyCount()); - methodIndexCache.reserve(metaObject->methodCount()); + // Preallocate enough space in the index caches for all the properties/methods/signals that + // are not cached in a parent cache so that the caches never need to be reallocated as this + // would invalidate pointers stored in the stringCache. + int pc = metaObject->propertyCount(); + int mc = metaObject->methodCount(); + int sc = metaObjectSignalCount(metaObject); + propertyIndexCache.reserve(pc - propertyIndexCacheStart); + methodIndexCache.reserve(mc - methodIndexCacheStart); + signalHandlerIndexCache.reserve(sc - signalHanderIndexCacheStart); + + // Reserve enough space in the stringCache for all properties/methods/signals including those + // cached in a parent cache. + stringCache.reserve(pc + mc + sc); updateRecur(engine,metaObject); } -QDeclarativePropertyCache::Data * +QDeclarativePropertyData * QDeclarativePropertyCache::property(int index) const { if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count())) @@ -432,12 +602,12 @@ QDeclarativePropertyCache::property(int index) const if (index < propertyIndexCacheStart) return parent->property(index); - Data *rv = const_cast(&propertyIndexCache.at(index - propertyIndexCacheStart)); + QDeclarativePropertyData *rv = const_cast(&propertyIndexCache.at(index - propertyIndexCacheStart)); if (rv->notFullyResolved()) resolve(rv); return rv; } -QDeclarativePropertyCache::Data * +QDeclarativePropertyData * QDeclarativePropertyCache::method(int index) const { if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count())) @@ -446,20 +616,36 @@ QDeclarativePropertyCache::method(int index) const if (index < methodIndexCacheStart) return parent->method(index); - Data *rv = const_cast(&methodIndexCache.at(index - methodIndexCacheStart)); + QDeclarativePropertyData *rv = const_cast(&methodIndexCache.at(index - methodIndexCacheStart)); if (rv->notFullyResolved()) resolve(rv); return rv; } -QDeclarativePropertyCache::Data * +QDeclarativePropertyData * +QDeclarativePropertyCache::property(const QHashedStringRef &str) const +{ + QDeclarativePropertyData **rv = stringCache.value(str); + if (rv && (*rv)->notFullyResolved()) resolve(*rv); + return rv?*rv:0; +} + +QDeclarativePropertyData * +QDeclarativePropertyCache::property(const QHashedCStringRef &str) const +{ + QDeclarativePropertyData **rv = stringCache.value(str); + if (rv && (*rv)->notFullyResolved()) resolve(*rv); + return rv?*rv:0; +} + +QDeclarativePropertyData * QDeclarativePropertyCache::property(const QString &str) const { - QDeclarativePropertyCache::Data **rv = stringCache.value(str); + QDeclarativePropertyData **rv = stringCache.value(str); if (rv && (*rv)->notFullyResolved()) resolve(*rv); return rv?*rv:0; } -QString QDeclarativePropertyCache::Data::name(QObject *object) +QString QDeclarativePropertyData::name(QObject *object) { if (!object) return QString(); @@ -467,7 +653,7 @@ QString QDeclarativePropertyCache::Data::name(QObject *object) return name(object->metaObject()); } -QString QDeclarativePropertyCache::Data::name(const QMetaObject *metaObject) +QString QDeclarativePropertyData::name(const QMetaObject *metaObject) { if (!metaObject || coreIndex == -1) return QString(); @@ -494,32 +680,183 @@ QStringList QDeclarativePropertyCache::propertyNames() const return keys; } -QDeclarativePropertyCache::Data * -QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj, - const QHashedV8String &name, Data &local) +static int EnumType(const QMetaObject *meta, const QByteArray &str) +{ + QByteArray scope; + QByteArray name; + int scopeIdx = str.lastIndexOf("::"); + if (scopeIdx != -1) { + scope = str.left(scopeIdx); + name = str.mid(scopeIdx + 2); + } else { + name = str; + } + for (int i = meta->enumeratorCount() - 1; i >= 0; --i) { + QMetaEnum m = meta->enumerator(i); + if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) + return QVariant::Int; + } + return QVariant::Invalid; +} + +// Returns an array of the arguments for method \a index. The first entry in the array +// is the number of arguments. +int *QDeclarativePropertyCache::methodParameterTypes(QObject *object, int index, + QVarLengthArray &dummy, + QByteArray *unknownTypeError) +{ + Q_ASSERT(object && index >= 0); + + QDeclarativeData *ddata = QDeclarativeData::get(object, false); + + if (ddata && ddata->propertyCache) { + typedef QDeclarativePropertyCacheMethodArguments A; + + QDeclarativePropertyCache *c = ddata->propertyCache; + Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count()); + + while (index < c->methodIndexCacheStart) + c = c->parent; + + QDeclarativePropertyData *rv = const_cast(&c->methodIndexCache.at(index - c->methodIndexCacheStart)); + + if (rv->arguments) + return static_cast(rv->arguments)->arguments; + + const QMetaObject *metaObject = object->metaObject(); + QMetaMethod m = metaObject->method(index); + QList argTypeNames = m.parameterTypes(); + + A *args = static_cast(malloc(sizeof(A) + (argTypeNames.count() + 1) * sizeof(int))); + args->arguments[0] = argTypeNames.count(); + + for (int ii = 0; ii < argTypeNames.count(); ++ii) { + int type = QMetaType::type(argTypeNames.at(ii)); + if (type == QVariant::Invalid) + type = EnumType(object->metaObject(), argTypeNames.at(ii)); + if (type == QVariant::Invalid) { + if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii); + free(args); + return 0; + } + args->arguments[ii + 1] = type; + } + + rv->arguments = args; + args->next = c->argumentsCache; + c->argumentsCache = args; + return static_cast(rv->arguments)->arguments; + + } else { + QMetaMethod m = object->metaObject()->method(index); + QList argTypeNames = m.parameterTypes(); + dummy.resize(argTypeNames.count() + 1); + dummy[0] = argTypeNames.count(); + + for (int ii = 0; ii < argTypeNames.count(); ++ii) { + int type = QMetaType::type(argTypeNames.at(ii)); + if (type == QVariant::Invalid) + type = EnumType(object->metaObject(), argTypeNames.at(ii)); + if (type == QVariant::Invalid) { + if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii); + return 0; + } + dummy[ii + 1] = type; + } + + return dummy.data(); + } +} + +QDeclarativePropertyData qDeclarativePropertyCacheCreate(const QMetaObject *metaObject, + const QString &property) +{ + Q_ASSERT(metaObject); + + QDeclarativePropertyData rv; + { + const QMetaObject *cmo = metaObject; + const QByteArray propertyName = property.toUtf8(); + while (cmo) { + int idx = cmo->indexOfProperty(propertyName); + if (idx != -1) { + QMetaProperty p = cmo->property(idx); + if (p.isScriptable()) { + rv.load(p); + return rv; + } else { + while (cmo && cmo->propertyOffset() >= idx) + cmo = cmo->superClass(); + } + } else { + cmo = 0; + } + } + } + + int methodCount = metaObject->methodCount(); + int defaultMethods = QObject::staticMetaObject.methodCount(); + for (int ii = methodCount - 1; ii >= defaultMethods; --ii) { + // >=defaultMethods to block the signals and slots of QObject::staticMetaObject + // incl. destroyed signals, objectNameChanged signal, deleteLater slot, _q_reregisterTimers slot. + QMetaMethod m = metaObject->method(ii); + if (m.access() == QMetaMethod::Private) + continue; + QString methodName = QString::fromUtf8(m.signature()); + + int parenIdx = methodName.indexOf(QLatin1Char('(')); + Q_ASSERT(parenIdx != -1); + QStringRef methodNameRef = methodName.leftRef(parenIdx); + + if (methodNameRef == property) { + rv.load(m); + return rv; + } + } + + return rv; +} + +inline const QString &qDeclarativePropertyCacheToString(const QString &string) +{ + return string; +} + +inline QString qDeclarativePropertyCacheToString(const QHashedV8String &string) +{ + return QV8Engine::toStringStatic(string.string()); +} + +template +QDeclarativePropertyData * +qDeclarativePropertyCacheProperty(QDeclarativeEngine *engine, QObject *obj, + const T &name, QDeclarativePropertyData &local) { - // XXX Optimize for worker script case where engine isn't available QDeclarativePropertyCache *cache = 0; - if (engine) { - QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); + if (engine) { QDeclarativeData *ddata = QDeclarativeData::get(obj); - if (ddata && ddata->propertyCache) + + if (ddata && ddata->propertyCache) { cache = ddata->propertyCache; - if (!cache) { + } else if (engine) { + QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); cache = ep->cache(obj); - if (cache && ddata && !ddata->propertyCache) { cache->addref(); ddata->propertyCache = cache; } + if (cache) { + ddata = QDeclarativeData::get(obj, true); + cache->addref(); + ddata->propertyCache = cache; + } } } - QDeclarativePropertyCache::Data *rv = 0; + QDeclarativePropertyData *rv = 0; if (cache) { rv = cache->property(name); } else { - QString strname = QV8Engine::toStringStatic(name.string()); - // QString strname = ep->v8engine.toString(name); - local = QDeclarativePropertyCache::create(obj->metaObject(), strname); + local = qDeclarativePropertyCacheCreate(obj->metaObject(), + qDeclarativePropertyCacheToString(name)); if (local.isValid()) rv = &local; } @@ -527,38 +864,18 @@ QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj, return rv; } -QDeclarativePropertyCache::Data * +QDeclarativePropertyData * QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj, - const QString &name, Data &local) + const QHashedV8String &name, QDeclarativePropertyData &local) { - QDeclarativePropertyCache::Data *rv = 0; - - if (!engine) { - local = QDeclarativePropertyCache::create(obj->metaObject(), name); - if (local.isValid()) - rv = &local; - } else { - QDeclarativeEnginePrivate *enginePrivate = QDeclarativeEnginePrivate::get(engine); - - QDeclarativePropertyCache *cache = 0; - QDeclarativeData *ddata = QDeclarativeData::get(obj); - if (ddata && ddata->propertyCache) - cache = ddata->propertyCache; - if (!cache) { - cache = enginePrivate->cache(obj); - if (cache && ddata && !ddata->propertyCache) { cache->addref(); ddata->propertyCache = cache; } - } - - if (cache) { - rv = cache->property(name); - } else { - local = QDeclarativePropertyCache::create(obj->metaObject(), name); - if (local.isValid()) - rv = &local; - } - } + return qDeclarativePropertyCacheProperty(engine, obj, name, local); +} - return rv; +QDeclarativePropertyData * +QDeclarativePropertyCache::property(QDeclarativeEngine *engine, QObject *obj, + const QString &name, QDeclarativePropertyData &local) +{ + return qDeclarativePropertyCacheProperty(engine, obj, name, local); } static inline const QMetaObjectPrivate *priv(const uint* data)