Optimize QDeclarativePropertyCache
authorAaron Kennedy <aaron.kennedy@nokia.com>
Mon, 4 Jul 2011 02:41:21 +0000 (12:41 +1000)
committerQt by Nokia <qt-info@nokia.com>
Mon, 4 Jul 2011 05:27:11 +0000 (07:27 +0200)
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 <aaron.kennedy@nokia.com>
src/declarative/qml/qdeclarativecompiler.cpp
src/declarative/qml/qdeclarativeenginedebug.cpp
src/declarative/qml/qdeclarativelist.cpp
src/declarative/qml/qdeclarativeproperty.cpp
src/declarative/qml/qdeclarativepropertycache.cpp
src/declarative/qml/qdeclarativepropertycache_p.h
src/declarative/qml/v4/qdeclarativev4irbuilder.cpp
src/declarative/qml/v8/qv8qobjectwrapper.cpp
src/declarative/qml/v8/qv8valuetypewrapper.cpp

index bca9c65..32025cc 100644 (file)
@@ -981,7 +981,8 @@ void QDeclarativeCompiler::genObject(QDeclarativeParser::Object *obj)
                 reinterpret_cast<const QDeclarativeVMEMetaData *>(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)) {
index 7844d30..af99f05 100644 (file)
@@ -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);
index ff3dfc9..458812a 100644 (file)
@@ -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;
 
index dcab6be..088379e 100644 (file)
@@ -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[] = { &currentObject, 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<const QDeclarativeVMEMetaObject *>(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<const QDeclarativeVMEMetaObject *>(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<const QDeclarativeVMEMetaObject *>(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<const QDeclarativeVMEMetaObject *>(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<QObject> 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();
 
index 6a4cf4f..24dc15a 100644 (file)
@@ -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<QDeclarativeBinding *>()) {
-        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<QDeclarativeBinding *>()) {
+        flags |= QDeclarativePropertyCache::Data::IsQmlBinding;
     } else if (propType == qMetaTypeId<QScriptValue>()) {
-        flags |= Data::IsQScriptValue;
+        flags |= QDeclarativePropertyCache::Data::IsQScriptValue;
     } else if (propType == qMetaTypeId<QDeclarativeV8Handle>()) {
-        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<QVariant>();
     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<QByteArray> 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<QVariant>();
+
+
+    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<Data *>(&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<Data *>(&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;
 }
 
index 69e810a..1787e6a 100644 (file)
@@ -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<v8::Object> newQObject(QObject *, QV8Engine *);
 
-    // XXX is this worth it anymore?
-    struct RData : public Data, public QDeclarativeRefCount { 
-    };
-
-    typedef QVector<RData *> IndexCache;
-    typedef QStringHash<RData *> StringCache;
+    typedef QVector<Data> IndexCache;
+    typedef QStringHash<Data *> StringCache;
     typedef QVector<int> 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;
 }
 
index 928fea4..9232292 100644 (file)
@@ -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());
index 7e5bd4e..e59df8d 100644 (file)
@@ -436,9 +436,9 @@ v8::Handle<v8::Value> 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<v8::Value> 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<QByteArray> argTypeNames = m.parameterTypes();
@@ -1620,7 +1620,7 @@ static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QDeclarativeP
     do {
         QList<QByteArray> 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<v8::Value> QV8QObjectWrapper::Invoke(const v8::Arguments &args)
             return v8::Undefined();
     }
 
-    if (method.flags & QDeclarativePropertyCache::Data::IsV8Function) {
+    if (method.isV8Function()) {
         v8::Handle<v8::Value> rv;
         v8::Handle<v8::Object> qmlglobal = args[2]->ToObject();
 
index f4f79ce..f3100cf 100644 (file)
@@ -231,7 +231,7 @@ v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Local<v8::String> property
             v8::Handle<v8::Function> function = v8::Handle<v8::Function>::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;