From: Aaron Kennedy Date: Mon, 4 Jul 2011 02:41:21 +0000 (+1000) Subject: Optimize QDeclarativePropertyCache X-Git-Tag: qt-v5.0.0-alpha1~2144^2~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=71114ff964582f58e68d68bf0301cd42110751cc;p=profile%2Fivi%2Fqtdeclarative.git Optimize QDeclarativePropertyCache The creation of QDeclarativePropertyCaches contributes significantly to the initial compile time of a QML app. Change-Id: Iac5d1578155dfa4678a0e21eab51f4c1675762a9 Reviewed-on: http://codereview.qt.nokia.com/1026 Reviewed-by: Aaron Kennedy --- diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index bca9c65..32025cc 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -981,7 +981,8 @@ void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj) reinterpret_cast(obj->synthdata.constData()); for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) { int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii; - propertyCache->property(index)->flags |= QDeclarativePropertyCache::Data::IsAlias; + QDeclarativePropertyCache::Data *data = propertyCache->property(index); + data->setFlags(data->getFlags() | QDeclarativePropertyCache::Data::IsAlias); } } @@ -1546,8 +1547,7 @@ bool QDeclarativeCompiler::buildProperty(QDeclarativeParser::Property *prop, output->types.at(prop->parent->type).component) { QDeclarativePropertyCache *cache = output->types.at(prop->parent->type).component->rootPropertyCache; - if (cache && cache->property(prop->index) && - cache->property(prop->index)->flags & QDeclarativePropertyCache::Data::IsAlias) + if (cache && cache->property(prop->index) && cache->property(prop->index)->isAlias()) prop->isAlias = true; } @@ -3138,7 +3138,7 @@ int QDeclarativeCompiler::indexOfSignal(QDeclarativeParser::Object *object, cons QDeclarativePropertyCache::Data *d = cache->property(strName); if (notInRevision) *notInRevision = false; - while (d && !(d->flags & QDeclarativePropertyCache::Data::IsFunction)) + while (d && !(d->isFunction())) d = cache->overrideData(d); if (d && !cache->isAllowedInRevision(d)) { @@ -3178,7 +3178,7 @@ int QDeclarativeCompiler::indexOfProperty(QDeclarativeParser::Object *object, co QDeclarativePropertyCache::Data *d = cache->property(strName); // Find the first property - while (d && d->flags & QDeclarativePropertyCache::Data::IsFunction) + while (d && d->isFunction()) d = cache->overrideData(d); if (d && !cache->isAllowedInRevision(d)) { diff --git a/src/declarative/qml/qdeclarativeenginedebug.cpp b/src/declarative/qml/qdeclarativeenginedebug.cpp index 7844d30..af99f05 100644 --- a/src/declarative/qml/qdeclarativeenginedebug.cpp +++ b/src/declarative/qml/qdeclarativeenginedebug.cpp @@ -678,7 +678,7 @@ void QDeclarativeEngineDebugServer::setMethodBody(int objectId, const QString &m QDeclarativePropertyCache::Data *prop = QDeclarativePropertyCache::property(context->engine(), object, method, dummy); - if (!prop || !(prop->flags & QDeclarativePropertyCache::Data::IsVMEFunction)) + if (!prop || !prop->isVMEFunction()) return; QMetaMethod metaMethod = object->metaObject()->method(prop->coreIndex); diff --git a/src/declarative/qml/qdeclarativelist.cpp b/src/declarative/qml/qdeclarativelist.cpp index ff3dfc9..458812a 100644 --- a/src/declarative/qml/qdeclarativelist.cpp +++ b/src/declarative/qml/qdeclarativelist.cpp @@ -139,7 +139,7 @@ QDeclarativeListReference::QDeclarativeListReference(QObject *object, const char QDeclarativePropertyCache::Data *data = QDeclarativePropertyCache::property(engine, object, QLatin1String(property), local); - if (!data || !(data->flags & QDeclarativePropertyCache::Data::IsQList)) return; + if (!data || !data->isQList()) return; QDeclarativeEnginePrivate *p = engine?QDeclarativeEnginePrivate::get(engine):0; diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp index dcab6be..088379e 100644 --- a/src/declarative/qml/qdeclarativeproperty.cpp +++ b/src/declarative/qml/qdeclarativeproperty.cpp @@ -255,7 +255,7 @@ void QDeclarativePropertyPrivate::initProperty(QObject *obj, const QString &name QDeclarativePropertyCache::property(engine, obj, pathName, local); if (!property) return; // Not a property - if (property->flags & QDeclarativePropertyCache::Data::IsFunction) + if (property->isFunction()) return; // Not an object property if (ii == (path.count() - 2) && QDeclarativeValueTypeFactory::isValueType(property->propType)) { @@ -277,7 +277,7 @@ void QDeclarativePropertyPrivate::initProperty(QObject *obj, const QString &name return; } else { - if (!(property->flags & QDeclarativePropertyCache::Data::IsQObjectDerived)) + if (!property->isQObject()) return; // Not an object property void *args[] = { ¤tObject, 0 }; @@ -311,7 +311,7 @@ void QDeclarativePropertyPrivate::initProperty(QObject *obj, const QString &name QDeclarativePropertyCache::Data local; QDeclarativePropertyCache::Data *property = QDeclarativePropertyCache::property(engine, currentObject, terminal, local); - if (property && !(property->flags & QDeclarativePropertyCache::Data::IsFunction)) { + if (property && !property->isFunction()) { object = currentObject; core = *property; nameCache = terminal; @@ -371,9 +371,9 @@ QDeclarativePropertyPrivate::propertyTypeCategory() const return QDeclarativeProperty::InvalidCategory; else if (QDeclarativeValueTypeFactory::isValueType((uint)type)) return QDeclarativeProperty::Normal; - else if (core.flags & QDeclarativePropertyCache::Data::IsQObjectDerived) + else if (core.isQObject()) return QDeclarativeProperty::Object; - else if (core.flags & QDeclarativePropertyCache::Data::IsQList) + else if (core.isQList()) return QDeclarativeProperty::List; else return QDeclarativeProperty::Normal; @@ -457,7 +457,7 @@ int QDeclarativePropertyPrivate::propertyType() const QDeclarativeProperty::Type QDeclarativePropertyPrivate::type() const { - if (core.flags & QDeclarativePropertyCache::Data::IsFunction) + if (core.isFunction()) return QDeclarativeProperty::SignalProperty; else if (core.isValid()) return QDeclarativeProperty::Property; @@ -520,12 +520,12 @@ bool QDeclarativeProperty::isWritable() const return false; if (!d->object) return false; - if (d->core.flags & QDeclarativePropertyCache::Data::IsQList) //list + if (d->core.isQList()) //list return true; - else if (d->core.flags & QDeclarativePropertyCache::Data::IsFunction) //signal handler + else if (d->core.isFunction()) //signal handler return false; - else if (d->core.isValid()) //normal property - return d->core.flags & QDeclarativePropertyCache::Data::IsWritable; + else if (d->core.isValid()) //normal property + return d->core.isWritable(); else return false; } @@ -551,7 +551,7 @@ bool QDeclarativeProperty::isResettable() const if (!d) return false; if (type() & Property && d->core.isValid() && d->object) - return d->core.flags & QDeclarativePropertyCache::Data::IsResettable; + return d->core.isResettable(); else return false; } @@ -682,7 +682,7 @@ QDeclarativePropertyPrivate::binding(QObject *object, int coreIndex, int valueTy QDeclarativePropertyCache::Data *propertyData = data->propertyCache?data->propertyCache->property(coreIndex):0; - if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) { + if (propertyData && propertyData->isAlias()) { const QDeclarativeVMEMetaObject *vme = static_cast(metaObjectForProperty(object->metaObject(), coreIndex)); @@ -723,7 +723,7 @@ void QDeclarativePropertyPrivate::findAliasTarget(QObject *object, int bindingIn if (data) { QDeclarativePropertyCache::Data *propertyData = data->propertyCache?data->propertyCache->property(coreIndex):0; - if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) { + if (propertyData && propertyData->isAlias()) { const QDeclarativeVMEMetaObject *vme = static_cast(metaObjectForProperty(object->metaObject(), coreIndex)); QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; @@ -757,7 +757,7 @@ QDeclarativePropertyPrivate::setBinding(QObject *object, int coreIndex, int valu if (data) { QDeclarativePropertyCache::Data *propertyData = data->propertyCache?data->propertyCache->property(coreIndex):0; - if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) { + if (propertyData && propertyData->isAlias()) { const QDeclarativeVMEMetaObject *vme = static_cast(metaObjectForProperty(object->metaObject(), coreIndex)); @@ -811,7 +811,7 @@ QDeclarativePropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, if (data) { QDeclarativePropertyCache::Data *propertyData = data->propertyCache?data->propertyCache->property(coreIndex):0; - if (propertyData && propertyData->flags & QDeclarativePropertyCache::Data::IsAlias) { + if (propertyData && propertyData->isAlias()) { const QDeclarativeVMEMetaObject *vme = static_cast(metaObjectForProperty(object->metaObject(), coreIndex)); @@ -994,14 +994,14 @@ QVariant QDeclarativePropertyPrivate::readValueProperty() if (!ep) delete valueType; return rv; - } else if (core.flags & QDeclarativePropertyCache::Data::IsQList) { + } else if (core.isQList()) { QDeclarativeListProperty prop; void *args[] = { &prop, 0 }; QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args); return QVariant::fromValue(QDeclarativeListReferencePrivate::init(prop, core.propType, engine)); - } else if (core.flags & QDeclarativePropertyCache::Data::IsQObjectDerived) { + } else if (core.isQObject()) { QObject *rv = 0; void *args[] = { &rv, 0 }; @@ -1077,7 +1077,7 @@ bool QDeclarativePropertyPrivate::writeValueProperty(const QVariant &value, Writ writeBack->read(object, core.coreIndex); QDeclarativePropertyCache::Data data = core; - data.flags = valueType.flags; + data.setFlags(valueType.flags); data.coreIndex = valueType.valueTypeCoreIdx; data.propType = valueType.valueTypePropType; rv = write(writeBack, data, value, context, flags); @@ -1101,7 +1101,7 @@ bool QDeclarativePropertyPrivate::write(QObject *object, const QDeclarativePrope int coreIdx = property.coreIndex; int status = -1; //for dbus - if (property.flags & QDeclarativePropertyCache::Data::IsEnumType) { + if (property.isEnum()) { QMetaProperty prop = object->metaObject()->property(property.coreIndex); QVariant v = value; // Enum values come through the script engine as doubles @@ -1153,7 +1153,7 @@ bool QDeclarativePropertyPrivate::write(QObject *object, const QDeclarativePrope void *a[] = { (void *)&value, 0, &status, &flags }; QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); - } else if (property.flags & QDeclarativePropertyCache::Data::IsQObjectDerived) { + } else if (property.isQObject()) { const QMetaObject *valMo = rawMetaObjectForType(enginePriv, value.userType()); @@ -1180,7 +1180,7 @@ bool QDeclarativePropertyPrivate::write(QObject *object, const QDeclarativePrope return false; } - } else if (property.flags & QDeclarativePropertyCache::Data::IsQList) { + } else if (property.isQList()) { const QMetaObject *listType = 0; if (enginePriv) { @@ -1703,7 +1703,7 @@ static inline void flush_vme_signal(const QObject *object, int index) if (data && data->propertyCache) { QDeclarativePropertyCache::Data *property = data->propertyCache->method(index); - if (property && property->flags & QDeclarativePropertyCache::Data::IsVMESignal) { + if (property && property->isVMESignal()) { const QMetaObject *metaObject = object->metaObject(); int methodOffset = metaObject->methodOffset(); diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp index 6a4cf4f..24dc15a 100644 --- a/src/declarative/qml/qdeclarativepropertycache.cpp +++ b/src/declarative/qml/qdeclarativepropertycache.cpp @@ -54,41 +54,78 @@ Q_DECLARE_METATYPE(QDeclarativeV8Handle); QT_BEGIN_NAMESPACE -QDeclarativePropertyCache::Data::Flags QDeclarativePropertyCache::Data::flagsForProperty(const QMetaProperty &p, QDeclarativeEngine *engine) +// 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) { - int propType = p.userType(); - - Flags flags; + QDeclarativePropertyCache::Data::Flags flags; if (p.isConstant()) - flags |= Data::IsConstant; + flags |= QDeclarativePropertyCache::Data::IsConstant; if (p.isWritable()) - flags |= Data::IsWritable; + flags |= QDeclarativePropertyCache::Data::IsWritable; if (p.isResettable()) - flags |= Data::IsResettable; + flags |= QDeclarativePropertyCache::Data::IsResettable; if (p.isFinal()) - flags |= Data::IsFinal; + flags |= QDeclarativePropertyCache::Data::IsFinal; + if (p.isEnumType()) + flags |= QDeclarativePropertyCache::Data::IsEnumType; + + return flags; +} - if (propType == qMetaTypeId()) { - flags |= Data::IsQmlBinding; +// 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) +{ + QDeclarativePropertyCache::Data::Flags flags; + + if (propType < QMetaType::User) { + } else if (propType == qMetaTypeId()) { + flags |= QDeclarativePropertyCache::Data::IsQmlBinding; } else if (propType == qMetaTypeId()) { - flags |= Data::IsQScriptValue; + flags |= QDeclarativePropertyCache::Data::IsQScriptValue; } else if (propType == qMetaTypeId()) { - flags |= Data::IsV8Handle; - } else if (p.isEnumType()) { - flags |= Data::IsEnumType; + flags |= QDeclarativePropertyCache::Data::IsV8Handle; } else { - QDeclarativeMetaType::TypeCategory cat = engine ? QDeclarativeEnginePrivate::get(engine)->typeCategory(propType) - : QDeclarativeMetaType::typeCategory(propType); + QDeclarativeMetaType::TypeCategory cat = + engine ? QDeclarativeEnginePrivate::get(engine)->typeCategory(propType) + : QDeclarativeMetaType::typeCategory(propType); + if (cat == QDeclarativeMetaType::Object) - flags |= Data::IsQObjectDerived; + flags |= QDeclarativePropertyCache::Data::IsQObjectDerived; else if (cat == QDeclarativeMetaType::List) - flags |= Data::IsQList; + flags |= QDeclarativePropertyCache::Data::IsQList; } return flags; } +QDeclarativePropertyCache::Data::Flags +QDeclarativePropertyCache::Data::flagsForProperty(const QMetaProperty &p, QDeclarativeEngine *engine) +{ + return fastFlagsForProperty(p) | flagsForPropertyType(p.userType(), engine); +} + +void QDeclarativePropertyCache::Data::lazyLoad(const QMetaProperty &p, QDeclarativeEngine *engine) +{ + Q_UNUSED(engine); + + coreIndex = p.propertyIndex(); + notifyIndex = p.notifySignalIndex(); + revision = p.revision(); + + flags = fastFlagsForProperty(p); + + int type = p.type(); + if (type == QVariant::UserType || type == -1) { + propTypeName = p.typeName(); + flags |= QDeclarativePropertyCache::Data::NotFullyResolved; + } else { + propType = type; + } +} + void QDeclarativePropertyCache::Data::load(const QMetaProperty &p, QDeclarativeEngine *engine) { propType = p.userType(); @@ -96,7 +133,7 @@ void QDeclarativePropertyCache::Data::load(const QMetaProperty &p, QDeclarativeE propType = qMetaTypeId(); coreIndex = p.propertyIndex(); notifyIndex = p.notifySignalIndex(); - flags = flagsForProperty(p, engine); + flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine); revision = p.revision(); } @@ -113,23 +150,54 @@ void QDeclarativePropertyCache::Data::load(const QMetaMethod &m) if (returnType) propType = QMetaType::type(returnType); - QList params = m.parameterTypes(); - if (!params.isEmpty()) { + const char *signature = m.signature(); + while (*signature != '(') { Q_ASSERT(*signature != 0); ++signature; } + + ++signature; + if (*signature != ')') { flags |= Data::HasArguments; - if (params.at(0).length() == 23 && - 0 == qstrcmp(params.at(0).constData(), "QDeclarativeV8Function*")) { + if (0 == ::strcmp(signature, "QDeclarativeV8Function*)")) { flags |= Data::IsV8Function; } } + revision = m.revision(); } +void QDeclarativePropertyCache::Data::lazyLoad(const QMetaMethod &m) +{ + coreIndex = m.methodIndex(); + relatedIndex = -1; + flags |= Data::IsFunction; + if (m.methodType() == QMetaMethod::Signal) + flags |= Data::IsSignal; + propType = QVariant::Invalid; + + const char *returnType = m.typeName(); + if (returnType && *returnType) { + propTypeName = returnType; + flags |= Data::NotFullyResolved; + } + + const char *signature = m.signature(); + while (*signature != '(') { Q_ASSERT(*signature != 0); ++signature; } + + ++signature; + if (*signature != ')') { + flags |= Data::HasArguments; + if (0 == ::strcmp(signature, "QDeclarativeV8Function*)")) { + flags |= Data::IsV8Function; + } + } + + revision = m.revision(); +} /*! Creates a new empty QDeclarativePropertyCache. */ QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e) -: QDeclarativeCleanup(e), engine(e) +: QDeclarativeCleanup(e), engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0) { Q_ASSERT(engine); } @@ -138,7 +206,7 @@ QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e) Creates a new QDeclarativePropertyCache of \a metaObject. */ QDeclarativePropertyCache::QDeclarativePropertyCache(QDeclarativeEngine *e, const QMetaObject *metaObject) -: QDeclarativeCleanup(e), engine(e) +: QDeclarativeCleanup(e), engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0) { Q_ASSERT(engine); Q_ASSERT(metaObject); @@ -153,22 +221,13 @@ QDeclarativePropertyCache::~QDeclarativePropertyCache() void QDeclarativePropertyCache::clear() { - for (int ii = 0; ii < indexCache.count(); ++ii) { - if (indexCache.at(ii)) indexCache.at(ii)->release(); - } - - for (int ii = 0; ii < methodIndexCache.count(); ++ii) { - RData *data = methodIndexCache.at(ii); - if (data) data->release(); - } + if (parent) parent->release(); + parent = 0; - for (StringCache::ConstIterator iter = stringCache.begin(); - iter != stringCache.end(); ++iter) { - RData *data = (*iter); - data->release(); - } + propertyIndexCacheStart = 0; + methodIndexCacheStart = 0; - indexCache.clear(); + propertyIndexCache.clear(); methodIndexCache.clear(); stringCache.clear(); qPersistentDispose(constructor); @@ -219,23 +278,16 @@ QDeclarativePropertyCache::Data QDeclarativePropertyCache::create(const QMetaObj return rv; } -QDeclarativePropertyCache *QDeclarativePropertyCache::copy() const +QDeclarativePropertyCache *QDeclarativePropertyCache::copy() { QDeclarativePropertyCache *cache = new QDeclarativePropertyCache(engine); - cache->indexCache = indexCache; - cache->methodIndexCache = methodIndexCache; + cache->parent = this; + cache->parent->addref(); + cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart; + cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart; cache->stringCache = stringCache; cache->allowedRevisionCache = allowedRevisionCache; - for (int ii = 0; ii < indexCache.count(); ++ii) { - if (indexCache.at(ii)) indexCache.at(ii)->addref(); - } - for (int ii = 0; ii < methodIndexCache.count(); ++ii) { - if (methodIndexCache.at(ii)) methodIndexCache.at(ii)->addref(); - } - for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) - (*iter)->addref(); - // We specifically do *NOT* copy the constructor return cache; @@ -259,65 +311,64 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb allowedRevisionCache.append(0); - QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine); int methodCount = metaObject->methodCount(); // 3 to block the destroyed signal and the deleteLater() slot int methodOffset = qMax(3, metaObject->methodOffset()); - methodIndexCache.resize(methodCount); + methodIndexCache.resize(methodCount - methodIndexCacheStart); for (int ii = methodOffset; ii < methodCount; ++ii) { 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); - methodName = methodName.left(parenIdx); + // 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); - RData *data = new RData; - methodIndexCache[ii] = data; + Data *data = &methodIndexCache[ii - methodIndexCacheStart]; - data->load(m); - if (m.methodType() == QMetaMethod::Slot || m.methodType() == QMetaMethod::Method) - data->flags |= methodFlags; - else if (m.methodType() == QMetaMethod::Signal) + data->lazyLoad(m); + if (data->isSignal()) data->flags |= signalFlags; + else + data->flags |= methodFlags; if (!dynamicMetaObject) data->flags |= Data::IsDirect; data->metaObjectOffset = allowedRevisionCache.count() - 1; - if (stringCache.contains(methodName)) { - RData *old = stringCache[methodName]; + 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; - stringCache[methodName]->release(); + if ((*old)->flags & Data::IsFunction && (*old)->coreIndex >= methodOffset) + data->relatedIndex = (*old)->coreIndex; + data->overrideIndexIsProperty = !bool((*old)->flags & Data::IsFunction); + data->overrideIndex = (*old)->coreIndex; } stringCache.insert(methodName, data); - data->addref(); } int propCount = metaObject->propertyCount(); int propOffset = metaObject->propertyOffset(); - indexCache.resize(propCount); + propertyIndexCache.resize(propCount - propertyIndexCacheStart); for (int ii = propOffset; ii < propCount; ++ii) { QMetaProperty p = metaObject->property(ii); if (!p.isScriptable()) continue; - QString propName = QString::fromUtf8(p.name()); + QString str = dynamicMetaObject?QString::fromUtf8(p.name()): + QString::fromLatin1(p.name()); + QHashedString propName(str); - RData *data = new RData; - indexCache[ii] = data; + Data *data = &propertyIndexCache[ii - propertyIndexCacheStart]; - data->load(p, engine); + data->lazyLoad(p, engine); data->flags |= propertyFlags; if (!dynamicMetaObject) @@ -325,18 +376,30 @@ void QDeclarativePropertyCache::append(QDeclarativeEngine *engine, const QMetaOb data->metaObjectOffset = allowedRevisionCache.count() - 1; - if (stringCache.contains(propName)) { - RData *old = stringCache[propName]; - data->overrideIndexIsProperty = !bool(old->flags & Data::IsFunction); - data->overrideIndex = old->coreIndex; - stringCache[propName]->release(); + if (Data **old = stringCache.value(propName)) { + data->overrideIndexIsProperty = !bool((*old)->flags & Data::IsFunction); + data->overrideIndex = (*old)->coreIndex; } stringCache.insert(propName, data); - data->addref(); } } +void QDeclarativePropertyCache::resolve(Data *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)) + data->flags |= flagsForPropertyType(data->propType, engine); + + data->flags &= ~Data::NotFullyResolved; +} + void QDeclarativePropertyCache::updateRecur(QDeclarativeEngine *engine, const QMetaObject *metaObject) { if (!metaObject) @@ -355,7 +418,7 @@ void QDeclarativePropertyCache::update(QDeclarativeEngine *engine, const QMetaOb clear(); // Optimization to prevent unnecessary reallocation of lists - indexCache.reserve(metaObject->propertyCount()); + propertyIndexCache.reserve(metaObject->propertyCount()); methodIndexCache.reserve(metaObject->methodCount()); updateRecur(engine,metaObject); @@ -364,25 +427,36 @@ void QDeclarativePropertyCache::update(QDeclarativeEngine *engine, const QMetaOb QDeclarativePropertyCache::Data * QDeclarativePropertyCache::property(int index) const { - if (index < 0 || index >= indexCache.count()) + if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count())) return 0; + + if (index < propertyIndexCacheStart) + return parent->property(index); - return indexCache.at(index); + Data *rv = const_cast(&propertyIndexCache.at(index - propertyIndexCacheStart)); + if (rv->notFullyResolved()) resolve(rv); + return rv; } QDeclarativePropertyCache::Data * QDeclarativePropertyCache::method(int index) const { - if (index < 0 || index >= methodIndexCache.count()) + if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count())) return 0; - return methodIndexCache.at(index); + if (index < methodIndexCacheStart) + return parent->method(index); + + Data *rv = const_cast(&methodIndexCache.at(index - methodIndexCacheStart)); + if (rv->notFullyResolved()) resolve(rv); + return rv; } QDeclarativePropertyCache::Data * QDeclarativePropertyCache::property(const QString &str) const { - QDeclarativePropertyCache::RData **rv = stringCache.value(str); + QDeclarativePropertyCache::Data **rv = stringCache.value(str); + if (rv && (*rv)->notFullyResolved()) resolve(*rv); return rv?*rv:0; } diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h index 69e810a..1787e6a 100644 --- a/src/declarative/qml/qdeclarativepropertycache_p.h +++ b/src/declarative/qml/qdeclarativepropertycache_p.h @@ -104,11 +104,18 @@ public: HasArguments = 0x00004000, // Function takes arguments IsSignal = 0x00008000, // Function is a signal IsVMESignal = 0x00010000, // Signal was added by QML - IsV8Function = 0x00020000 // Function takes QDeclarativeV8Function* args + IsV8Function = 0x00020000, // Function takes QDeclarativeV8Function* args + + // Internal QDeclarativePropertyCache flags + NotFullyResolved = 0x00040000 // True if the type data is to be lazily resolved }; Q_DECLARE_FLAGS(Flags, Flag) + Flags getFlags() const { return flags; } + void setFlags(Flags f) { flags = f; } + bool isValid() const { return coreIndex != -1; } + bool isConstant() const { return flags & IsConstant; } bool isWritable() const { return flags & IsWritable; } bool isResettable() const { return flags & IsResettable; } @@ -122,9 +129,16 @@ public: bool isQmlBinding() const { return flags & IsQmlBinding; } bool isQScriptValue() const { return flags & IsQScriptValue; } bool isV8Handle() const { return flags & IsV8Handle; } + 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 isV8Function() const { return flags & IsV8Function; } - Flags flags; - int propType; + union { + int propType; // When !NotFullyResolved + const char *propTypeName; // When NotFullyResolved + }; int coreIndex; union { int notifyIndex; // When !IsFunction @@ -140,6 +154,13 @@ public: void load(const QMetaMethod &); QString name(QObject *); QString name(const QMetaObject *); + + private: + void lazyLoad(const QMetaProperty &, QDeclarativeEngine *engine = 0); + void lazyLoad(const QMetaMethod &); + bool notFullyResolved() const { return flags & NotFullyResolved; } + friend class QDeclarativePropertyCache; + Flags flags; }; struct ValueTypeData { @@ -152,7 +173,7 @@ public: void update(QDeclarativeEngine *, const QMetaObject *); - QDeclarativePropertyCache *copy() const; + QDeclarativePropertyCache *copy(); void append(QDeclarativeEngine *, const QMetaObject *, Data::Flag propertyFlags = Data::NoFlags, Data::Flag methodFlags = Data::NoFlags, Data::Flag signalFlags = Data::NoFlags); void append(QDeclarativeEngine *, const QMetaObject *, int revision, Data::Flag propertyFlags = Data::NoFlags, @@ -184,18 +205,20 @@ private: // Implemented in v8/qv8qobjectwrapper.cpp v8::Local newQObject(QObject *, QV8Engine *); - // XXX is this worth it anymore? - struct RData : public Data, public QDeclarativeRefCount { - }; - - typedef QVector IndexCache; - typedef QStringHash StringCache; + typedef QVector IndexCache; + typedef QStringHash StringCache; typedef QVector AllowedRevisionCache; + void resolve(Data *) const; void updateRecur(QDeclarativeEngine *, const QMetaObject *); QDeclarativeEngine *engine; - IndexCache indexCache; + + QDeclarativePropertyCache *parent; + int propertyIndexCacheStart; + int methodIndexCacheStart; + + IndexCache propertyIndexCache; IndexCache methodIndexCache; StringCache stringCache; AllowedRevisionCache allowedRevisionCache; @@ -204,8 +227,8 @@ private: Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativePropertyCache::Data::Flags); QDeclarativePropertyCache::Data::Data() -: flags(0), propType(0), coreIndex(-1), notifyIndex(-1), overrideIndexIsProperty(false), overrideIndex(-1), - revision(0), metaObjectOffset(-1) +: propType(0), coreIndex(-1), notifyIndex(-1), overrideIndexIsProperty(false), overrideIndex(-1), + revision(0), metaObjectOffset(-1), flags(0) { } @@ -225,9 +248,9 @@ QDeclarativePropertyCache::overrideData(Data *data) const return 0; if (data->overrideIndexIsProperty) - return indexCache.at(data->overrideIndex); + return property(data->overrideIndex); else - return methodIndexCache.at(data->overrideIndex); + return method(data->overrideIndex); } QDeclarativePropertyCache::ValueTypeData::ValueTypeData() @@ -255,7 +278,8 @@ QDeclarativeEngine *QDeclarativePropertyCache::qmlEngine() const QDeclarativePropertyCache::Data *QDeclarativePropertyCache::property(const QHashedV8String &str) const { - QDeclarativePropertyCache::RData **rv = stringCache.value(str); + QDeclarativePropertyCache::Data **rv = stringCache.value(str); + if (rv && (*rv)->notFullyResolved()) resolve(*rv); return rv?*rv:0; } diff --git a/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp b/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp index 928fea4..9232292 100644 --- a/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp +++ b/src/declarative/qml/v4/qdeclarativev4irbuilder.cpp @@ -472,7 +472,7 @@ bool QDeclarativeV4IRBuilder::visit(AST::IdentifierExpression *ast) return false; } - if (data && !(data->flags & QDeclarativePropertyCache::Data::IsFunction)) { + if (data && !data->isFunction()) { IR::Type irType = irTypeFromVariantType(data->propType, m_engine, metaObject); _expr.code = _block->SYMBOL(irType, name, metaObject, data->coreIndex, IR::Name::ScopeStorage, line, column); found = true; @@ -493,7 +493,7 @@ bool QDeclarativeV4IRBuilder::visit(AST::IdentifierExpression *ast) return false; } - if (data && !(data->flags & QDeclarativePropertyCache::Data::IsFunction)) { + if (data && !data->isFunction()) { IR::Type irType = irTypeFromVariantType(data->propType, m_engine, metaObject); _expr.code = _block->SYMBOL(irType, name, metaObject, data->coreIndex, IR::Name::RootStorage, line, column); found = true; @@ -611,10 +611,10 @@ bool QDeclarativeV4IRBuilder::visit(AST::FieldMemberExpression *ast) QDeclarativePropertyCache *cache = m_engine->cache(attachedMeta); QDeclarativePropertyCache::Data *data = cache->property(name); - if (!data || data->flags & QDeclarativePropertyCache::Data::IsFunction) + if (!data || data->isFunction()) return false; // Don't support methods (or non-existing properties ;) - if(!(data->flags & QDeclarativePropertyCache::Data::IsFinal)) { + if(!data->isFinal()) { if (qmlVerboseCompiler()) qWarning() << "*** non-final attached property:" << (baseName->id + QLatin1String(".") + ast->name->asString()); @@ -633,7 +633,7 @@ bool QDeclarativeV4IRBuilder::visit(AST::FieldMemberExpression *ast) QDeclarativePropertyCache::Data *data = cache->property(name); - if (!data || data->flags & QDeclarativePropertyCache::Data::IsFunction) + if (!data || data->isFunction()) return false; // Don't support methods (or non-existing properties ;) if (data->revision != 0) { @@ -657,10 +657,10 @@ bool QDeclarativeV4IRBuilder::visit(AST::FieldMemberExpression *ast) QDeclarativePropertyCache::Data *data = cache->property(name); - if (!data || data->flags & QDeclarativePropertyCache::Data::IsFunction) + if (!data || data->isFunction()) return false; // Don't support methods (or non-existing properties ;) - if(!(data->flags & QDeclarativePropertyCache::Data::IsFinal)) { + if(!data->isFinal()) { if (qmlVerboseCompiler()) qWarning() << "*** non-final property access:" << (baseName->id + QLatin1String(".") + ast->name->asString()); diff --git a/src/declarative/qml/v8/qv8qobjectwrapper.cpp b/src/declarative/qml/v8/qv8qobjectwrapper.cpp index 7e5bd4e..e59df8d 100644 --- a/src/declarative/qml/v8/qv8qobjectwrapper.cpp +++ b/src/declarative/qml/v8/qv8qobjectwrapper.cpp @@ -436,9 +436,9 @@ v8::Handle QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject typedef QDeclarativeEnginePrivate::CapturedProperty CapturedProperty; if (result->isFunction()) { - if (result->flags & QDeclarativePropertyCache::Data::IsVMEFunction) { + if (result->isVMEFunction()) { return ((QDeclarativeVMEMetaObject *)(object->metaObject()))->vmeMethod(result->coreIndex); - } else if (result->flags & QDeclarativePropertyCache::Data::IsV8Function) { + } else if (result->isV8Function()) { return MethodClosure::createWithGlobal(engine, object, objectHandle, result->coreIndex); } else { return MethodClosure::create(engine, object, objectHandle, result->coreIndex); @@ -1558,7 +1558,7 @@ static const QDeclarativePropertyCache::Data * RelatedMethod(QObject *object, static v8::Handle CallPrecise(QObject *object, const QDeclarativePropertyCache::Data &data, QV8Engine *engine, CallArgs &callArgs) { - if (data.flags & QDeclarativePropertyCache::Data::HasArguments) { + if (data.hasArguments()) { QMetaMethod m = object->metaObject()->method(data.coreIndex); QList argTypeNames = m.parameterTypes(); @@ -1620,7 +1620,7 @@ static v8::Handle CallOverloaded(QObject *object, const QDeclarativeP do { QList methodArgTypeNames; - if (attempt->flags & QDeclarativePropertyCache::Data::HasArguments) + if (attempt->hasArguments()) methodArgTypeNames = object->metaObject()->method(attempt->coreIndex).parameterTypes(); int methodArgumentCount = methodArgTypeNames.count(); @@ -1780,7 +1780,7 @@ v8::Handle QV8QObjectWrapper::Invoke(const v8::Arguments &args) return v8::Undefined(); } - if (method.flags & QDeclarativePropertyCache::Data::IsV8Function) { + if (method.isV8Function()) { v8::Handle rv; v8::Handle qmlglobal = args[2]->ToObject(); diff --git a/src/declarative/qml/v8/qv8valuetypewrapper.cpp b/src/declarative/qml/v8/qv8valuetypewrapper.cpp index f4f79ce..f3100cf 100644 --- a/src/declarative/qml/v8/qv8valuetypewrapper.cpp +++ b/src/declarative/qml/v8/qv8valuetypewrapper.cpp @@ -231,7 +231,7 @@ v8::Handle QV8ValueTypeWrapper::Setter(v8::Local property v8::Handle function = v8::Handle::Cast(value); QDeclarativePropertyCache::Data cacheData; - cacheData.flags = QDeclarativePropertyCache::Data::IsWritable; + cacheData.setFlags(QDeclarativePropertyCache::Data::IsWritable); cacheData.propType = reference->object->metaObject()->property(reference->property).userType(); cacheData.coreIndex = reference->property;