diff options
-rw-r--r-- | src/declarative/qml/ftw/ftw.pri | 5 | ||||
-rw-r--r-- | src/declarative/qml/ftw/qfastmetabuilder.cpp | 371 | ||||
-rw-r--r-- | src/declarative/qml/ftw/qfastmetabuilder_p.h | 194 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativecompiler.cpp | 444 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativecompiler_p.h | 5 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeparser.cpp | 24 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativeparser_p.h | 20 | ||||
-rw-r--r-- | src/declarative/qml/qdeclarativevme.cpp | 5 |
8 files changed, 914 insertions, 154 deletions
diff --git a/src/declarative/qml/ftw/ftw.pri b/src/declarative/qml/ftw/ftw.pri index 190296a93e..7e88598728 100644 --- a/src/declarative/qml/ftw/ftw.pri +++ b/src/declarative/qml/ftw/ftw.pri @@ -9,7 +9,8 @@ HEADERS += \ $$PWD/qdeclarativerefcount_p.h \ $$PWD/qdeclarativepool_p.h \ $$PWD/qfieldlist_p.h \ - $$PWD/qdeclarativeutils_p.h + $$PWD/qdeclarativeutils_p.h \ + $$PWD/qfastmetabuilder_p.h \ SOURCES += \ $$PWD/qintrusivelist.cpp \ @@ -17,3 +18,5 @@ SOURCES += \ $$PWD/qhashedstring.cpp \ $$PWD/qdeclarativerefcount.cpp \ $$PWD/qdeclarativepool.cpp \ + $$PWD/qfastmetabuilder.cpp \ + diff --git a/src/declarative/qml/ftw/qfastmetabuilder.cpp b/src/declarative/qml/ftw/qfastmetabuilder.cpp new file mode 100644 index 0000000000..20c5e08499 --- /dev/null +++ b/src/declarative/qml/ftw/qfastmetabuilder.cpp @@ -0,0 +1,371 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfastmetabuilder_p.h" + +QT_BEGIN_NAMESPACE + +struct QFastMetaBuilderHeader +{ + int fieldCount; +}; + +struct QMetaObjectPrivate +{ + int revision; + int className; + int classInfoCount, classInfoData; + int methodCount, methodData; + int propertyCount, propertyData; + int enumeratorCount, enumeratorData; + int constructorCount, constructorData; //since revision 2 + int flags; //since revision 3 + int signalCount; //since revision 4 +}; + +enum MetaObjectFlag { + DynamicMetaObject = 0x01 +}; + +enum PropertyFlags { + Invalid = 0x00000000, + Readable = 0x00000001, + Writable = 0x00000002, + Resettable = 0x00000004, + EnumOrFlag = 0x00000008, + StdCppSet = 0x00000100, +// Override = 0x00000200, + Constant = 0x00000400, + Final = 0x00000800, + Designable = 0x00001000, + ResolveDesignable = 0x00002000, + Scriptable = 0x00004000, + ResolveScriptable = 0x00008000, + Stored = 0x00010000, + ResolveStored = 0x00020000, + Editable = 0x00040000, + ResolveEditable = 0x00080000, + User = 0x00100000, + ResolveUser = 0x00200000, + Notify = 0x00400000, + Revisioned = 0x00800000 +}; + +enum MethodFlags { + AccessPrivate = 0x00, + AccessProtected = 0x01, + AccessPublic = 0x02, + AccessMask = 0x03, //mask + + MethodMethod = 0x00, + MethodSignal = 0x04, + MethodSlot = 0x08, + MethodConstructor = 0x0c, + MethodTypeMask = 0x0c, + + MethodCompatibility = 0x10, + MethodCloned = 0x20, + MethodScriptable = 0x40, + MethodRevisioned = 0x80 +}; + +#define FMBHEADER_FIELD_COUNT 1 + +#define HEADER_FIELD_COUNT 14 +#define CLASSINFO_FIELD_COUNT 2 +#define METHOD_FIELD_COUNT 5 +#define PROPERTY_FIELD_COUNT 3 +#define PROPERTY_NOTIFY_FIELD_COUNT 1 + +static inline uint *fieldPointer(QByteArray &data) +{ return reinterpret_cast<uint *>(data.data()) + FMBHEADER_FIELD_COUNT; } + +static inline const uint *fieldPointer(const QByteArray &data) +{ return reinterpret_cast<const uint *>(data.constData()) + FMBHEADER_FIELD_COUNT; } + +static inline QMetaObjectPrivate *priv(QByteArray &data) +{ return reinterpret_cast<QMetaObjectPrivate*>(fieldPointer(data)); } + +static inline const QMetaObjectPrivate *priv(const QByteArray &data) +{ return reinterpret_cast<const QMetaObjectPrivate*>(fieldPointer(data)); } + +static inline QFastMetaBuilderHeader *header(QByteArray &data) +{ return reinterpret_cast<QFastMetaBuilderHeader*>(data.data()); } + +static inline const QFastMetaBuilderHeader *header(const QByteArray &data) +{ return reinterpret_cast<const QFastMetaBuilderHeader*>(data.constData()); } + +QFastMetaBuilder::QFastMetaBuilder() +: m_zeroPtr(0), m_stringData(0), m_stringDataLength(0), m_stringDataAllocated(0) +{ +} + +QFastMetaBuilder::~QFastMetaBuilder() +{ +} + +QFastMetaBuilder::StringRef QFastMetaBuilder::init(int classNameLength, + int propertyCount, int methodCount, + int signalCount, int classInfoCount) +{ + Q_ASSERT(m_data.isEmpty()); + Q_ASSERT(classNameLength > 0); + Q_ASSERT(propertyCount >= 0); + Q_ASSERT(methodCount >= 0); + Q_ASSERT(signalCount >= 0); + Q_ASSERT(classInfoCount >= 0); + + int fieldCount = FMBHEADER_FIELD_COUNT + + HEADER_FIELD_COUNT + + propertyCount * (PROPERTY_FIELD_COUNT + PROPERTY_NOTIFY_FIELD_COUNT) + + methodCount * (METHOD_FIELD_COUNT) + + signalCount * (METHOD_FIELD_COUNT) + + classInfoCount * CLASSINFO_FIELD_COUNT; + + m_data.resize(fieldCount * sizeof(uint) + classNameLength + 1); + m_stringData = m_data.data() + m_data.size() - classNameLength - 1; + m_stringDataLength = classNameLength + 1; + m_stringDataAllocated = classNameLength + 1; + m_stringData[classNameLength] = 0; + m_zeroPtr = classNameLength; + + header(m_data)->fieldCount = fieldCount; + + QMetaObjectPrivate *p = priv(m_data); + + int dataIndex = HEADER_FIELD_COUNT; + + p->revision = 4; + p->className = 0; + + // Class infos + p->classInfoCount = classInfoCount; + if (p->classInfoCount) { + p->classInfoData = dataIndex; + dataIndex += p->classInfoCount * CLASSINFO_FIELD_COUNT; + } else { + p->classInfoData = 0; + } + + // Methods + p->methodCount = methodCount + signalCount; + if (p->methodCount) { + p->methodData = dataIndex; + dataIndex += p->methodCount * METHOD_FIELD_COUNT; + } else { + p->methodData = 0; + } + p->signalCount = signalCount; + + // Properties + p->propertyCount = propertyCount; + if (p->propertyCount) { + p->propertyData = dataIndex; + dataIndex += p->propertyCount * (PROPERTY_FIELD_COUNT + PROPERTY_NOTIFY_FIELD_COUNT); + } else { + p->propertyData = 0; + } + + // Flags + p->flags = DynamicMetaObject; // Always dynamic + + // Enums and constructors not supported + p->enumeratorCount = 0; + p->enumeratorData = 0; + p->constructorCount = 0; + p->constructorData = 0; + + StringRef className; + className._b = this; + className._o = 0; + className._l = classNameLength; + return className; +} + +// Allocate a string of \a length. \a length should *not* include the null terminator. +QFastMetaBuilder::StringRef QFastMetaBuilder::newString(int length) +{ + Q_ASSERT(length > 0); + + StringRef sr; + sr._b = this; + sr._o = m_stringDataLength; + sr._l = length; + + m_stringDataLength += length + 1 /* for null terminator */; + + return sr; +} + +void QFastMetaBuilder::setClassInfo(int index, const StringRef &key, const StringRef &value) +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(!key.isEmpty() && !value.isEmpty()); + + QMetaObjectPrivate *p = priv(m_data); + Q_ASSERT(index < p->classInfoCount); + + uint *ptr = fieldPointer(m_data) + p->classInfoData + index * CLASSINFO_FIELD_COUNT; + // classinfo: key, value + ptr[0] = key.offset(); ptr[1] = value.offset(); +} + +void QFastMetaBuilder::setProperty(int index, const StringRef &name, const StringRef &type, + QMetaType::Type mtype, PropertyFlag flags, int notifySignal) +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(!name.isEmpty() && !type.isEmpty()); + + QMetaObjectPrivate *p = priv(m_data); + Q_ASSERT(index < p->propertyCount); + + uint qtType = mtype; + if ((int)qtType == qMetaTypeId<QVariant>()) + qtType = 0xFF; // Special handling for QVariant + + uint *ptr = fieldPointer(m_data) + p->propertyData + index * PROPERTY_FIELD_COUNT; + // properties: name, type, flags + ptr[0] = name.offset(); + ptr[1] = type.offset(); + if (notifySignal == -1) { + ptr[2] = qtType << 24; + ptr[2] |= flags | Scriptable | Readable; + *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = 0; + } else { + ptr[2] = qtType << 24; + ptr[2] |= flags | Scriptable | Readable | Notify; + *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = notifySignal; + } +} + +void QFastMetaBuilder::setProperty(int index, const StringRef &name, const StringRef &type, + QFastMetaBuilder::PropertyFlag flags, int notifySignal) +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(!name.isEmpty() && !type.isEmpty()); + + QMetaObjectPrivate *p = priv(m_data); + Q_ASSERT(index < p->propertyCount); + + uint *ptr = fieldPointer(m_data) + p->propertyData + index * PROPERTY_FIELD_COUNT; + // properties: name, type, flags + ptr[0] = name.offset(); + ptr[1] = type.offset(); + if (notifySignal == -1) { + ptr[2] = flags | Scriptable | Readable; + *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = 0; + } else { + ptr[2] = flags | Scriptable | Readable | Notify; + *(fieldPointer(m_data) + p->propertyData + p->propertyCount * PROPERTY_FIELD_COUNT + index) = notifySignal; + } +} + +void QFastMetaBuilder::setSignal(int index, const StringRef &signature, + const StringRef ¶meterNames, + const StringRef &type) +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(!signature.isEmpty()); + + QMetaObjectPrivate *p = priv(m_data); + int mindex = metaObjectIndexForSignal(index); + + uint *ptr = fieldPointer(m_data) + p->methodData + mindex * METHOD_FIELD_COUNT; + // methods: signature, parameters, type, tag, flags + ptr[0] = signature.offset(); + ptr[1] = parameterNames.isEmpty()?m_zeroPtr:parameterNames.offset(); + ptr[2] = type.isEmpty()?m_zeroPtr:type.offset(); + ptr[3] = m_zeroPtr; + ptr[4] = AccessProtected | MethodSignal; +} + +void QFastMetaBuilder::setMethod(int index, const StringRef &signature, + const StringRef ¶meterNames, + const StringRef &type) +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(!signature.isEmpty()); + + QMetaObjectPrivate *p = priv(m_data); + int mindex = metaObjectIndexForMethod(index); + + uint *ptr = fieldPointer(m_data) + p->methodData + mindex * METHOD_FIELD_COUNT; + // methods: signature, parameters, type, tag, flags + ptr[0] = signature.offset(); + ptr[1] = parameterNames.isEmpty()?m_zeroPtr:parameterNames.offset(); + ptr[2] = type.isEmpty()?m_zeroPtr:type.offset(); + ptr[3] = m_zeroPtr; + ptr[4] = AccessProtected | MethodSlot; +} + +int QFastMetaBuilder::metaObjectIndexForSignal(int index) const +{ + Q_ASSERT(!m_data.isEmpty()); + Q_ASSERT(index < priv(m_data)->signalCount); + return index; +} + +int QFastMetaBuilder::metaObjectIndexForMethod(int index) const +{ + Q_ASSERT(!m_data.isEmpty()); + + const QMetaObjectPrivate *p = priv(m_data); + Q_ASSERT(index < (p->methodCount - p->signalCount)); + return index + p->signalCount; +} + +void QFastMetaBuilder::allocateStringData() +{ + if (m_stringDataAllocated < m_stringDataLength) { + m_data.resize(m_data.size() + m_stringDataLength - m_stringDataAllocated); + m_stringDataAllocated = m_stringDataLength; + m_stringData = m_data.data() + header(m_data)->fieldCount * sizeof(uint); + } +} + +void QFastMetaBuilder::fromData(QMetaObject *output, const QMetaObject *parent, const QByteArray &data) +{ + output->d.superdata = parent; + output->d.stringdata = data.constData() + header(data)->fieldCount * sizeof(uint); + output->d.data = fieldPointer(data); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/ftw/qfastmetabuilder_p.h b/src/declarative/qml/ftw/qfastmetabuilder_p.h new file mode 100644 index 0000000000..c0cb0fc2fb --- /dev/null +++ b/src/declarative/qml/ftw/qfastmetabuilder_p.h @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFASTMETABUILDER_P_H +#define QFASTMETABUILDER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of moc. This header file may change from version to version without notice, +// or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> +#include <QtCore/qmetatype.h> + +QT_BEGIN_NAMESPACE + +class QFastMetaBuilder +{ +public: + QFastMetaBuilder(); + ~QFastMetaBuilder(); + + struct StringRef { + public: + inline StringRef(); + inline StringRef(const StringRef &); + inline StringRef &operator=(const StringRef &); + + inline void load(const QByteArray &); + inline void load(const char *); + + inline bool isEmpty() const; + inline QFastMetaBuilder *builder() const; + inline int offset() const; + inline char *data(); + inline int length() const; + private: + friend class QFastMetaBuilder; + + QFastMetaBuilder *_b; + int _o; + int _l; + }; + StringRef newString(int length); + + // Returns class name + StringRef init(int classNameLength, + int propertyCount, int methodCount, + int signalCount, int classInfoCount); + + void setClassInfo(int index, const StringRef &key, const StringRef &value); + + enum PropertyFlag { + None = 0x00000000, + Writable = 0x00000002, + Resettable = 0x00000004, + Constant = 0x00000400, + Final = 0x00000800 + }; + // void setProperty(int index, const StringRef &name, QMetaType::Type type, int notifySignal = -1); + void setProperty(int index, const StringRef &name, const StringRef &type, + QMetaType::Type mtype, PropertyFlag flags, int notifySignal = -1); + void setProperty(int index, const StringRef &name, const StringRef &type, + PropertyFlag flags, int notifySignal = -1); + void setMethod(int index, const StringRef &signature, + const StringRef ¶meterNames = StringRef(), + const StringRef &type = StringRef()); + void setSignal(int index, const StringRef &signature, + const StringRef ¶meterNames = StringRef(), + const StringRef &type = StringRef()); + + int metaObjectIndexForSignal(int) const; + int metaObjectIndexForMethod(int) const; + + QByteArray toData() const { return m_data; } + static void fromData(QMetaObject *, const QMetaObject *parent, const QByteArray &); +private: + friend class StringRef; + + QByteArray m_data; + int m_zeroPtr; + + void allocateStringData(); + char *m_stringData; + int m_stringDataLength; + int m_stringDataAllocated; +}; + +QFastMetaBuilder::StringRef::StringRef() +: _b(0), _o(0), _l(0) +{ +} + +QFastMetaBuilder::StringRef::StringRef(const StringRef &o) +: _b(o._b), _o(o._o), _l(o._l) +{ +} + +QFastMetaBuilder::StringRef &QFastMetaBuilder::StringRef::operator=(const StringRef &o) +{ + _b = o._b; + _o = o._o; + _l = o._l; + return *this; +} + +bool QFastMetaBuilder::StringRef::isEmpty() const +{ + return _l == 0; +} + +QFastMetaBuilder *QFastMetaBuilder::StringRef::builder() const +{ + return _b; +} + +int QFastMetaBuilder::StringRef::offset() const +{ + return _o; +} + +char *QFastMetaBuilder::StringRef::data() +{ + Q_ASSERT(_b); + if (_b->m_stringDataLength != _b->m_stringDataAllocated) + _b->allocateStringData(); + return _b->m_stringData + _o; +} + +int QFastMetaBuilder::StringRef::length() const +{ + return _l; +} + +void QFastMetaBuilder::StringRef::load(const QByteArray &str) +{ + Q_ASSERT(str.length() == _l); + strcpy(data(), str.constData()); +} + +void QFastMetaBuilder::StringRef::load(const char *str) +{ + Q_ASSERT(strlen(str) == _l); + strcpy(data(), str); +} + +QT_END_NAMESPACE + +#endif // QFASTMETABUILDER_P_H + diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index 984e2c8b51..95d1ffbbb4 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -46,6 +46,7 @@ #include "qdeclarativepropertyvaluesource.h" #include "qdeclarativecomponent.h" #include "private/qmetaobjectbuilder_p.h" +#include "private/qfastmetabuilder_p.h" #include "private/qdeclarativestringconverters_p.h" #include "private/qdeclarativeengine_p.h" #include "qdeclarativeengine.h" @@ -2489,53 +2490,114 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn obj->dynamicSlots.isEmpty()) return true; - QByteArray dynamicData(sizeof(QDeclarativeVMEMetaData), (char)0); + bool resolveAlias = (mode == ResolveAliases); + + const Object::DynamicProperty *defaultProperty = 0; + int aliasCount = 0; + + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + + if (p.type == Object::DynamicProperty::Alias) + aliasCount++; + + if (p.isDefaultProperty && + (resolveAlias || p.type != Object::DynamicProperty::Alias)) + defaultProperty = &p; + + if (!resolveAlias) { + // No point doing this for both the alias and non alias cases + QString name = QString::fromUtf8(p.name); + QDeclarativePropertyCache::Data *d = property(obj, QStringRef(&name)); + if (d && d->isFinal()) + COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property")); + } + } + + bool buildData = resolveAlias || aliasCount == 0; + + QByteArray dynamicData; + if (buildData) { + typedef QDeclarativeVMEMetaData VMD; + + dynamicData = QByteArray(sizeof(QDeclarativeVMEMetaData) + + (obj->dynamicProperties.count() - aliasCount) * sizeof(VMD::PropertyData) + + obj->dynamicSlots.count() * sizeof(VMD::MethodData) + + aliasCount * sizeof(VMD::AliasData), 0); + } + + int uniqueClassId = classIndexCounter()->fetchAndAddRelaxed(1); QByteArray newClassName = obj->metatype->className(); newClassName.append("_QML_"); - int idx = classIndexCounter()->fetchAndAddRelaxed(1); - newClassName.append(QByteArray::number(idx)); + newClassName.append(QByteArray::number(uniqueClassId)); + if (compileState->root == obj && !compileState->nested) { QString path = output->url.path(); int lastSlash = path.lastIndexOf(QLatin1Char('/')); if (lastSlash > -1) { QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5); if (!nameBase.isEmpty() && QDeclarativeUtils::isUpper(nameBase.at(0))) - newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(idx); + newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId); } } - QMetaObjectBuilder builder; - builder.setClassName(newClassName); - builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); - - bool hasAlias = false; - for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { - const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + QFastMetaBuilder builder; + QFastMetaBuilder::StringRef classNameRef = builder.init(newClassName.length(), + obj->dynamicProperties.count() - (resolveAlias?0:aliasCount), + obj->dynamicSlots.count(), + obj->dynamicSignals.count() + obj->dynamicProperties.count(), + defaultProperty?1:0); + + struct TypeData { + Object::DynamicProperty::Type dtype; + int metaType; + const char *cppType; + } builtinTypes[] = { + { Object::DynamicProperty::Variant, 0, "QVariant" }, + { Object::DynamicProperty::Int, QMetaType::Int, "int" }, + { Object::DynamicProperty::Bool, QMetaType::Bool, "bool" }, + { Object::DynamicProperty::Real, QMetaType::Double, "double" }, + { Object::DynamicProperty::String, QMetaType::QString, "QString" }, + { Object::DynamicProperty::Url, QMetaType::QUrl, "QUrl" }, + { Object::DynamicProperty::Color, QMetaType::QColor, "QColor" }, + { Object::DynamicProperty::Time, QMetaType::QTime, "QTime" }, + { Object::DynamicProperty::Date, QMetaType::QDate, "QDate" }, + { Object::DynamicProperty::DateTime, QMetaType::QDateTime, "QDateTime" }, + }; + static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData); + QFastMetaBuilder::StringRef typeRefs[builtinTypeCount]; + + // Reserve dynamic properties + if (obj->dynamicProperties.count()) { + typedef QDeclarativeVMEMetaData VMD; + + int effectivePropertyIndex = 0; + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + Object::DynamicProperty &p = obj->dynamicProperties[ii]; + + // Reserve space for name + p.nameRef = builder.newString(p.name.length()); + + int propertyType = 0; + bool readonly = false; + QFastMetaBuilder::StringRef typeRef; + + if (p.type == Object::DynamicProperty::Alias) { + continue; + } else if (p.type < builtinTypeCount) { + Q_ASSERT(builtinTypes[p.type].dtype == p.type); + propertyType = builtinTypes[p.type].metaType; + if (typeRefs[p.type].isEmpty()) + typeRefs[p.type] = builder.newString(strlen(builtinTypes[p.type].cppType)); + typeRef = typeRefs[p.type]; + if (p.type == Object::DynamicProperty::Variant) + propertyType = qMetaTypeId<QVariant>(); - int propIdx = obj->metaObject()->indexOfProperty(p.name.constData()); - if (-1 != propIdx) { - QMetaProperty prop = obj->metaObject()->property(propIdx); - if (prop.isFinal()) - COMPILE_EXCEPTION(&p, tr("Cannot override FINAL property")); - } + } else { + Q_ASSERT(p.type == Object::DynamicProperty::CustomList || + p.type == Object::DynamicProperty::Custom); - if (p.isDefaultProperty && - (p.type != Object::DynamicProperty::Alias || - mode == ResolveAliases)) - builder.addClassInfo("DefaultProperty", p.name); - - QByteArray type; - int propertyType = 0; - bool readonly = false; - switch(p.type) { - case Object::DynamicProperty::Alias: - hasAlias = true; - continue; - break; - case Object::DynamicProperty::CustomList: - case Object::DynamicProperty::Custom: - { QByteArray customTypeName; QDeclarativeType *qmltype = 0; QString url; @@ -2556,144 +2618,216 @@ bool QDeclarativeCompiler::buildDynamicMeta(QDeclarativeParser::Object *obj, Dyn } if (p.type == Object::DynamicProperty::Custom) { - type = customTypeName + '*'; + customTypeName += '*'; propertyType = QMetaType::QObjectStar; } else { readonly = true; - type = "QDeclarativeListProperty<"; - type.append(customTypeName); - type.append(">"); + customTypeName = QByteArray("QDeclarativeListProperty<") + customTypeName + QByteArray(">"); propertyType = qMetaTypeId<QDeclarativeListProperty<QObject> >(); } + + p.resolvedCustomTypeName = customTypeName; + p.typeRef = builder.newString(customTypeName.length()); + typeRef = p.typeRef; } - break; - case Object::DynamicProperty::Variant: - propertyType = -1; - type = "QVariant"; - break; - case Object::DynamicProperty::Int: - propertyType = QVariant::Int; - type = "int"; - break; - case Object::DynamicProperty::Bool: - propertyType = QVariant::Bool; - type = "bool"; - break; - case Object::DynamicProperty::Real: - propertyType = QVariant::Double; - type = "double"; - break; - case Object::DynamicProperty::String: - propertyType = QVariant::String; - type = "QString"; - break; - case Object::DynamicProperty::Url: - propertyType = QVariant::Url; - type = "QUrl"; - break; - case Object::DynamicProperty::Color: - propertyType = QVariant::Color; - type = "QColor"; - break; - case Object::DynamicProperty::Time: - propertyType = QVariant::Time; - type = "QTime"; - break; - case Object::DynamicProperty::Date: - propertyType = QVariant::Date; - type = "QDate"; - break; - case Object::DynamicProperty::DateTime: - propertyType = QVariant::DateTime; - type = "QDateTime"; - break; - } - ((QDeclarativeVMEMetaData *)dynamicData.data())->propertyCount++; - QDeclarativeVMEMetaData::PropertyData propertyData = { propertyType }; - dynamicData.append((char *)&propertyData, sizeof(propertyData)); + if (buildData) { + VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data(); + vmd->propertyCount++; + (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType; + } - builder.addSignal(p.name + "Changed()"); - QMetaPropertyBuilder propBuilder = - builder.addProperty(p.name, type, builder.methodCount() - 1); - propBuilder.setWritable(!readonly); - } + if (p.type < builtinTypeCount) + builder.setProperty(effectivePropertyIndex, p.nameRef, typeRef, (QMetaType::Type)propertyType, + readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, + effectivePropertyIndex); + else + builder.setProperty(effectivePropertyIndex, p.nameRef, typeRef, + readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, + effectivePropertyIndex); - for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { - const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + p.changedSignatureRef = builder.newString(p.name.length() + strlen("Changed()")); + builder.setSignal(effectivePropertyIndex, p.changedSignatureRef); - if (p.type == Object::DynamicProperty::Alias) { - if (mode == ResolveAliases) { - ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++; - COMPILE_CHECK(compileAlias(builder, dynamicData, obj, p)); - } else { - // Need a fake signal so that the metaobject remains consistent across - // the resolve and non-resolve alias runs - builder.addSignal(p.name + "Changed()"); + effectivePropertyIndex++; + } + + if (aliasCount) { + int aliasIndex = 0; + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + Object::DynamicProperty &p = obj->dynamicProperties[ii]; + if (p.type == Object::DynamicProperty::Alias) { + if (resolveAlias) { + Q_ASSERT(buildData); + ((QDeclarativeVMEMetaData *)dynamicData.data())->aliasCount++; + COMPILE_CHECK(compileAlias(builder, dynamicData, obj, effectivePropertyIndex, aliasIndex, p)); + } + // Even if we aren't resolving the alias, we need a fake signal so that the + // metaobject remains consistent across the resolve and non-resolve alias runs + p.changedSignatureRef = builder.newString(p.name.length() + strlen("Changed()")); + builder.setSignal(effectivePropertyIndex, p.changedSignatureRef); + effectivePropertyIndex++; + aliasIndex++; + } } } } + // Reserve default property + QFastMetaBuilder::StringRef defPropRef; + if (defaultProperty) { + defPropRef = builder.newString(strlen("DefaultProperty")); + builder.setClassInfo(0, defPropRef, defaultProperty->nameRef); + } + + // Reserve dynamic signals for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { - const Object::DynamicSignal &s = obj->dynamicSignals.at(ii); - QByteArray sig(s.name + '('); - for (int jj = 0; jj < s.parameterTypes.count(); ++jj) { - if (jj) sig.append(','); - sig.append(s.parameterTypes.at(jj)); - } - sig.append(')'); - QMetaMethodBuilder b = builder.addSignal(sig); - b.setParameterNames(s.parameterNames); - ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++; + Object::DynamicSignal &s = obj->dynamicSignals[ii]; + + int paramCount = s.parameterNames.count(); + + int signatureSize = s.name.length() + 2 /* paren */; + int namesSize = 0; + if (paramCount) signatureSize += s.parameterTypesLength() + (paramCount - 1) /* commas */; + if (paramCount) namesSize += s.parameterNamesLength() + (paramCount - 1) /* commas */; + + s.signatureRef = builder.newString(signatureSize); + if (namesSize) s.parameterNamesRef = builder.newString(namesSize); + + if (buildData) + ((QDeclarativeVMEMetaData *)dynamicData.data())->signalCount++; + + builder.setSignal(ii + obj->dynamicProperties.count(), s.signatureRef, s.parameterNamesRef); } - QStringList funcScripts; + // Reserve dynamic slots + if (obj->dynamicSlots.count()) { - for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { - Object::DynamicSlot &s = obj->dynamicSlots[ii]; - QByteArray sig(s.name + '('); - QString funcScript(QLatin1String("(function ") + s.name + QLatin1Char('(')); + // Allocate QVariant string + if (typeRefs[0].isEmpty()) + typeRefs[0] = builder.newString(strlen(builtinTypes[0].cppType)); - for (int jj = 0; jj < s.parameterNames.count(); ++jj) { - if (jj) { - sig.append(','); - funcScript.append(QLatin1Char(',')); + typedef QDeclarativeVMEMetaData VMD; + + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + Object::DynamicSlot &s = obj->dynamicSlots[ii]; + int paramCount = s.parameterNames.count(); + + int signatureSize = s.name.length() + 2 /* paren */; + int namesSize = 0; + if (paramCount) signatureSize += (paramCount * strlen("QVariant") + (paramCount - 1)); + if (paramCount) namesSize += s.parameterNamesLength() + (paramCount - 1 /* commas */); + + s.signatureRef = builder.newString(signatureSize); + if (namesSize) s.parameterNamesRef = builder.newString(namesSize); + + builder.setMethod(ii, s.signatureRef, s.parameterNamesRef, typeRefs[0]); + + if (buildData) { + QString funcScript; + funcScript.reserve(strlen("(function ") + s.name.length() + 1 /* lparen */ + + namesSize + 1 /* rparen */ + s.body.length() + 1 /* rparen */); + funcScript = QLatin1String("(function ") + s.name + QLatin1Char('('); + for (int jj = 0; jj < paramCount; ++jj) { + if (jj) funcScript.append(QLatin1Char(',')); + funcScript.append(QLatin1String(s.parameterNames.at(jj))); + } + funcScript += QLatin1Char(')') + s.body + QLatin1Char(')'); + + VMD::MethodData methodData = { s.parameterNames.count(), 0, + funcScript.length(), + s.location.start.line }; + + VMD *vmd = (QDeclarativeVMEMetaData *)dynamicData.data(); + vmd->methodCount++; + + VMD::MethodData &md = *(vmd->methodData() + ii); + md = methodData; + md.bodyOffset = dynamicData.size(); + + dynamicData.append((const char *)funcScript.constData(), + (funcScript.length() * sizeof(QChar))); } - funcScript.append(QLatin1String(s.parameterNames.at(jj))); - sig.append("QVariant"); + } - sig.append(')'); - funcScript.append(QLatin1Char(')')); - funcScript.append(s.body); - funcScript.append(QLatin1Char(')')); - funcScripts << funcScript; + } - QMetaMethodBuilder b = builder.addSlot(sig); - b.setReturnType("QVariant"); - b.setParameterNames(s.parameterNames); + // Now allocate used builtin types + for (int ii = 0; ii < builtinTypeCount; ++ii) { + if (!typeRefs[ii].isEmpty()) + typeRefs[ii].load(builtinTypes[ii].cppType); + } + + // Now allocate properties + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + Object::DynamicProperty &p = obj->dynamicProperties[ii]; + + char *d = p.changedSignatureRef.data(); + strcpy(d, p.name.constData()); + strcpy(d + p.name.length(), "Changed()"); + + if (p.type == Object::DynamicProperty::Alias && !resolveAlias) + continue; - ((QDeclarativeVMEMetaData *)dynamicData.data())->methodCount++; - QDeclarativeVMEMetaData::MethodData methodData = - { s.parameterNames.count(), 0, funcScript.length(), s.location.start.line }; + p.nameRef.load(p.name); - dynamicData.append((char *)&methodData, sizeof(methodData)); + if (p.type >= builtinTypeCount) + p.typeRef.load(p.resolvedCustomTypeName); } - for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { - const QString &funcScript = funcScripts.at(ii); - QDeclarativeVMEMetaData::MethodData *data = - ((QDeclarativeVMEMetaData *)dynamicData.data())->methodData() + ii; + // Allocate default property if necessary + if (defaultProperty) + strcpy(defPropRef.data(), "DefaultProperty"); + + // Now allocate signals + for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { + Object::DynamicSignal &s = obj->dynamicSignals[ii]; - data->bodyOffset = dynamicData.size(); + char *d = s.signatureRef.data(); + char *d2 = s.parameterNamesRef.isEmpty()?0:s.parameterNamesRef.data(); + strcpy(d, s.name.constData()); + d += s.name.length(); + *d++ = '('; + + for (int jj = 0; jj < s.parameterNames.count(); ++jj) { + if (jj != 0) { *d++ = ','; *d2++ = ','; } + strcpy(d, s.parameterTypes.at(jj).constData()); + d += s.parameterTypes.at(jj).length(); + strcpy(d2, s.parameterNames.at(jj).constData()); + d2 += s.parameterNames.at(jj).length(); + } + *d++ = ')'; + *d = 0; + if (d2) *d2 = 0; + } - dynamicData.append((const char *)funcScript.constData(), - (funcScript.length() * sizeof(QChar))); + // Now allocate methods + for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { + Object::DynamicSlot &s = obj->dynamicSlots[ii]; + char *d = s.signatureRef.data(); + char *d2 = s.parameterNamesRef.isEmpty()?0:s.parameterNamesRef.data(); + strcpy(d, s.name.constData()); + d += s.name.length(); + *d++ = '('; + for (int jj = 0; jj < s.parameterNames.count(); ++jj) { + if (jj != 0) { *d++ = ','; *d2++ = ','; } + strcpy(d, "QVariant"); + d += strlen("QVariant"); + strcpy(d2, s.parameterNames.at(jj).constData()); + d2 += s.parameterNames.at(jj).length(); + } + *d++ = ')'; + *d = 0; + if (d2) *d2 = 0; } - obj->metadata = builder.toRelocatableData(); - builder.fromRelocatableData(&obj->extObject, obj->metatype, obj->metadata); + // Now allocate class name + classNameRef.load(newClassName); - if (mode == IgnoreAliases && hasAlias) + obj->metadata = builder.toData(); + builder.fromData(&obj->extObject, obj->metatype, obj->metadata); + + if (mode == IgnoreAliases && aliasCount) compileState->aliasingObjects.append(obj); obj->synthdata = dynamicData; @@ -2759,10 +2893,11 @@ static QStringList astNodeToStringList(QDeclarativeJS::AST::Node *node) return QStringList(); } -bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, +bool QDeclarativeCompiler::compileAlias(QFastMetaBuilder &builder, QByteArray &data, QDeclarativeParser::Object *obj, - const Object::DynamicProperty &prop) + int propIndex, int aliasIndex, + Object::DynamicProperty &prop) { if (!prop.defaultValue) COMPILE_EXCEPTION(obj, tr("No property alias location")); @@ -2789,6 +2924,7 @@ bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, int propIdx = -1; int flags = 0; + int type = 0; bool writable = false; bool resettable = false; if (alias.count() == 2 || alias.count() == 3) { @@ -2807,6 +2943,9 @@ bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, writable = aliasProperty.isWritable(); resettable = aliasProperty.isResettable(); + if (aliasProperty.type() < QVariant::UserType) + type = aliasProperty.type(); + if (alias.count() == 3) { QDeclarativeValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()]; if (!valueType) @@ -2842,15 +2981,20 @@ bool QDeclarativeCompiler::compileAlias(QMetaObjectBuilder &builder, if (typeName.endsWith('*')) flags |= QML_ALIAS_FLAG_PTR; - data.append((const char *)&idObject->idIndex, sizeof(idObject->idIndex)); - data.append((const char *)&propIdx, sizeof(propIdx)); - data.append((const char *)&flags, sizeof(flags)); + QDeclarativeVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags }; + + typedef QDeclarativeVMEMetaData VMD; + VMD *vmd = (QDeclarativeVMEMetaData *)data.data(); + *(vmd->aliasData() + aliasIndex) = aliasData; + + prop.nameRef = builder.newString(prop.name.length()); + prop.resolvedCustomTypeName = typeName; + prop.typeRef = builder.newString(typeName.length()); + + builder.setProperty(propIndex, prop.nameRef, prop.typeRef, (QMetaType::Type)type, + (QFastMetaBuilder::PropertyFlag)(writable?int(QFastMetaBuilder::Writable):0), + propIndex); - builder.addSignal(prop.name + "Changed()"); - QMetaPropertyBuilder propBuilder = - builder.addProperty(prop.name, typeName.constData(), builder.methodCount() - 1); - propBuilder.setWritable(writable); - propBuilder.setResettable(resettable); return true; } diff --git a/src/declarative/qml/qdeclarativecompiler_p.h b/src/declarative/qml/qdeclarativecompiler_p.h index 66d094e886..e8f5c6ac52 100644 --- a/src/declarative/qml/qdeclarativecompiler_p.h +++ b/src/declarative/qml/qdeclarativecompiler_p.h @@ -301,10 +301,11 @@ private: bool buildBinding(QDeclarativeParser::Value *, QDeclarativeParser::Property *prop, const QDeclarativeCompilerTypes::BindingContext &ctxt); bool buildComponentFromRoot(QDeclarativeParser::Object *obj, const QDeclarativeCompilerTypes::BindingContext &); - bool compileAlias(QMetaObjectBuilder &, + bool compileAlias(QFastMetaBuilder &, QByteArray &data, QDeclarativeParser::Object *obj, - const QDeclarativeParser::Object::DynamicProperty &); + int propIndex, int aliasIndex, + QDeclarativeParser::Object::DynamicProperty &); bool completeComponentBuild(); bool checkValidId(QDeclarativeParser::Value *, const QString &); diff --git a/src/declarative/qml/qdeclarativeparser.cpp b/src/declarative/qml/qdeclarativeparser.cpp index 9f08ae8dc0..a34eceb456 100644 --- a/src/declarative/qml/qdeclarativeparser.cpp +++ b/src/declarative/qml/qdeclarativeparser.cpp @@ -195,6 +195,22 @@ QDeclarativeParser::Object::DynamicSignal::DynamicSignal(const DynamicSignal &o) { } +int QDeclarativeParser::Object::DynamicSignal::parameterTypesLength() const +{ + int rv = 0; + for (int ii = 0; ii < parameterTypes.count(); ++ii) + rv += parameterTypes.at(ii).length(); + return rv; +} + +int QDeclarativeParser::Object::DynamicSignal::parameterNamesLength() const +{ + int rv = 0; + for (int ii = 0; ii < parameterNames.count(); ++ii) + rv += parameterNames.at(ii).length(); + return rv; +} + QDeclarativeParser::Object::DynamicSlot::DynamicSlot() { } @@ -204,6 +220,14 @@ QDeclarativeParser::Object::DynamicSlot::DynamicSlot(const DynamicSlot &o) { } +int QDeclarativeParser::Object::DynamicSlot::parameterNamesLength() const +{ + int rv = 0; + for (int ii = 0; ii < parameterNames.count(); ++ii) + rv += parameterNames.at(ii).length(); + return rv; +} + QDeclarativeParser::Property::Property() : parent(0), type(0), index(-1), value(0), _name(0), isDefault(true), isDeferred(false), isValueTypeSubProperty(false), isAlias(false), scriptStringScope(-1), nextProperty(0), diff --git a/src/declarative/qml/qdeclarativeparser_p.h b/src/declarative/qml/qdeclarativeparser_p.h index 0d39c20979..023cb9cd07 100644 --- a/src/declarative/qml/qdeclarativeparser_p.h +++ b/src/declarative/qml/qdeclarativeparser_p.h @@ -67,6 +67,7 @@ #include <private/qdeclarativepool_p.h> #include <private/qfieldlist_p.h> #include <private/qdeclarativepropertycache_p.h> +#include <private/qfastmetabuilder_p.h> QT_BEGIN_HEADER @@ -374,6 +375,12 @@ namespace QDeclarativeParser QByteArray name; QDeclarativeParser::Property *defaultValue; LocationSpan location; + + // Used by the compiler + QByteArray resolvedCustomTypeName; + QFastMetaBuilder::StringRef typeRef; + QFastMetaBuilder::StringRef nameRef; + QFastMetaBuilder::StringRef changedSignatureRef; }; struct DynamicSignal { DynamicSignal(); @@ -382,6 +389,13 @@ namespace QDeclarativeParser QByteArray name; QList<QByteArray> parameterTypes; QList<QByteArray> parameterNames; + + int parameterTypesLength() const; + int parameterNamesLength() const; + + // Used by the compiler + QFastMetaBuilder::StringRef signatureRef; + QFastMetaBuilder::StringRef parameterNamesRef; }; struct DynamicSlot { DynamicSlot(); @@ -391,6 +405,12 @@ namespace QDeclarativeParser QString body; QList<QByteArray> parameterNames; LocationSpan location; + + int parameterNamesLength() const; + + // Used by the compiler + QFastMetaBuilder::StringRef signatureRef; + QFastMetaBuilder::StringRef parameterNamesRef; }; // The list of dynamic properties diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index dae1ba0030..e631dbbc08 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -45,6 +45,7 @@ #include "private/qdeclarativeboundsignal_p.h" #include "private/qdeclarativestringconverters_p.h" #include "private/qmetaobjectbuilder_p.h" +#include "private/qfastmetabuilder_p.h" #include "private/qdeclarativedata_p.h" #include "qdeclarative.h" #include "private/qdeclarativecustomparser_p.h" @@ -356,7 +357,9 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEObjectStack &stack, QMetaObject mo; const QByteArray &metadata = datas.at(instr.data); - QMetaObjectBuilder::fromRelocatableData(&mo, 0, metadata); + QFastMetaBuilder::fromData(&mo, 0, metadata); +// QMetaObjectBuilder::fromRelocatableData(&mo, 0, metadata); + const QDeclarativeVMEMetaData *data = (const QDeclarativeVMEMetaData *)datas.at(instr.aliasData).constData(); |