diff options
Diffstat (limited to 'src/qml/qml')
33 files changed, 1697 insertions, 1602 deletions
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri index f2fec4e2dd..c2409c6790 100644 --- a/src/qml/qml/ftw/ftw.pri +++ b/src/qml/qml/ftw/ftw.pri @@ -6,7 +6,6 @@ HEADERS += \ $$PWD/qqmlrefcount_p.h \ $$PWD/qqmlpool_p.h \ $$PWD/qfieldlist_p.h \ - $$PWD/qfastmetabuilder_p.h \ $$PWD/qhashfield_p.h \ $$PWD/qqmlthread_p.h \ $$PWD/qfinitestack_p.h \ @@ -22,7 +21,6 @@ SOURCES += \ $$PWD/qintrusivelist.cpp \ $$PWD/qhashedstring.cpp \ $$PWD/qqmlpool.cpp \ - $$PWD/qfastmetabuilder.cpp \ $$PWD/qqmlthread.cpp \ $$PWD/qqmltrace.cpp \ diff --git a/src/qml/qml/ftw/qfastmetabuilder.cpp b/src/qml/qml/ftw/qfastmetabuilder.cpp deleted file mode 100644 index b22be84107..0000000000 --- a/src/qml/qml/ftw/qfastmetabuilder.cpp +++ /dev/null @@ -1,343 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtQml 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" - -#include <QtCore/qmetaobject.h> -#include <private/qobject_p.h> -#include <private/qmetaobject_p.h> - -QT_BEGIN_NAMESPACE - -struct QFastMetaBuilderHeader -{ - int fieldCount; -}; - -#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_stringData(0), m_stringCount(0), m_stringDataLength(0), - m_stringCountAllocated(0), m_stringCountLoaded(0) -{ -} - -QFastMetaBuilder::~QFastMetaBuilder() -{ -} - -QFastMetaBuilder::StringRef QFastMetaBuilder::init(int classNameLength, - int propertyCount, int methodCount, - int signalCount, int classInfoCount, - int paramDataSize, int *paramIndex) -{ - 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); - Q_ASSERT(paramDataSize >= 0); - Q_ASSERT((paramIndex != 0) || (methodCount + signalCount == 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) + - paramDataSize + - classInfoCount * CLASSINFO_FIELD_COUNT; - // Ensure stringdata alignment (void*) - fieldCount += fieldCount % (sizeof(void*) / sizeof(uint)); - - m_stringCount = 2; // class name and zero string - m_stringDataLength = classNameLength + 1; - m_data.resize(fieldCount * sizeof(uint) + m_stringCount * sizeof(QByteArrayData) + m_stringDataLength); - m_stringCountAllocated = m_stringCount; - m_stringData = reinterpret_cast<QByteArrayData *>(m_data.data() + fieldCount * sizeof(uint)); - - m_zeroString._b = this; - m_zeroString._i = 1; - m_zeroString._o = classNameLength; - m_zeroString._l = 0; - - header(m_data)->fieldCount = fieldCount; - - QMetaObjectPrivate *p = priv(m_data); - - int dataIndex = HEADER_FIELD_COUNT; - - p->revision = 7; - 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; - *paramIndex = dataIndex; - dataIndex += paramDataSize; - } 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._i = 0; - 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); - Q_ASSERT_X(m_stringCountLoaded == 0, Q_FUNC_INFO, - "All strings must be created before string loading begins"); - - StringRef sr; - sr._b = this; - sr._i = m_stringCount; - sr._o = m_stringDataLength; - sr._l = length; - - ++m_stringCount; - 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.index(); ptr[1] = value.index(); -} - -void QFastMetaBuilder::setProperty(int index, const StringRef &name, int type, - PropertyFlag flags, int notifySignal) -{ - Q_ASSERT(!m_data.isEmpty()); - Q_ASSERT(!name.isEmpty()); - Q_ASSERT(type != 0); - Q_ASSERT(QMetaType::isRegistered(type)); - - 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.index(); - ptr[1] = type; - 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 &name, - int paramIndex, int argc, const int *types, - const StringRef *parameterNames, - QMetaType::Type type) -{ - Q_ASSERT(!m_data.isEmpty()); - Q_ASSERT(!name.isEmpty()); - Q_ASSERT(QMetaType::isRegistered(type)); - - QMetaObjectPrivate *p = priv(m_data); - int mindex = metaObjectIndexForSignal(index); - - uint *ptr = fieldPointer(m_data) + p->methodData + mindex * METHOD_FIELD_COUNT; - // methods: name, arc, parameters, tag, flags - ptr[0] = name.index(); - ptr[1] = argc; - ptr[2] = paramIndex; - ptr[3] = m_zeroString.index(); - ptr[4] = AccessProtected | MethodSignal; - - uint *paramPtr = fieldPointer(m_data) + paramIndex; - paramPtr[0] = type; - if (argc) { - Q_ASSERT(types != 0); - Q_ASSERT(parameterNames != 0); - for (int i = 0; i < argc; ++i) { - Q_ASSERT(types[i] != 0); - Q_ASSERT(QMetaType::isRegistered(types[i])); - paramPtr[1+i] = types[i]; - paramPtr[1+argc+i] = parameterNames[i].index(); - } - } -} - -void QFastMetaBuilder::setMethod(int index, const StringRef &name, - int paramIndex, int argc, const int *types, - const StringRef *parameterNames, - QMetaType::Type type) -{ - Q_ASSERT(!m_data.isEmpty()); - Q_ASSERT(!name.isEmpty()); - Q_ASSERT(QMetaType::isRegistered(type)); - - QMetaObjectPrivate *p = priv(m_data); - int mindex = metaObjectIndexForMethod(index); - - uint *ptr = fieldPointer(m_data) + p->methodData + mindex * METHOD_FIELD_COUNT; - // methods: name, arc, parameters, tag, flags - ptr[0] = name.index(); - ptr[1] = argc; - ptr[2] = paramIndex; - ptr[3] = m_zeroString.index(); - ptr[4] = AccessProtected | MethodSlot; - - uint *paramPtr = fieldPointer(m_data) + paramIndex; - paramPtr[0] = type; - if (argc) { - Q_ASSERT(types != 0); - Q_ASSERT(parameterNames != 0); - for (int i = 0; i < argc; ++i) { - Q_ASSERT(types[i] != 0); - Q_ASSERT(QMetaType::isRegistered(types[i])); - paramPtr[1+i] = types[i]; - paramPtr[1+argc+i] = parameterNames[i].index(); - } - } -} - -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_stringCountAllocated < m_stringCount) { - m_data.resize(header(m_data)->fieldCount * sizeof(uint) - + m_stringCount * sizeof(QByteArrayData) + m_stringDataLength); - m_stringCountAllocated = m_stringCount; - char *rawStringData = m_data.data() + header(m_data)->fieldCount * sizeof(uint); - m_stringData = reinterpret_cast<QByteArrayData *>(rawStringData); - } -} - -void QFastMetaBuilder::fromData(QMetaObject *output, const QMetaObject *parent, const QByteArray &data) -{ - output->d.superdata = parent; - output->d.stringdata = reinterpret_cast<const QByteArrayData *>(data.constData() + header(data)->fieldCount * sizeof(uint)); - output->d.data = fieldPointer(data); - output->d.extradata = 0; - output->d.static_metacall = 0; - output->d.relatedMetaObjects = 0; -} - -QT_END_NAMESPACE diff --git a/src/qml/qml/ftw/qfastmetabuilder_p.h b/src/qml/qml/ftw/qfastmetabuilder_p.h deleted file mode 100644 index aebafc8b55..0000000000 --- a/src/qml/qml/ftw/qfastmetabuilder_p.h +++ /dev/null @@ -1,234 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtQml 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> -#include <QtCore/qmetaobject.h> - -#include <private/qhashedstring_p.h> - -QT_BEGIN_NAMESPACE - -struct QMetaObject; -class QFastMetaBuilder -{ -public: - QFastMetaBuilder(); - ~QFastMetaBuilder(); - - struct StringRef { - public: - inline StringRef(); - inline StringRef(const StringRef &); - inline StringRef &operator=(const StringRef &); - - inline void load(const QHashedStringRef &); - inline void load(const QByteArray &); - inline void load(const char *); - - inline bool isEmpty() const; - inline QFastMetaBuilder *builder() const; - inline int index() const; - inline char *data(); - inline int length() const; - inline void loadByteArrayData(); - private: - friend class QFastMetaBuilder; - - QFastMetaBuilder *_b; - int _i; - int _o; - int _l; - }; - StringRef newString(int length); - - // Returns class name - StringRef init(int classNameLength, - int propertyCount, int methodCount, - int signalCount, int classInfoCount, - int paramDataSize, int *paramIndex); - - 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, int type, - PropertyFlag flags, int notifySignal = -1); - void setMethod(int index, const StringRef &name, int paramIndex, int argc = 0, - const int *types = 0, const StringRef *parameterNames = 0, - QMetaType::Type type = QMetaType::Void); - void setSignal(int index, const StringRef &name, int paramIndex, int argc = 0, - const int *types = 0, const StringRef *parameterNames = 0, - QMetaType::Type type = QMetaType::Void); - - int metaObjectIndexForSignal(int) const; - int metaObjectIndexForMethod(int) const; - - QByteArray toData() const { - if (m_stringCountLoaded == m_stringCount - 1) { - // zero-string is lazily loaded last - const_cast<StringRef &>(m_zeroString).loadByteArrayData(); - } - Q_ASSERT(m_stringCountLoaded == m_stringCount); - return m_data; - } - static void fromData(QMetaObject *, const QMetaObject *parent, const QByteArray &); -private: - friend struct StringRef; - - QByteArray m_data; - StringRef m_zeroString; - - void allocateStringData(); - QByteArrayData *m_stringData; - int m_stringCount; - int m_stringDataLength; - int m_stringCountAllocated; - int m_stringCountLoaded; -}; - -QFastMetaBuilder::StringRef::StringRef() -: _b(0), _i(0), _o(0), _l(0) -{ -} - -QFastMetaBuilder::StringRef::StringRef(const StringRef &o) -: _b(o._b), _i(o._i), _o(o._o), _l(o._l) -{ -} - -QFastMetaBuilder::StringRef &QFastMetaBuilder::StringRef::operator=(const StringRef &o) -{ - _b = o._b; - _i = o._i; - _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::index() const -{ - return _i; -} - -char *QFastMetaBuilder::StringRef::data() -{ - Q_ASSERT(_b); - if (_b->m_stringCountAllocated < _b->m_stringCount) - _b->allocateStringData(); - return reinterpret_cast<char *>(&_b->m_stringData[_b->m_stringCount]) + _o; -} - -int QFastMetaBuilder::StringRef::length() const -{ - return _l; -} - -void QFastMetaBuilder::StringRef::load(const QHashedStringRef &str) -{ - Q_ASSERT(str.utf8length() == _l); - str.writeUtf8(data()); - *(data() + _l) = 0; - loadByteArrayData(); -} - -void QFastMetaBuilder::StringRef::load(const QByteArray &str) -{ - Q_ASSERT(str.length() == _l); - strcpy(data(), str.constData()); - loadByteArrayData(); -} - -void QFastMetaBuilder::StringRef::load(const char *str) -{ - Q_ASSERT(strlen(str) == (uint)_l); - strcpy(data(), str); - loadByteArrayData(); -} - -void QFastMetaBuilder::StringRef::loadByteArrayData() -{ - if (_b->m_stringCountAllocated < _b->m_stringCount) - _b->allocateStringData(); - Q_ASSERT(_b->m_stringCountLoaded < _b->m_stringCount); - - int offsetofCstrings = _b->m_stringCount * sizeof(QByteArrayData); - qptrdiff offset = offsetofCstrings + _o - _i * sizeof(QByteArrayData); - - const QByteArrayData bad = Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(_l, offset); - memcpy(&_b->m_stringData[_i], &bad, sizeof(QByteArrayData)); - - ++_b->m_stringCountLoaded; -} - -QT_END_NAMESPACE - -#endif // QFASTMETABUILDER_P_H - diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h index f8099d508b..cdc1577987 100644 --- a/src/qml/qml/ftw/qhashedstring_p.h +++ b/src/qml/qml/ftw/qhashedstring_p.h @@ -157,6 +157,8 @@ public: QString toString() const; + inline bool isLatin1() const; + inline int utf8length() const; QByteArray toUtf8() const; void writeUtf8(char *) const; @@ -1337,6 +1339,13 @@ int QHashedStringRef::utf8length() const return m_utf8length; } +bool QHashedStringRef::isLatin1() const +{ + for (int ii = 0; ii < m_length; ++ii) + if (m_data[ii].unicode() > 127) return false; + return true; +} + bool QHashedStringRef::startsWithUpper() const { if (m_length < 1) return false; diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 9a3ce65ad3..1a16c07a75 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -242,9 +242,9 @@ void QQmlAbstractBoundSignal::removeFromObject() } } -QQmlBoundSignal::QQmlBoundSignal(QObject *scope, const QMetaMethod &signal, - QObject *owner, QQmlEngine *engine) -: m_expression(0), m_params(0), m_scope(scope), m_index(signal.methodIndex()) +QQmlBoundSignal::QQmlBoundSignal(QObject *scope, int signal, QObject *owner, + QQmlEngine *engine) +: m_expression(0), m_params(0), m_scope(scope), m_index(signal) { setParamsValid(false); setIsEvaluating(false); @@ -257,11 +257,15 @@ QQmlBoundSignal::QQmlBoundSignal(QObject *scope, const QMetaMethod &signal, index refers to 'aSignal()', get the index of 'aSignal(int)'. This ensures that 'parameter' will be available from QML. */ - if (signal.attributes() & QMetaMethod::Cloned) { - do { + if (QQmlData::get(scope, false) && QQmlData::get(scope, false)->propertyCache) { + QQmlPropertyCache *cache = QQmlData::get(scope, false)->propertyCache; + while (cache->method(m_index)->isCloned()) + --m_index; + } else { + while (scope->metaObject()->method(m_index).attributes() & QMetaMethod::Cloned) --m_index; - } while (scope->metaObject()->method(m_index).attributes() & QMetaMethod::Cloned); } + QQmlNotifierEndpoint::connect(scope, m_index, engine); } @@ -328,9 +332,12 @@ void QQmlBoundSignal::subscriptionCallback(QQmlNotifierEndpoint *e, void **a) s->setIsEvaluating(true); if (!s->paramsValid()) { - QMetaMethod signal = s->m_scope->metaObject()->method(s->m_index); - if (!signal.parameterTypes().isEmpty()) + QList<QByteArray> names = QQmlPropertyCache::methodParameterNames(*s->m_scope, s->m_index); + if (!names.isEmpty()) { + QMetaMethod signal = s->m_scope->metaObject()->method(s->m_index); s->m_params = new QQmlBoundSignalParameters(signal, s); + } + s->setParamsValid(true); } diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h index e3ef65ed7f..b7f3e5f885 100644 --- a/src/qml/qml/qqmlboundsignal_p.h +++ b/src/qml/qml/qqmlboundsignal_p.h @@ -137,7 +137,7 @@ class Q_QML_PRIVATE_EXPORT QQmlBoundSignal : public QQmlAbstractBoundSignal, public QQmlNotifierEndpoint { public: - QQmlBoundSignal(QObject *scope, const QMetaMethod &signal, QObject *owner, QQmlEngine *engine); + QQmlBoundSignal(QObject *scope, int signal, QObject *owner, QQmlEngine *engine); virtual ~QQmlBoundSignal(); int index() const; diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp index 6e6da6ae0d..49f00944d5 100644 --- a/src/qml/qml/qqmlcompileddata.cpp +++ b/src/qml/qml/qqmlcompileddata.cpp @@ -55,21 +55,6 @@ QT_BEGIN_NAMESPACE -int QQmlCompiledData::pack(const char *data, size_t size) -{ - const char *p = packData.constData(); - unsigned int ps = packData.size(); - - for (unsigned int ii = 0; (ii + size) <= ps; ii += sizeof(int)) { - if (0 == ::memcmp(p + ii, data, size)) - return ii; - } - - int rv = packData.size(); - packData.append(data, int(size)); - return rv; -} - int QQmlCompiledData::indexForString(const QString &data) { int idx = primitives.indexOf(data); @@ -101,7 +86,8 @@ int QQmlCompiledData::indexForUrl(const QUrl &data) } QQmlCompiledData::QQmlCompiledData(QQmlEngine *engine) -: engine(engine), importCache(0), root(0), rootPropertyCache(0) +: engine(engine), importCache(0), metaTypeId(-1), listMetaTypeId(-1), isRegisteredWithEngine(false), + rootPropertyCache(0) { Q_ASSERT(engine); @@ -118,6 +104,9 @@ void QQmlCompiledData::destroy() QQmlCompiledData::~QQmlCompiledData() { + if (isRegisteredWithEngine) + QQmlEnginePrivate::get(engine)->unregisterCompositeType(this); + clear(); for (int ii = 0; ii < types.count(); ++ii) { @@ -149,16 +138,6 @@ void QQmlCompiledData::clear() qPersistentDispose(programs[ii].bindings); } -const QMetaObject *QQmlCompiledData::TypeReference::metaObject() const -{ - if (type) { - return type->metaObject(); - } else { - Q_ASSERT(component); - return component->root; - } -} - /*! Returns the property cache, if one alread exists. The cache is not referenced. */ diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index b00f4b3294..2e26d94047 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -44,7 +44,6 @@ #include "qqmlpropertyvaluesource.h" #include "qqmlcomponent.h" #include <private/qmetaobjectbuilder_p.h> -#include <private/qfastmetabuilder_p.h> #include "qqmlstringconverters_p.h" #include "qqmlengine_p.h" #include "qqmlengine.h" @@ -217,8 +216,7 @@ bool QQmlCompiler::isSignalPropertyName(const QHashedStringRef &name) This test corresponds to action taken by genLiteralAssignment(). Any change made here, must have a corresponding action in genLiteralAssigment(). */ -bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop, - QQmlScript::Value *v) +bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop, QQmlScript::Value *v) { const QQmlScript::Variant &value = v->value; @@ -226,7 +224,7 @@ bool QQmlCompiler::testLiteralAssignment(QQmlScript::Property *prop, COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); if (prop->core.isEnum()) { - QMetaProperty p = prop->parent->metaObject()->property(prop->index); + QMetaProperty p = prop->parent->metatype->firstCppMetaObject()->property(prop->index); int enumValue; bool ok; if (p.isFlagType()) { @@ -438,7 +436,7 @@ void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop, if (v->value.isNumber()) { double n = v->value.asNumber(); if (double(int(n)) == n) { - if (prop->core.isVMEProperty()) { + if (prop->core.isVarProperty()) { Instruction::StoreVarInteger instr; instr.propertyIndex = prop->index; instr.value = int(n); @@ -450,7 +448,7 @@ void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop, output->addInstruction(instr); } } else { - if (prop->core.isVMEProperty()) { + if (prop->core.isVarProperty()) { Instruction::StoreVarDouble instr; instr.propertyIndex = prop->index; instr.value = n; @@ -463,7 +461,7 @@ void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop, } } } else if (v->value.isBoolean()) { - if (prop->core.isVMEProperty()) { + if (prop->core.isVarProperty()) { Instruction::StoreVarBool instr; instr.propertyIndex = prop->index; instr.value = v->value.asBoolean(); @@ -475,7 +473,7 @@ void QQmlCompiler::genLiteralAssignment(QQmlScript::Property *prop, output->addInstruction(instr); } } else { - if (prop->core.isVMEProperty()) { + if (prop->core.isVarProperty()) { Instruction::StoreVar instr; instr.propertyIndex = prop->index; instr.value = output->indexForString(v->value.asString()); @@ -944,15 +942,18 @@ void QQmlCompiler::compileTree(QQmlScript::Object *tree) output->addInstruction(done); Q_ASSERT(tree->metatype); - - if (tree->metadata.isEmpty()) { - output->root = tree->metatype; + if (!tree->synthdata.isEmpty()) { + enginePrivate->registerCompositeType(output); + } else if (output->types.at(tree->type).component) { + output->metaTypeId = output->types.at(tree->type).component->metaTypeId; + output->listMetaTypeId = output->types.at(tree->type).component->listMetaTypeId; } else { - static_cast<QMetaObject &>(output->rootData) = *tree->metaObject(); - output->root = &output->rootData; + Q_ASSERT(output->types.at(tree->type).type); + output->metaTypeId = output->types.at(tree->type).type->typeId(); + output->listMetaTypeId = output->types.at(tree->type).type->qListTypeId(); } - if (!tree->metadata.isEmpty()) - enginePrivate->registerCompositeType(output->root); + if (!tree->synthdata.isEmpty()) + enginePrivate->registerCompositeType(output); } static bool QStringList_contains(const QStringList &list, const QHashedStringRef &string) @@ -970,11 +971,11 @@ bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ct componentStats->componentStat.objects++; Q_ASSERT (obj->type != -1); - const QQmlCompiledData::TypeReference &tr = output->types.at(obj->type); - obj->metatype = tr.metaObject(); + QQmlCompiledData::TypeReference &tr = output->types[obj->type]; + obj->metatype = tr.createPropertyCache(engine); - // This object is a "Component" element - if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) { + // This object is a "Component" element. + if (tr.type && obj->metatype->metaObject() == &QQmlComponent::staticMetaObject) { COMPILE_CHECK(buildComponent(obj, ctxt)); return true; } @@ -999,7 +1000,7 @@ bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ct // Create the synthesized meta object, ignoring aliases COMPILE_CHECK(checkDynamicMeta(obj)); COMPILE_CHECK(mergeDynamicMetaProperties(obj)); - COMPILE_CHECK(buildDynamicMeta(obj, IgnoreAliases)); + COMPILE_CHECK(buildDynamicMeta(obj, Normal)); // Find the native type and check for the QQmlParserStatus interface QQmlType *type = toQmlType(obj); @@ -1036,54 +1037,22 @@ bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ct Property *explicitProperty = 0; - const QMetaObject *mo = obj->metatype; - int idx = mo->indexOfClassInfo("DefaultProperty"); - if (idx != -1) { - QMetaClassInfo info = mo->classInfo(idx); - const char *p = info.value(); - if (p) { - int plen = 0; - char ord = 0; - while (char c = p[plen++]) { ord |= c; }; - --plen; - - if (ord & 0x80) { - // Utf8 - unoptimal, but seldom hit - QString *s = pool->NewString(QString::fromUtf8(p, plen)); - QHashedStringRef r(*s); - - if (obj->propertiesHashField.test(r.hash())) { - for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) { - if (ep->name() == r) { - explicitProperty = ep; - break; - } - } - } + QString defaultPropertyName = obj->metatype->defaultPropertyName(); + if (!defaultPropertyName.isEmpty()) { + QString *s = pool->NewString(defaultPropertyName); + QHashedStringRef r(*s); - if (!explicitProperty) - defaultProperty->setName(r); - - } else { - QHashedCStringRef r(p, plen); - - if (obj->propertiesHashField.test(r.hash())) { - for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) { - if (ep->name() == r) { - explicitProperty = ep; - break; - } - } - } - - if (!explicitProperty) { - // Set the default property name - QChar *buffer = pool->NewRawArray<QChar>(r.length()); - r.writeUtf16(buffer); - defaultProperty->setName(QHashedStringRef(buffer, r.length(), r.hash())); + if (obj->propertiesHashField.test(r.hash())) { + for (Property *ep = obj->properties.first(); ep; ep = obj->properties.next(ep)) { + if (ep->name() == r) { + explicitProperty = ep; + break; } } } + + if (!explicitProperty) + defaultProperty->setName(r); } if (explicitProperty && !explicitProperty->value && !explicitProperty->values.isEmpty()) { @@ -1189,7 +1158,7 @@ bool QQmlCompiler::buildObject(QQmlScript::Object *obj, const BindingContext &ct void QQmlCompiler::genObject(QQmlScript::Object *obj) { QQmlCompiledData::TypeReference &tr = output->types[obj->type]; - if (tr.type && obj->metatype == &QQmlComponent::staticMetaObject) { + if (tr.type && obj->metatype->metaObject() == &QQmlComponent::staticMetaObject) { genComponent(obj); return; } @@ -1240,9 +1209,8 @@ void QQmlCompiler::genObject(QQmlScript::Object *obj) } // Setup the synthesized meta object if necessary - if (!obj->metadata.isEmpty()) { + if (!obj->synthdata.isEmpty()) { Instruction::StoreMetaObject meta; - meta.data = output->indexForByteArray(obj->metadata); meta.aliasData = output->indexForByteArray(obj->synthdata); meta.propertyCache = output->propertyCaches.count(); @@ -1250,17 +1218,6 @@ void QQmlCompiler::genObject(QQmlScript::Object *obj) Q_ASSERT(propertyCache); propertyCache->addref(); - // Add flag for alias properties - if (!obj->synthdata.isEmpty()) { - const QQmlVMEMetaData *vmeMetaData = - reinterpret_cast<const QQmlVMEMetaData *>(obj->synthdata.constData()); - for (int ii = 0; ii < vmeMetaData->aliasCount; ++ii) { - int index = obj->metaObject()->propertyOffset() + vmeMetaData->propertyCount + ii; - QQmlPropertyData *data = propertyCache->property(index); - data->setFlags(data->getFlags() | QQmlPropertyData::IsAlias); - } - } - if (obj == unitRoot) { propertyCache->addref(); output->rootPropertyCache = propertyCache; @@ -1388,11 +1345,14 @@ void QQmlCompiler::genObjectBody(QQmlScript::Object *obj) fetch.line = prop->location.start.line; output->addInstruction(fetch); - if (!prop->value->metadata.isEmpty()) { + if (!prop->value->synthdata.isEmpty()) { Instruction::StoreMetaObject meta; - meta.data = output->indexForByteArray(prop->value->metadata); meta.aliasData = output->indexForByteArray(prop->value->synthdata); - meta.propertyCache = -1; + meta.propertyCache = output->propertyCaches.count(); + QQmlPropertyCache *propertyCache = prop->value->synthCache; + Q_ASSERT(propertyCache); + propertyCache->addref(); + output->propertyCaches << propertyCache; output->addInstruction(meta); } @@ -1665,7 +1625,7 @@ int QQmlCompiler::translationContextIndex() bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *obj, const BindingContext &ctxt) { - Q_ASSERT(obj->metaObject()); + Q_ASSERT(obj->metatype); const QHashedStringRef &propName = prop->name(); @@ -1754,9 +1714,6 @@ bool QQmlCompiler::buildProperty(QQmlScript::Property *prop, if (prop->isEmpty()) COMPILE_EXCEPTION(prop, tr("Empty property assignment")); - const QMetaObject *metaObject = obj->metaObject(); - Q_ASSERT(metaObject); - if (isAttachedPropertyName(prop->name())) { // Setup attached property data @@ -1784,7 +1741,7 @@ bool QQmlCompiler::buildProperty(QQmlScript::Property *prop, Q_ASSERT(type->attachedPropertiesFunction()); prop->index = type->attachedPropertiesId(); - prop->value->metatype = type->attachedPropertiesType(); + prop->value->metatype = enginePrivate->cache(type->attachedPropertiesType()); } else { // Setup regular property data bool notInRevision = false; @@ -1803,13 +1760,13 @@ bool QQmlCompiler::buildProperty(QQmlScript::Property *prop, prop->index = d->coreIndex; prop->core = *d; } else if (prop->isDefault) { - QMetaProperty p = QQmlMetaType::defaultProperty(metaObject); - QQmlPropertyData defaultPropertyData; - defaultPropertyData.load(p, engine); - if (p.name()) - prop->setName(QLatin1String(p.name())); - prop->core = defaultPropertyData; - prop->index = prop->core.coreIndex; + QString defaultPropertyName = obj->metatype->defaultPropertyName(); + + if (!defaultPropertyName.isEmpty()) { + prop->setName(defaultPropertyName); + prop->core = *obj->metatype->defaultProperty(); + prop->index = prop->core.coreIndex; + } } // We can't error here as the "id" property does not require a @@ -1901,7 +1858,7 @@ bool QQmlCompiler::buildPropertyInNamespace(QQmlImportNamespace *ns, Q_ASSERT(type->attachedPropertiesFunction()); prop->index = type->index(); - prop->value->metatype = type->attachedPropertiesType(); + prop->value->metatype = enginePrivate->cache(type->attachedPropertiesType()); COMPILE_CHECK(buildAttachedProperty(prop, obj, ctxt)); } @@ -1979,7 +1936,7 @@ void QQmlCompiler::genPropertyAssignment(QQmlScript::Property *prop, } else if (prop->type == QMetaType::QVariant) { - if (prop->core.isVMEProperty()) { + if (prop->core.isVarProperty()) { Instruction::StoreVarObject store; store.line = v->object->location.start.line; store.propertyIndex = prop->index; @@ -2178,7 +2135,7 @@ bool QQmlCompiler::buildGroupedProperty(QQmlScript::Property *prop, } else { // Load the nested property's meta type - prop->value->metatype = enginePrivate->metaObjectForType(prop->type); + prop->value->metatype = enginePrivate->propertyCacheForType(prop->type); if (!prop->value->metatype) COMPILE_EXCEPTION(prop, tr("Invalid grouped property access")); @@ -2206,7 +2163,7 @@ bool QQmlCompiler::buildValueTypeProperty(QObject *type, if (obj->defaultProperty) COMPILE_EXCEPTION(obj, tr("Invalid property use")); - obj->metatype = type->metaObject(); + obj->metatype = enginePrivate->cache(type); for (Property *prop = obj->properties.first(); prop; prop = obj->properties.next(prop)) { @@ -2396,22 +2353,22 @@ bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop, // meta object earlier to test for assignability. It doesn't matter // that there may still be outstanding synthesized meta object changes // on this type, as they are not relevant for assignability testing - v->object->metatype = output->types.at(v->object->type).metaObject(); - Q_ASSERT(v->object->metaObject()); + v->object->metatype = output->types[v->object->type].createPropertyCache(engine); + Q_ASSERT(v->object->metatype); // We want to raw metaObject here as the raw metaobject is the // actual property type before we applied any extensions that might // effect the properties on the type, but don't effect assignability - const QMetaObject *propertyMetaObject = enginePrivate->rawMetaObjectForType(prop->type); + QQmlPropertyCache *propertyMetaObject = enginePrivate->rawPropertyCacheForType(prop->type); // Will be true if the assgned type inherits propertyMetaObject bool isAssignable = false; // Determine isAssignable value if (propertyMetaObject) { - const QMetaObject *c = v->object->metatype; - while(c) { - isAssignable |= (QQmlPropertyPrivate::equal(c, propertyMetaObject)); - c = c->superClass(); + QQmlPropertyCache *c = v->object->metatype; + while (c && !isAssignable) { + isAssignable |= c == propertyMetaObject; + c = c->parent(); } } @@ -2420,12 +2377,12 @@ bool QQmlCompiler::buildPropertyObjectAssignment(QQmlScript::Property *prop, COMPILE_CHECK(buildObject(v->object, ctxt)); v->type = Value::CreatedObject; - } else if (propertyMetaObject == &QQmlComponent::staticMetaObject) { + } else if (propertyMetaObject && propertyMetaObject->metaObject() == &QQmlComponent::staticMetaObject) { // Automatic "Component" insertion QQmlScript::Object *root = v->object; QQmlScript::Object *component = pool->New<Object>(); component->type = componentTypeRef(); - component->metatype = &QQmlComponent::staticMetaObject; + component->metatype = enginePrivate->cache(&QQmlComponent::staticMetaObject); component->location = root->location; QQmlScript::Value *componentValue = pool->New<Value>(); componentValue->object = root; @@ -2465,8 +2422,8 @@ bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop, // meta object earlier to test for assignability. It doesn't matter // that there may still be outstanding synthesized meta object changes // on this type, as they are not relevant for assignability testing - v->object->metatype = output->types.at(v->object->type).metaObject(); - Q_ASSERT(v->object->metaObject()); + v->object->metatype = output->types[v->object->type].createPropertyCache(engine); + Q_ASSERT(v->object->metatype); // Will be true if the assigned type inherits QQmlPropertyValueSource bool isPropertyValue = false; @@ -2481,7 +2438,7 @@ bool QQmlCompiler::buildPropertyOnAssignment(QQmlScript::Property *prop, // Assign as a property value source COMPILE_CHECK(buildObject(v->object, ctxt)); - if (isPropertyInterceptor && prop->parent->synthdata.isEmpty()) + if (isPropertyInterceptor && baseObj->synthdata.isEmpty()) buildDynamicMeta(baseObj, ForceCreation); v->type = isPropertyValue ? Value::ValueSource : Value::ValueInterceptor; } else { @@ -2537,7 +2494,7 @@ bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop, if (!prop->core.isEnum() && !isIntProp) return true; - QMetaProperty mprop = obj->metaObject()->property(prop->index); + QMetaProperty mprop = obj->metatype->firstCppMetaObject()->property(prop->index); if (!prop->core.isWritable() && !prop->isReadOnlyDeclaration) COMPILE_EXCEPTION(v, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); @@ -2775,7 +2732,27 @@ bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj) return true; } -Q_GLOBAL_STATIC(QAtomicInt, classIndexCounter) +#include <private/qqmljsparser_p.h> + +static QStringList astNodeToStringList(QQmlJS::AST::Node *node) +{ + if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) { + QString name = + static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString(); + return QStringList() << name; + } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) { + QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node); + + QStringList rv = astNodeToStringList(expr->base); + if (rv.isEmpty()) + return rv; + rv.append(expr->name.toString()); + return rv; + } + return QStringList(); +} + +static QAtomicInt classIndexCounter(0); bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode) { @@ -2788,74 +2765,7 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod obj->dynamicSlots.isEmpty()) return true; - bool resolveAlias = (mode == ResolveAliases); - - const Object::DynamicProperty *defaultProperty = 0; - int aliasCount = 0; - int varPropCount = 0; - int totalPropCount = 0; - int firstPropertyVarIndex = 0; - - for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { - - if (p->type == Object::DynamicProperty::Alias) - aliasCount++; - if (p->type == Object::DynamicProperty::Var) - varPropCount++; - - 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 - QQmlPropertyData *d = property(obj, p->name); - if (d && d->isFinal()) - COMPILE_EXCEPTION(p, tr("Cannot override FINAL property")); - } - } - - bool buildData = resolveAlias || aliasCount == 0; - - QByteArray dynamicData; - if (buildData) { - typedef QQmlVMEMetaData VMD; - - dynamicData = QByteArray(sizeof(QQmlVMEMetaData) + - (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_"); - 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() && nameBase.at(0).isUpper()) - newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(uniqueClassId); - } - } - - // Size of the array that describes parameter types & names - int paramDataSize = (obj->aggregateDynamicSignalParameterCount() + obj->aggregateDynamicSlotParameterCount()) * 2 - + obj->dynamicProperties.count() // for Changed() signals return types - // Return "parameters" don't have names - - (obj->dynamicSignals.count() + obj->dynamicSlots.count()); - - QFastMetaBuilder builder; - int paramIndex; - 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, paramDataSize, ¶mIndex); + Q_ASSERT(obj->synthCache == 0); struct TypeData { Object::DynamicProperty::Type dtype; @@ -2876,456 +2786,521 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod }; static const int builtinTypeCount = sizeof(builtinTypes) / sizeof(TypeData); - // Reserve dynamic properties - if (obj->dynamicProperties.count()) { - typedef QQmlVMEMetaData VMD; + QByteArray newClassName; - int effectivePropertyIndex = 0; - for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { + 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() && nameBase.at(0).isUpper()) + newClassName = nameBase.toUtf8() + "_QMLTYPE_" + + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)); + } + } + if (newClassName.isEmpty()) { + newClassName = QQmlMetaObject(obj->metatype).className(); + newClassName.append("_QML_"); + newClassName.append(QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1))); + } + QQmlPropertyCache *cache = obj->metatype->copyAndReserve(engine, obj->dynamicProperties.count(), + obj->dynamicProperties.count() + + obj->dynamicSignals.count() + + obj->dynamicSlots.count(), + obj->dynamicProperties.count() + + obj->dynamicSignals.count()); - // Reserve space for name - if (p->type != Object::DynamicProperty::Alias || resolveAlias) - p->nameRef = builder.newString(p->name.utf8length()); + cache->_dynamicClassName = newClassName; - int metaType = 0; - int propertyType = 0; // for VMD - bool readonly = false; + int cStringNameCount = 0; - if (p->type == Object::DynamicProperty::Alias) { - continue; - } else if (p->type < builtinTypeCount) { - Q_ASSERT(builtinTypes[p->type].dtype == p->type); - metaType = builtinTypes[p->type].metaType; - propertyType = metaType; + int aliasCount = 0; + int varPropCount = 0; - } else { - Q_ASSERT(p->type == Object::DynamicProperty::CustomList || - p->type == Object::DynamicProperty::Custom); - - // XXX don't double resolve this in the case of an alias run - - QByteArray customTypeName; - QQmlType *qmltype = 0; - QString url; - if (!unit->imports().resolveType(p->customType, &qmltype, &url, 0, 0, 0)) - COMPILE_EXCEPTION(p, tr("Invalid property type")); - - if (!qmltype) { - QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url)); - Q_ASSERT(tdata); - Q_ASSERT(tdata->isComplete()); - customTypeName = tdata->compiledData()->root->className(); - tdata->release(); - } else { - customTypeName = qmltype->typeName(); - } + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; + p = obj->dynamicProperties.next(p)) { - if (p->type == Object::DynamicProperty::Custom) { - customTypeName += '*'; - propertyType = QMetaType::QObjectStar; - } else { - readonly = true; - customTypeName = QByteArrayLiteral("QQmlListProperty<") + customTypeName + '>'; - propertyType = qMetaTypeId<QQmlListProperty<QObject> >(); - } + if (p->type == Object::DynamicProperty::Alias) + aliasCount++; + else if (p->type == Object::DynamicProperty::Var) + varPropCount++; - metaType = QMetaType::type(customTypeName); - Q_ASSERT(metaType != QMetaType::UnknownType); - Q_ASSERT(metaType != QMetaType::Void); - } + if (p->name.isLatin1()) { + p->nameIndex = cStringNameCount; + cStringNameCount += p->name.length() + 7 /* strlen("Changed") */; + } - if (p->type == Object::DynamicProperty::Var) - continue; + // No point doing this for both the alias and non alias cases + QQmlPropertyData *d = property(obj, p->name); + if (d && d->isFinal()) + COMPILE_EXCEPTION(p, tr("Cannot override FINAL property")); + } - if (p->isReadOnly) - readonly = true; + for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { + if (s->name.isLatin1()) { + s->nameIndex = cStringNameCount; + cStringNameCount += s->name.length(); + } + } - if (buildData) { - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - vmd->propertyCount++; - (vmd->propertyData() + effectivePropertyIndex)->propertyType = propertyType; - } + for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { + if (s->name.isLatin1()) { + s->nameIndex = cStringNameCount; + cStringNameCount += s->name.length(); + } + } - builder.setProperty(effectivePropertyIndex, p->nameRef, metaType, - readonly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, - effectivePropertyIndex); + char *cStringData = 0; + if (cStringNameCount) { + cache->_dynamicStringData.resize(cStringNameCount); + cStringData = cache->_dynamicStringData.data(); - p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size()); - builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex); - paramIndex++; + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; + p = obj->dynamicProperties.next(p)) { - effectivePropertyIndex++; - } + if (p->nameIndex == -1) continue; - if (varPropCount) { - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - if (buildData) - vmd->varPropertyCount = varPropCount; - firstPropertyVarIndex = effectivePropertyIndex; - totalPropCount = varPropCount + effectivePropertyIndex; - for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { - if (p->type == Object::DynamicProperty::Var) { - if (buildData) { - vmd->propertyCount++; - (vmd->propertyData() + effectivePropertyIndex)->propertyType = QMetaType::QVariant; - } + char *myData = cStringData + p->nameIndex; + for (int ii = 0; ii < p->name.length(); ++ii) + *myData++ = p->name.at(ii).unicode(); + *myData++ = 'C'; *myData++ = 'h'; *myData++ = 'a'; *myData++ = 'n'; + *myData++ = 'g'; *myData++ = 'e'; *myData++ = 'd'; + } - builder.setProperty(effectivePropertyIndex, p->nameRef, - QMetaType::QVariant, - p->isReadOnly?QFastMetaBuilder::None:QFastMetaBuilder::Writable, - effectivePropertyIndex); + for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { - p->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size()); - builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex); - paramIndex++; + if (s->nameIndex == -1) continue; - effectivePropertyIndex++; - } - } + char *myData = cStringData + s->nameIndex; + for (int ii = 0; ii < s->name.length(); ++ii) + *myData++ = s->name.at(ii).unicode(); } - - if (aliasCount) { - int aliasIndex = 0; - for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { - if (p->type == Object::DynamicProperty::Alias) { - if (resolveAlias) { - Q_ASSERT(buildData); - ((QQmlVMEMetaData *)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->changedNameRef = builder.newString(p->name.utf8length() + Changed_string.size()); - builder.setSignal(effectivePropertyIndex, p->changedNameRef, paramIndex); - paramIndex++; - effectivePropertyIndex++; - aliasIndex++; - } - } + + for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; + s = obj->dynamicSignals.next(s)) { + + if (s->nameIndex == -1) continue; + + char *myData = cStringData + s->nameIndex; + for (int ii = 0; ii < s->name.length(); ++ii) + *myData++ = s->name.at(ii).unicode(); } } - // Reserve default property - QFastMetaBuilder::StringRef defPropRef; - if (defaultProperty) { - defPropRef = builder.newString(int(sizeof("DefaultProperty")) - 1); - builder.setClassInfo(0, defPropRef, defaultProperty->nameRef); + QByteArray dynamicData; + typedef QQmlVMEMetaData VMD; + + dynamicData = QByteArray(sizeof(QQmlVMEMetaData) + + obj->dynamicProperties.count() * sizeof(VMD::PropertyData) + + obj->dynamicSlots.count() * sizeof(VMD::MethodData) + + aliasCount * sizeof(VMD::AliasData), 0); + + int effectivePropertyIndex = cache->propertyIndexCacheStart; + int effectiveMethodIndex = cache->methodIndexCacheStart; + + // First set up notify signals for properties - first normal, then var, then alias + enum { NSS_Normal = 0, NSS_Var = 1, NSS_Alias = 2 }; + for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias + + if (ii == NSS_Var && varPropCount == 0) continue; + else if (ii == NSS_Alias && aliasCount == 0) continue; + + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; + p = obj->dynamicProperties.next(p)) { + + if ((ii == NSS_Normal && (p->type == Object::DynamicProperty::Alias || + p->type == Object::DynamicProperty::Var)) || + ((ii == NSS_Var) && (p->type != Object::DynamicProperty::Var)) || + ((ii == NSS_Alias) && (p->type != Object::DynamicProperty::Alias))) + continue; + + quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | + QQmlPropertyData::IsVMESignal; + + if (p->nameIndex != -1) { + QHashedCStringRef changedSignalName(cStringData + p->nameIndex, + p->name.length() + 7 /* strlen("Changed") */); + cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++); + } else { + QString changedSignalName = p->name.toString() + QLatin1String("Changed"); + + cache->appendSignal(changedSignalName, flags, effectiveMethodIndex++); + } + } } - // Reserve dynamic signals - int signalIndex = 0; + // Dynamic signals for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { + int paramCount = s->parameterNames.count(); - s->nameRef = builder.newString(s->name.utf8length()); + QList<QByteArray> names; + QVarLengthArray<int, 10> paramTypes(paramCount?(paramCount + 1):0); - int paramCount = s->parameterNames.count(); - QVarLengthArray<int, 10> paramTypes(paramCount); if (paramCount) { - s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount); + paramTypes[0] = paramCount; + for (int i = 0; i < paramCount; ++i) { - s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).utf8length()); Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount); - paramTypes[i] = builtinTypes[s->parameterTypes.at(i)].metaType; + paramTypes[i + 1] = builtinTypes[s->parameterTypes.at(i)].metaType; + names.append(s->parameterNames.at(i).toString().toUtf8()); } } - if (buildData) - ((QQmlVMEMetaData *)dynamicData.data())->signalCount++; - - builder.setSignal(signalIndex + obj->dynamicProperties.count(), s->nameRef, - paramIndex, paramCount, paramTypes.constData(), s->parameterNamesRef.data()); - paramIndex += paramCount*2 + 1; - ++signalIndex; + ((QQmlVMEMetaData *)dynamicData.data())->signalCount++; + + quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction | + QQmlPropertyData::IsVMESignal; + if (paramCount) + flags |= QQmlPropertyData::HasArguments; + + if (s->nameIndex != -1) { + QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash()); + cache->appendSignal(name, flags, effectiveMethodIndex++, + paramCount?paramTypes.constData():0, names); + } else { + QString name = s->name.toString(); + cache->appendSignal(name, flags, effectiveMethodIndex++, + paramCount?paramTypes.constData():0, names); + } } - // Reserve dynamic slots - if (obj->dynamicSlots.count()) { - typedef QQmlVMEMetaData VMD; + // Dynamic slots + for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { + int paramCount = s->parameterNames.count(); - int methodIndex = 0; - for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { - s->nameRef = builder.newString(s->name.utf8length()); - int paramCount = s->parameterNames.count(); - - QVarLengthArray<int, 10> paramTypes(paramCount); - if (paramCount) { - s->parameterNamesRef = pool->NewRawList<QFastMetaBuilder::StringRef>(paramCount); - for (int i = 0; i < paramCount; ++i) { - s->parameterNamesRef[i] = builder.newString(s->parameterNames.at(i).size()); - paramTypes[i] = QMetaType::QVariant; - } - } + quint32 flags = QQmlPropertyData::IsFunction | QQmlPropertyData::IsVMEFunction; - builder.setMethod(methodIndex, s->nameRef, paramIndex, paramCount, - paramTypes.constData(), s->parameterNamesRef.data(), QMetaType::QVariant); - paramIndex += paramCount*2 + 1; - - if (buildData) { - QString funcScript; - int namesSize = 0; - if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */); - funcScript.reserve(int(sizeof("(function ")) - 1 + s->name.length() + 1 /* lparen */ + - namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */); - funcScript = QLatin1String("(function ") + s->name.toString() + 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(')'); + if (paramCount) + flags |= QQmlPropertyData::HasArguments; - QByteArray utf8 = funcScript.toUtf8(); - VMD::MethodData methodData = { s->parameterNames.count(), 0, - utf8.length(), - s->location.start.line }; + if (s->nameIndex != -1) { + QHashedCStringRef name(cStringData + s->nameIndex, s->name.length(), s->name.hash()); + cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames); + } else { + QString name = s->name.toString(); + cache->appendMethod(name, flags, effectiveMethodIndex++, s->parameterNames); + } + } - VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); - vmd->methodCount++; - VMD::MethodData &md = *(vmd->methodData() + methodIndex); - md = methodData; - md.bodyOffset = dynamicData.size(); + // Dynamic properties (except var and aliases) + effectiveMethodIndex = cache->methodIndexCacheStart; + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; + p = obj->dynamicProperties.next(p)) { - dynamicData.append((const char *)utf8.constData(), utf8.length()); - } + if (p->type == Object::DynamicProperty::Alias || + p->type == Object::DynamicProperty::Var) + continue; + int propertyType = 0; + int vmePropertyType = 0; + quint32 propertyFlags = 0; - methodIndex++; - } - } + if (p->type < builtinTypeCount) { + propertyType = builtinTypes[p->type].metaType; + vmePropertyType = propertyType; - // Now allocate properties - for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; p = obj->dynamicProperties.next(p)) { + if (p->type == Object::DynamicProperty::Variant) + propertyFlags |= QQmlPropertyData::IsQVariant; + } else { + Q_ASSERT(p->type == Object::DynamicProperty::CustomList || + p->type == Object::DynamicProperty::Custom); - char *d = p->changedNameRef.data(); - p->name.writeUtf8(d); - strcpy(d + p->name.utf8length(), "Changed"); - p->changedNameRef.loadByteArrayData(); + QQmlType *qmltype = 0; + QString url; + if (!unit->imports().resolveType(p->customType.toString(), &qmltype, &url, 0, 0, 0)) + COMPILE_EXCEPTION(p, tr("Invalid property type")); - if (p->type == Object::DynamicProperty::Alias && !resolveAlias) - continue; + if (!qmltype) { + QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url)); + Q_ASSERT(tdata); + Q_ASSERT(tdata->isComplete()); - p->nameRef.load(p->name); - } + QQmlCompiledData *data = tdata->compiledData(); - // Allocate default property if necessary - if (defaultProperty) - defPropRef.load("DefaultProperty"); + if (p->type == Object::DynamicProperty::Custom) { + propertyType = data->metaTypeId; + vmePropertyType = QMetaType::QObjectStar; + } else { + propertyType = data->listMetaTypeId; + vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >(); + } - // Now allocate signals - for (Object::DynamicSignal *s = obj->dynamicSignals.first(); s; s = obj->dynamicSignals.next(s)) { + tdata->release(); + } else { + if (p->type == Object::DynamicProperty::Custom) { + propertyType = qmltype->typeId(); + vmePropertyType = QMetaType::QObjectStar; + } else { + propertyType = qmltype->qListTypeId(); + vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >(); + } + } - s->nameRef.load(s->name); + if (p->type == Object::DynamicProperty::Custom) + propertyFlags |= QQmlPropertyData::IsQObjectDerived; + else + propertyFlags |= QQmlPropertyData::IsQList; + } - for (int jj = 0; jj < s->parameterNames.count(); ++jj) - s->parameterNamesRef[jj].load(s->parameterNames.at(jj)); - } + if (!p->isReadOnly && p->type != Object::DynamicProperty::CustomList) + propertyFlags |= QQmlPropertyData::IsWritable; - // Now allocate methods - for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { - s->nameRef.load(s->name); + if (p->nameIndex != -1) { + QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(), + p->name.hash()); + if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16(); + cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, + propertyType, effectiveMethodIndex); + } else { + QString propertyName = p->name.toString(); + if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName; + cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, + propertyType, effectiveMethodIndex); + } - for (int jj = 0; jj < s->parameterNames.count(); ++jj) - s->parameterNamesRef[jj].load(s->parameterNames.at(jj).constData()); - } + effectiveMethodIndex++; - // Now allocate class name - classNameRef.load(newClassName); + VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); + (vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType; + vmd->propertyCount++; + } - obj->metadata = builder.toData(); - builder.fromData(&obj->extObject, obj->metatype, obj->metadata); + // Now do var properties + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p && varPropCount; + p = obj->dynamicProperties.next(p)) { - if (mode == IgnoreAliases && aliasCount) - compileState->aliasingObjects.append(obj); + if (p->type != Object::DynamicProperty::Var) + continue; - obj->synthdata = dynamicData; + quint32 propertyFlags = QQmlPropertyData::IsVarProperty; + if (!p->isReadOnly) + propertyFlags |= QQmlPropertyData::IsWritable; + + VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); + (vmd->propertyData() + vmd->propertyCount)->propertyType = QMetaType::QVariant; + vmd->propertyCount++; + ((QQmlVMEMetaData *)dynamicData.data())->varPropertyCount++; + + if (p->nameIndex != -1) { + QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(), + p->name.hash()); + if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16(); + cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, + QMetaType::QVariant, effectiveMethodIndex); + } else { + QString propertyName = p->name.toString(); + if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName; + cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, + QMetaType::QVariant, effectiveMethodIndex); + } - if (obj->synthCache) { - obj->synthCache->release(); - obj->synthCache = 0; + effectiveMethodIndex++; } - if (obj->type != -1) { - QQmlPropertyCache *superCache = output->types[obj->type].createPropertyCache(engine); - QQmlPropertyCache *cache = - superCache->copyAndAppend(engine, &obj->extObject, - QQmlPropertyData::NoFlags, - QQmlPropertyData::IsVMEFunction, - QQmlPropertyData::IsVMESignal); + // Alias property count. Actual data is setup in buildDynamicMetaAliases + ((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount; + + // Dynamic slot data - comes after the property data + for (Object::DynamicSlot *s = obj->dynamicSlots.first(); s; s = obj->dynamicSlots.next(s)) { + int paramCount = s->parameterNames.count(); - // now we modify the flags appropriately for var properties. - int propertyOffset = obj->extObject.propertyOffset(); - QQmlPropertyData *currPropData = 0; - for (int pvi = firstPropertyVarIndex; pvi < totalPropCount; ++pvi) { - currPropData = cache->property(pvi + propertyOffset); - currPropData->setFlags(currPropData->getFlags() | QQmlPropertyData::IsVMEProperty); + QString funcScript; + int namesSize = 0; + if (paramCount) namesSize += s->parameterNamesLength() + (paramCount - 1 /* commas */); + funcScript.reserve(strlen("(function ") + s->name.length() + 1 /* lparen */ + + namesSize + 1 /* rparen */ + s->body.length() + 1 /* rparen */); + funcScript = QLatin1String("(function ") + s->name.toString() + 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(')'); + + QByteArray utf8 = funcScript.toUtf8(); + VMD::MethodData methodData = { s->parameterNames.count(), + dynamicData.size(), + utf8.length(), + s->location.start.line }; + + VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); + VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount); + vmd->methodCount++; + md = methodData; - obj->synthCache = cache; + dynamicData.append((const char *)utf8.constData(), utf8.length()); } + if (aliasCount) + compileState->aliasingObjects.append(obj); + + obj->synthdata = dynamicData; + obj->synthCache = cache; + obj->metatype = cache; + return true; } -bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val) +bool QQmlCompiler::buildDynamicMetaAliases(QQmlScript::Object *obj) { - if (val.isEmpty()) - COMPILE_EXCEPTION(v, tr( "Invalid empty ID")); + Q_ASSERT(obj->synthCache); - QChar ch = val.at(0); - if (ch.isLetter() && !ch.isLower()) - COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter")); + QByteArray &dynamicData = obj->synthdata; - QChar u(QLatin1Char('_')); - if (!ch.isLetter() && ch != u) - COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore")); + QQmlPropertyCache *cache = obj->synthCache; + char *cStringData = cache->_dynamicStringData.data(); - for (int ii = 1; ii < val.count(); ++ii) { - ch = val.at(ii); - if (!ch.isLetterOrNumber() && ch != u) - COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores")); - } + int effectiveMethodIndex = cache->methodIndexCacheStart + cache->propertyIndexCache.count(); + int effectivePropertyIndex = cache->propertyIndexCacheStart + cache->propertyIndexCache.count(); + int effectiveAliasIndex = 0; - if (enginePrivate->v8engine()->illegalNames().contains(val)) - COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property")); + for (Object::DynamicProperty *p = obj->dynamicProperties.first(); p; + p = obj->dynamicProperties.next(p)) { - return true; -} + if (p->type != Object::DynamicProperty::Alias) + continue; -#include <private/qqmljsparser_p.h> + if (!p->defaultValue) + COMPILE_EXCEPTION(obj, tr("No property alias location")); -static QStringList astNodeToStringList(QQmlJS::AST::Node *node) -{ - if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) { - QString name = - static_cast<QQmlJS::AST::IdentifierExpression *>(node)->name.toString(); - return QStringList() << name; - } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) { - QQmlJS::AST::FieldMemberExpression *expr = static_cast<QQmlJS::AST::FieldMemberExpression *>(node); + if (!p->defaultValue->values.isOne() || + p->defaultValue->values.first()->object || + !p->defaultValue->values.first()->value.isScript()) + COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location")); - QStringList rv = astNodeToStringList(expr->base); - if (rv.isEmpty()) - return rv; - rv.append(expr->name.toString()); - return rv; - } - return QStringList(); -} + QQmlJS::AST::Node *node = p->defaultValue->values.first()->value.asAST(); + Q_ASSERT(node); -bool QQmlCompiler::compileAlias(QFastMetaBuilder &builder, - QByteArray &data, - QQmlScript::Object *obj, - int propIndex, int aliasIndex, - Object::DynamicProperty &prop) -{ - Q_ASSERT(!prop.nameRef.isEmpty()); - if (!prop.defaultValue) - COMPILE_EXCEPTION(obj, tr("No property alias location")); + QStringList alias = astNodeToStringList(node); + if (alias.count() < 1 || alias.count() > 3) + COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); - if (!prop.defaultValue->values.isOne() || - prop.defaultValue->values.first()->object || - !prop.defaultValue->values.first()->value.isScript()) - COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + QQmlScript::Object *idObject = compileState->ids.value(alias.at(0)); + if (!idObject) + COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0))); - QQmlJS::AST::Node *node = prop.defaultValue->values.first()->value.asAST(); - if (!node) - COMPILE_EXCEPTION(obj, tr("No property alias location")); // ### Can this happen? + int propIdx = -1; + int notifySignal = -1; + int flags = 0; + int type = 0; + bool writable = false; + bool resettable = false; - QStringList alias = astNodeToStringList(node); + quint32 propertyFlags = QQmlPropertyData::IsAlias; - if (alias.count() < 1 || alias.count() > 3) - COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>")); + if (alias.count() == 2 || alias.count() == 3) { + QQmlPropertyData *property = this->property(idObject, alias.at(1)); - QQmlScript::Object *idObject = compileState->ids.value(alias.at(0)); - if (!idObject) - COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias reference. Unable to find id \"%1\"").arg(alias.at(0))); + if (!property || property->coreIndex > 0xFFFF) + COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location")); - QByteArray typeName; + propIdx = property->coreIndex; + type = property->propType; - int propIdx = -1; - int flags = 0; - int type = 0; - bool writable = false; - bool resettable = false; - if (alias.count() == 2 || alias.count() == 3) { - propIdx = indexOfProperty(idObject, alias.at(1)); + writable = property->isWritable(); + resettable = property->isResettable(); + notifySignal = property->notifyIndex; - if (-1 == propIdx) { - COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); - } else if (propIdx > 0xFFFF) { - COMPILE_EXCEPTION(prop.defaultValue, tr("Alias property exceeds alias bounds")); - } + if (alias.count() == 3) { + QQmlValueType *valueType = enginePrivate->valueTypes[type]; // XXX threadsafe? + if (!valueType) + COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location")); - QMetaProperty aliasProperty = idObject->metaObject()->property(propIdx); - if (!aliasProperty.isScriptable()) - COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + propIdx |= ((unsigned int)type) << 24; + int valueTypeIndex = + valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData()); + if (valueTypeIndex == -1) + COMPILE_EXCEPTION(p->defaultValue, tr("Invalid alias location")); + Q_ASSERT(valueTypeIndex <= 0xFF); - writable = aliasProperty.isWritable() && !prop.isReadOnly; - resettable = aliasProperty.isResettable() && !prop.isReadOnly; + propIdx |= (valueTypeIndex << 16); + if (valueType->metaObject()->property(valueTypeIndex).isEnumType()) + type = QVariant::Int; + else + type = valueType->metaObject()->property(valueTypeIndex).userType(); - type = aliasProperty.userType(); + } else { + if (property->isEnum()) { + type = QVariant::Int; + } else { + // Copy type flags + propertyFlags |= property->getFlags() & QQmlPropertyData::PropTypeFlagMask; - if (alias.count() == 3) { - QQmlValueType *valueType = enginePrivate->valueTypes[aliasProperty.type()]; - if (!valueType) - COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); + if (property->isVarProperty()) + propertyFlags |= QQmlPropertyData::IsQVariant; - propIdx |= ((unsigned int)aliasProperty.type()) << 24; + if (property->isQObject()) + flags |= QML_ALIAS_FLAG_PTR; + } + } + } else { + Q_ASSERT(idObject->type != -1); // How else did it get an id? - int valueTypeIndex = valueType->metaObject()->indexOfProperty(alias.at(2).toUtf8().constData()); - if (valueTypeIndex == -1) - COMPILE_EXCEPTION(prop.defaultValue, tr("Invalid alias location")); - Q_ASSERT(valueTypeIndex <= 0xFF); - - aliasProperty = valueType->metaObject()->property(valueTypeIndex); - propIdx |= (valueTypeIndex << 16); + const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type); + if (ref.type) + type = ref.type->typeId(); + else + type = ref.component->metaTypeId; - // update the property type - type = aliasProperty.userType(); + flags |= QML_ALIAS_FLAG_PTR; + propertyFlags |= QQmlPropertyData::IsQObjectDerived; } - if (aliasProperty.isEnumType()) - typeName = "int"; // Avoid introducing a dependency on the aliased metaobject - else - typeName = aliasProperty.typeName(); - } else { - Q_ASSERT(idObject->type != -1); // How else did it get an id? + QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags, notifySignal }; + + typedef QQmlVMEMetaData VMD; + VMD *vmd = (QQmlVMEMetaData *)dynamicData.data(); + *(vmd->aliasData() + effectiveAliasIndex++) = aliasData; - const QQmlCompiledData::TypeReference &ref = output->types.at(idObject->type); - if (ref.type) - typeName = ref.type->typeName(); + if (!p->isReadOnly && writable) + propertyFlags |= QQmlPropertyData::IsWritable; else - typeName = ref.component->root->className(); + propertyFlags &= ~QQmlPropertyData::IsWritable; - typeName += '*'; + if (resettable) + propertyFlags |= QQmlPropertyData::IsResettable; + else + propertyFlags &= ~QQmlPropertyData::IsResettable; + + if (p->nameIndex != -1) { + QHashedCStringRef propertyName(cStringData + p->nameIndex, p->name.length(), + p->name.hash()); + if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName.toUtf16(); + cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, + type, effectiveMethodIndex++); + } else { + QString propertyName = p->name.toString(); + if (p->isDefaultProperty) cache->_defaultPropertyName = propertyName; + cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++, + type, effectiveMethodIndex++); + } } - if (typeName.endsWith('*')) - flags |= QML_ALIAS_FLAG_PTR; + return true; +} - if (type == QMetaType::UnknownType) { - Q_ASSERT(!typeName.isEmpty()); - type = QMetaType::type(typeName); - Q_ASSERT(type != QMetaType::UnknownType); - Q_ASSERT(type != QMetaType::Void); - } +bool QQmlCompiler::checkValidId(QQmlScript::Value *v, const QString &val) +{ + if (val.isEmpty()) + COMPILE_EXCEPTION(v, tr( "Invalid empty ID")); - QQmlVMEMetaData::AliasData aliasData = { idObject->idIndex, propIdx, flags }; + QChar ch = val.at(0); + if (ch.isLetter() && !ch.isLower()) + COMPILE_EXCEPTION(v, tr( "IDs cannot start with an uppercase letter")); - typedef QQmlVMEMetaData VMD; - VMD *vmd = (QQmlVMEMetaData *)data.data(); - *(vmd->aliasData() + aliasIndex) = aliasData; + QChar u(QLatin1Char('_')); + if (!ch.isLetter() && ch != u) + COMPILE_EXCEPTION(v, tr( "IDs must start with a letter or underscore")); - int propertyFlags = 0; - if (writable) - propertyFlags |= QFastMetaBuilder::Writable; - if (resettable) - propertyFlags |= QFastMetaBuilder::Resettable; + for (int ii = 1; ii < val.count(); ++ii) { + ch = val.at(ii); + if (!ch.isLetterOrNumber() && ch != u) + COMPILE_EXCEPTION(v, tr( "IDs must contain only letters, numbers, and underscores")); + } - builder.setProperty(propIndex, prop.nameRef, type, - (QFastMetaBuilder::PropertyFlag)propertyFlags, - propIndex); + if (enginePrivate->v8engine()->illegalNames().contains(val)) + COMPILE_EXCEPTION(v, tr( "ID illegally masks global JavaScript property")); return true; } @@ -3336,7 +3311,7 @@ bool QQmlCompiler::buildBinding(QQmlScript::Value *value, { Q_ASSERT(prop->index != -1); Q_ASSERT(prop->parent); - Q_ASSERT(prop->parent->metaObject()); + Q_ASSERT(prop->parent->metatype); if (!prop->core.isWritable() && !prop->core.isQList() && !prop->isReadOnlyDeclaration) COMPILE_EXCEPTION(prop, tr("Invalid property assignment: \"%1\" is a read-only property").arg(prop->name().toString())); @@ -3546,8 +3521,7 @@ QQmlCompiler::genValueTypeData(QQmlScript::Property *valueTypeProp, QQmlScript::Property *prop) { typedef QQmlPropertyPrivate QDPP; - return QDPP::saveValueType(prop->parent->metaObject(), prop->index, - enginePrivate->valueTypes[prop->type]->metaObject(), + return QDPP::saveValueType(prop->core, enginePrivate->valueTypes[prop->type]->metaObject(), valueTypeProp->index, engine); } @@ -3558,7 +3532,7 @@ bool QQmlCompiler::completeComponentBuild() for (Object *aliasObject = compileState->aliasingObjects.first(); aliasObject; aliasObject = compileState->aliasingObjects.next(aliasObject)) - COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases)); + COMPILE_CHECK(buildDynamicMetaAliases(aliasObject)); QV4Compiler::Expression expr(unit->imports()); expr.component = compileState->root; @@ -3733,13 +3707,13 @@ void QQmlCompiler::dumpStats() */ bool QQmlCompiler::canCoerce(int to, QQmlScript::Object *from) { - const QMetaObject *toMo = enginePrivate->rawMetaObjectForType(to); - const QMetaObject *fromMo = from->metaObject(); + QQmlPropertyCache *toMo = enginePrivate->rawPropertyCacheForType(to); + QQmlPropertyCache *fromMo = from->metatype; while (fromMo) { - if (QQmlPropertyPrivate::equal(fromMo, toMo)) + if (fromMo == toMo) return true; - fromMo = fromMo->superClass(); + fromMo = fromMo->parent(); } return false; } @@ -3762,8 +3736,7 @@ QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from) if (from->type != -1 && output->types.at(from->type).type) return output->types.at(from->type).type; - // ### Optimize - const QMetaObject *mo = from->metatype; + const QMetaObject *mo = from->metatype->firstCppMetaObject(); QQmlType *type = 0; while (!type && mo) { type = QQmlMetaType::qmlType(mo); @@ -3774,7 +3747,7 @@ QQmlType *QQmlCompiler::toQmlType(QQmlScript::Object *from) QStringList QQmlCompiler::deferredProperties(QQmlScript::Object *obj) { - const QMetaObject *mo = obj->metatype; + const QMetaObject *mo = obj->metatype->firstCppMetaObject(); int idx = mo->indexOfClassInfo("DeferredPropertyNames"); if (idx == -1) @@ -3795,7 +3768,7 @@ QQmlCompiler::property(QQmlScript::Object *object, int index) else if (object->type != -1) cache = output->types[object->type].createPropertyCache(engine); else - cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject()); + cache = object->metatype; return cache->property(index); } @@ -3812,7 +3785,7 @@ QQmlCompiler::property(QQmlScript::Object *object, const QHashedStringRef &name, else if (object->type != -1) cache = output->types[object->type].createPropertyCache(engine); else - cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject()); + cache = object->metatype; QQmlPropertyData *d = cache->property(name); @@ -3841,7 +3814,7 @@ QQmlCompiler::signal(QQmlScript::Object *object, const QHashedStringRef &name, b else if (object->type != -1) cache = output->types[object->type].createPropertyCache(engine); else - cache = QQmlEnginePrivate::get(engine)->cache(object->metaObject()); + cache = object->metatype; QQmlPropertyData *d = cache->property(name); diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h index a326344336..c5d319c0f0 100644 --- a/src/qml/qml/qqmlcompiler_p.h +++ b/src/qml/qml/qqmlcompiler_p.h @@ -76,8 +76,7 @@ class QQmlComponent; class QQmlContext; class QQmlContextData; -class Q_AUTOTEST_EXPORT QQmlCompiledData : public QQmlRefCount, - public QQmlCleanup +class Q_AUTOTEST_EXPORT QQmlCompiledData : public QQmlRefCount, public QQmlCleanup { public: QQmlCompiledData(QQmlEngine *engine); @@ -89,6 +88,10 @@ public: QUrl url; QQmlTypeNameCache *importCache; + int metaTypeId; + int listMetaTypeId; + bool isRegisteredWithEngine; + struct TypeReference { TypeReference() @@ -98,7 +101,6 @@ public: QQmlPropertyCache *typePropertyCache; QQmlCompiledData *component; - const QMetaObject *metaObject() const; QQmlPropertyCache *propertyCache() const; QQmlPropertyCache *createPropertyCache(QQmlEngine *); }; @@ -115,8 +117,6 @@ public: QList<V8Program> programs; - const QMetaObject *root; - QAbstractDynamicMetaObject rootData; QQmlPropertyCache *rootPropertyCache; QList<QString> primitives; QList<QByteArray> datas; @@ -161,8 +161,6 @@ private: void dump(QQmlInstruction *, int idx = -1); QQmlCompiledData(const QQmlCompiledData &other); QQmlCompiledData &operator=(const QQmlCompiledData &other); - QByteArray packData; - int pack(const char *, size_t); int indexForString(const QString &); int indexForByteArray(const QByteArray &); @@ -361,20 +359,16 @@ private: QQmlScript::Object *obj, QQmlScript::Value *value, bool *isAssignment); - enum DynamicMetaMode { IgnoreAliases, ResolveAliases, ForceCreation }; + enum DynamicMetaMode { Normal, ForceCreation }; bool mergeDynamicMetaProperties(QQmlScript::Object *obj); bool buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mode); + bool buildDynamicMetaAliases(QQmlScript::Object *obj); bool checkDynamicMeta(QQmlScript::Object *obj); bool buildBinding(QQmlScript::Value *, QQmlScript::Property *prop, const QQmlCompilerTypes::BindingContext &ctxt); bool buildLiteralBinding(QQmlScript::Value *, QQmlScript::Property *prop, const QQmlCompilerTypes::BindingContext &ctxt); bool buildComponentFromRoot(QQmlScript::Object *obj, const QQmlCompilerTypes::BindingContext &); - bool compileAlias(QFastMetaBuilder &, - QByteArray &data, - QQmlScript::Object *obj, - int propIndex, int aliasIndex, - QQmlScript::Object::DynamicProperty &); bool completeComponentBuild(); bool checkValidId(QQmlScript::Value *, const QString &); diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 352030d246..e3fc083914 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -441,6 +441,8 @@ QQmlEnginePrivate::~QQmlEnginePrivate() delete (*iter)->qobjectApi; delete *iter; } + for (QHash<int, QQmlCompiledData *>::Iterator iter = m_compositeTypes.begin(); iter != m_compositeTypes.end(); ++iter) + iter.value()->isRegisteredWithEngine = false; } void QQmlPrivate::qdeclarativeelement_destructor(QObject *o) @@ -724,7 +726,7 @@ QQmlEngine::~QQmlEngine() void QQmlEngine::clearComponentCache() { Q_D(QQmlEngine); - d->clearCache(); + d->typeLoader.clearCache(); } /*! @@ -742,7 +744,7 @@ void QQmlEngine::clearComponentCache() void QQmlEngine::trimComponentCache() { Q_D(QQmlEngine); - d->trimCache(); + d->typeLoader.trimCache(); } /*! @@ -1403,7 +1405,7 @@ void QQmlData::clearBindingBit(int bit) void QQmlData::setBindingBit(QObject *obj, int bit) { if (bindingBitsSize <= bit) { - int props = obj->metaObject()->propertyCount(); + int props = QQmlMetaObject(obj).propertyCount(); Q_ASSERT(bit < props); int arraySize = (props + 31) / 32; @@ -1878,33 +1880,59 @@ int QQmlEnginePrivate::listType(int t) const return QQmlMetaType::listType(t); } -const QMetaObject *QQmlEnginePrivate::rawMetaObjectForType(int t) const +QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const { Locker locker(this); - QHash<int, const QMetaObject *>::ConstIterator iter = m_compositeTypes.find(t); + QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t); if (iter != m_compositeTypes.end()) { - return *iter; + return QQmlMetaObject((*iter)->rootPropertyCache); } else { QQmlType *type = QQmlMetaType::qmlType(t); - return type?type->baseMetaObject():0; + return QQmlMetaObject(type?type->baseMetaObject():0); } } -const QMetaObject *QQmlEnginePrivate::metaObjectForType(int t) const +QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const { Locker locker(this); - QHash<int, const QMetaObject *>::ConstIterator iter = m_compositeTypes.find(t); + QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.find(t); if (iter != m_compositeTypes.end()) { - return *iter; + return QQmlMetaObject((*iter)->rootPropertyCache); + } else { + QQmlType *type = QQmlMetaType::qmlType(t); + return QQmlMetaObject(type?type->metaObject():0); + } +} + +QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t) +{ + Locker locker(this); + QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t); + if (iter != m_compositeTypes.end()) { + return (*iter)->rootPropertyCache; + } else { + QQmlType *type = QQmlMetaType::qmlType(t); + locker.unlock(); + return type?cache(type->metaObject()):0; + } +} + +QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t) +{ + Locker locker(this); + QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.find(t); + if (iter != m_compositeTypes.end()) { + return (*iter)->rootPropertyCache; } else { QQmlType *type = QQmlMetaType::qmlType(t); - return type?type->metaObject():0; + locker.unlock(); + return type?cache(type->baseMetaObject()):0; } } -void QQmlEnginePrivate::registerCompositeType(const QMetaObject *mo) +void QQmlEnginePrivate::registerCompositeType(QQmlCompiledData *data) { - QByteArray name = mo->className(); + QByteArray name = data->rootPropertyCache->className(); QByteArray ptr = name + '*'; QByteArray lst = "QQmlListProperty<" + name + '>'; @@ -1916,7 +1944,7 @@ void QQmlEnginePrivate::registerCompositeType(const QMetaObject *mo) qMetaTypeConstructHelper<QObject*>, sizeof(QObject*), static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QObject*>::Flags), - mo); + 0); int lst_type = QMetaType::registerNormalizedType(lst, qMetaTypeDeleteHelper<QQmlListProperty<QObject> >, qMetaTypeCreateHelper<QQmlListProperty<QObject> >, @@ -1926,48 +1954,27 @@ void QQmlEnginePrivate::registerCompositeType(const QMetaObject *mo) static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags), static_cast<QMetaObject*>(0)); + data->metaTypeId = ptr_type; + data->listMetaTypeId = lst_type; + data->isRegisteredWithEngine = true; + Locker locker(this); m_qmlLists.insert(lst_type, ptr_type); - m_compositeTypes.insert(ptr_type, mo); + // The QQmlCompiledData is not referenced here, but it is removed from this + // hash in the QQmlCompiledData destructor + m_compositeTypes.insert(ptr_type, data); } -void QQmlEnginePrivate::unregisterCompositeType(const QMetaObject *mo) +void QQmlEnginePrivate::unregisterCompositeType(QQmlCompiledData *data) { - QByteArray name = mo->className(); - - QByteArray ptr = name + '*'; - QByteArray lst = "QQmlListProperty<" + name + '>'; - - int ptr_type = QMetaType::type(ptr.constData()); - int lst_type = QMetaType::type(lst.constData()); + int ptr_type = data->metaTypeId; + int lst_type = data->listMetaTypeId; Locker locker(this); m_qmlLists.remove(lst_type); m_compositeTypes.remove(ptr_type); } -void QQmlEnginePrivate::clearCache() -{ - typeLoader.clearCache(this, &QQmlEnginePrivate::typeUnloaded); -} - -void QQmlEnginePrivate::trimCache() -{ - typeLoader.trimCache(this, &QQmlEnginePrivate::typeUnloaded); -} - -void QQmlEnginePrivate::typeUnloaded(QQmlTypeData *typeData) -{ - if (typeData && typeData->compiledData()) { - const QMetaObject *mo = typeData->compiledData()->root; - if (QQmlPropertyCache *pc = propertyCache.value(mo)) { - propertyCache.remove(mo); - pc->release(); - } - unregisterCompositeType(mo); - } -} - bool QQmlEnginePrivate::isTypeLoaded(const QUrl &url) const { return typeLoader.isTypeLoaded(url); diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 8048e409f9..0631fe09ca 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -237,13 +237,12 @@ public: QQmlMetaType::TypeCategory typeCategory(int) const; bool isList(int) const; int listType(int) const; - const QMetaObject *rawMetaObjectForType(int) const; - const QMetaObject *metaObjectForType(int) const; - void registerCompositeType(const QMetaObject *); - void unregisterCompositeType(const QMetaObject *); - - void clearCache(); - void trimCache(); + QQmlMetaObject rawMetaObjectForType(int) const; + QQmlMetaObject metaObjectForType(int) const; + QQmlPropertyCache *propertyCacheForType(int); + QQmlPropertyCache *rawPropertyCacheForType(int); + void registerCompositeType(QQmlCompiledData *); + void unregisterCompositeType(QQmlCompiledData *); bool isTypeLoaded(const QUrl &url) const; bool isScriptLoaded(const QUrl &url) const; @@ -302,15 +301,13 @@ private: QQmlPropertyCache *createCache(const QMetaObject *); QQmlPropertyCache *createCache(QQmlType *, int, QQmlError &error); - void typeUnloaded(QQmlTypeData *typeData); - // These members must be protected by a QQmlEnginePrivate::Locker as they are required by // the threaded loader. Only access them through their respective accessor methods. QHash<QQmlMetaType::ModuleApi, QQmlMetaType::ModuleApiInstance *> moduleApiInstances; QHash<const QMetaObject *, QQmlPropertyCache *> propertyCache; QHash<QPair<QQmlType *, int>, QQmlPropertyCache *> typePropertyCache; QHash<int, int> m_qmlLists; - QHash<int, const QMetaObject *> m_compositeTypes; + QHash<int, QQmlCompiledData *> m_compositeTypes; QHash<QUrl, QByteArray> debugChangesHash; // These members is protected by the full QQmlEnginePrivate::mutex mutex diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h index 6e233c9fae..3ed7286ed9 100644 --- a/src/qml/qml/qqmlglobal_p.h +++ b/src/qml/qml/qqmlglobal_p.h @@ -44,6 +44,7 @@ #include <private/qtqmlglobal_p.h> #include <QtCore/QObject> +#include <private/qqmlpropertycache_p.h> QT_BEGIN_HEADER @@ -63,32 +64,105 @@ QT_BEGIN_NAMESPACE return status == Yes; \ } -#define FAST_CONNECT(Sender, Signal, Receiver, Method) \ +/*! + Connect \a Signal of \a Sender to \a Method of \a Receiver. \a Signal must be + of type \a SenderType and \a Receiver of type \a ReceiverType. + + Unlike QObject::connect(), this method caches the lookup of the signal and method + indexes. It also does not require lazy QMetaObjects to be built so should be + preferred in all QML code that might interact with QML built objects. + + \code + QQuickTextControl *control; + QQuickTextEdit *textEdit; + qmlobject_connect(control, QQuickTextControl, SIGNAL(updateRequest(QRectF)), + textEdit, QQuickTextEdit, SLOT(updateDocument())); + \endcode +*/ +#define qmlobject_connect(Sender, SenderType, Signal, Receiver, ReceiverType, Method) \ { \ - QObject *sender = (Sender); \ - QObject *receiver = (Receiver); \ + SenderType *sender = (Sender); \ + ReceiverType *receiver = (Receiver); \ const char *signal = (Signal); \ const char *method = (Method); \ static int signalIdx = -1; \ static int methodIdx = -1; \ if (signalIdx < 0) { \ - if (((int)(*signal) - '0') == QSIGNAL_CODE) \ - signalIdx = sender->metaObject()->indexOfSignal(signal+1); \ - else \ - qWarning("FAST_CONNECT: Invalid signal %s. Please make sure you are using the SIGNAL macro.", signal); \ + Q_ASSERT(((int)(*signal) - '0') == QSIGNAL_CODE); \ + signalIdx = SenderType::staticMetaObject.indexOfSignal(signal+1); \ } \ if (methodIdx < 0) { \ int code = ((int)(*method) - '0'); \ + Q_ASSERT(code == QSLOT_CODE || code == QSIGNAL_CODE); \ if (code == QSLOT_CODE) \ - methodIdx = receiver->metaObject()->indexOfSlot(method+1); \ - else if (code == QSIGNAL_CODE) \ - methodIdx = receiver->metaObject()->indexOfSignal(method+1); \ + methodIdx = ReceiverType::staticMetaObject.indexOfSlot(method+1); \ else \ - qWarning("FAST_CONNECT: Invalid method %s. Please make sure you are using the SIGNAL or SLOT macro.", method); \ + methodIdx = ReceiverType::staticMetaObject.indexOfSignal(method+1); \ } \ + Q_ASSERT(signalIdx != -1 && methodIdx != -1); \ QMetaObject::connect(sender, signalIdx, receiver, methodIdx, Qt::DirectConnection); \ } +/*! + Disconnect \a Signal of \a Sender from \a Method of \a Receiver. \a Signal must be + of type \a SenderType and \a Receiver of type \a ReceiverType. + + Unlike QObject::disconnect(), this method caches the lookup of the signal and method + indexes. It also does not require lazy QMetaObjects to be built so should be + preferred in all QML code that might interact with QML built objects. + + \code + QQuickTextControl *control; + QQuickTextEdit *textEdit; + qmlobject_disconnect(control, QQuickTextControl, SIGNAL(updateRequest(QRectF)), + textEdit, QQuickTextEdit, SLOT(updateDocument())); + \endcode +*/ +#define qmlobject_disconnect(Sender, SenderType, Signal, Receiver, ReceiverType, Method) \ +{ \ + SenderType *sender = (Sender); \ + ReceiverType *receiver = (Receiver); \ + const char *signal = (Signal); \ + const char *method = (Method); \ + static int signalIdx = -1; \ + static int methodIdx = -1; \ + if (signalIdx < 0) { \ + Q_ASSERT(((int)(*signal) - '0') == QSIGNAL_CODE); \ + signalIdx = SenderType::staticMetaObject.indexOfSignal(signal+1); \ + } \ + if (methodIdx < 0) { \ + int code = ((int)(*method) - '0'); \ + Q_ASSERT(code == QSLOT_CODE || code == QSIGNAL_CODE); \ + if (code == QSLOT_CODE) \ + methodIdx = ReceiverType::staticMetaObject.indexOfSlot(method+1); \ + else \ + methodIdx = ReceiverType::staticMetaObject.indexOfSignal(method+1); \ + } \ + Q_ASSERT(signalIdx != -1 && methodIdx != -1); \ + QMetaObject::disconnect(sender, signalIdx, receiver, methodIdx); \ +} + +/*! + This method is identical to qobject_cast<T>() except that it does not require lazy + QMetaObjects to be built, so should be preferred in all QML code that might interact + with QML built objects. + + \code + QObject *object; + if (QQuickTextEdit *textEdit = qmlobject_cast<QQuickTextEdit *>(object)) { + // ...Do something... + } + \endcode +*/ +template<class T> +T qmlobject_cast(QObject *object) +{ + if (QQmlMetaObject::canConvert(object, &reinterpret_cast<T>(object)->staticMetaObject)) + return static_cast<T>(object); + else + return 0; +} + bool Q_QML_PRIVATE_EXPORT QQml_isSignalConnected(QObject*, int, int); #define IS_SIGNAL_CONNECTED(Sender, Signal) \ diff --git a/src/qml/qml/qqmlinstruction.cpp b/src/qml/qml/qqmlinstruction.cpp index 5715d7afb2..da5e9aa401 100644 --- a/src/qml/qml/qqmlinstruction.cpp +++ b/src/qml/qml/qqmlinstruction.cpp @@ -85,7 +85,7 @@ void QQmlCompiledData::dump(QQmlInstruction *instr, int idx) qWarning().nospace() << idx << "\t\t" << "CREATE_COMPONENT\t" << instr->createComponent.count; break; case QQmlInstruction::StoreMetaObject: - qWarning().nospace() << idx << "\t\t" << "STORE_META\t\t" << instr->storeMeta.data; + qWarning().nospace() << idx << "\t\t" << "STORE_META\t\t"; break; case QQmlInstruction::StoreFloat: qWarning().nospace() << idx << "\t\t" << "STORE_FLOAT\t\t" << instr->storeFloat.propertyIndex << "\t" << instr->storeFloat.value; diff --git a/src/qml/qml/qqmlinstruction_p.h b/src/qml/qml/qqmlinstruction_p.h index 04f419d9d5..bd279d66d8 100644 --- a/src/qml/qml/qqmlinstruction_p.h +++ b/src/qml/qml/qqmlinstruction_p.h @@ -211,7 +211,6 @@ union QQmlInstruction }; struct instr_storeMeta { QML_INSTR_HEADER - int data; int aliasData; int propertyCache; }; diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp index c3537dac9d..14425f22e5 100644 --- a/src/qml/qml/qqmllist.cpp +++ b/src/qml/qml/qqmllist.cpp @@ -64,7 +64,7 @@ QQmlListReference QQmlListReferencePrivate::init(const QQmlListProperty<QObject> rv.d = new QQmlListReferencePrivate; rv.d->object = prop.object; - rv.d->elementType = p?p->rawMetaObjectForType(listType):QQmlMetaType::qmlType(listType)->baseMetaObject(); + rv.d->elementType = QQmlPropertyPrivate::rawMetaObjectForType(p, listType); rv.d->property = prop; rv.d->propertyType = propType; @@ -205,7 +205,7 @@ to a list. */ const QMetaObject *QQmlListReference::listElementType() const { - if (isValid()) return d->elementType; + if (isValid()) return d->elementType.metaObject(); else return 0; } @@ -262,7 +262,7 @@ bool QQmlListReference::append(QObject *object) const { if (!canAppend()) return false; - if (object && !QQmlPropertyPrivate::canConvert(object->metaObject(), d->elementType)) + if (object && !QQmlMetaObject::canConvert(object, d->elementType)) return false; d->property.append(&d->property, object); diff --git a/src/qml/qml/qqmllist_p.h b/src/qml/qml/qqmllist_p.h index 0fe0ed3d44..e9a613a181 100644 --- a/src/qml/qml/qqmllist_p.h +++ b/src/qml/qml/qqmllist_p.h @@ -55,6 +55,7 @@ #include "qqmllist.h" #include "qqmlguard_p.h" +#include "qqmlpropertycache_p.h" QT_BEGIN_NAMESPACE @@ -66,7 +67,7 @@ public: static QQmlListReference init(const QQmlListProperty<QObject> &, int, QQmlEngine *); QQmlGuard<QObject> object; - const QMetaObject *elementType; + QQmlMetaObject elementType; QQmlListProperty<QObject> property; int propertyType; diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 087fbaa9bf..7af7848ddb 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -337,11 +337,44 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) QString signalName = terminal.mid(2); signalName[0] = signalName.at(0).toLower(); - QMetaMethod method = findSignalByName(currentObject->metaObject(), signalName.toLatin1().constData()); - if (method.isValid()) { - object = currentObject; - core.load(method); - return; + // XXX - this code treats methods as signals + + QQmlData *ddata = QQmlData::get(currentObject, false); + if (ddata && ddata->propertyCache) { + + // Try method + QQmlPropertyData *d = ddata->propertyCache->property(signalName); + while (d && !d->isFunction()) + d = ddata->propertyCache->overrideData(d); + + if (d) { + object = currentObject; + core = *d; + return; + } + + // Try property + if (signalName.endsWith(QLatin1String("Changed"))) { + QString propName = signalName.mid(0, signalName.length() - 7); + QQmlPropertyData *d = ddata->propertyCache->property(propName); + while (d && d->isFunction()) + d = ddata->propertyCache->overrideData(d); + + if (d && d->notifyIndex != -1) { + object = currentObject; + core = *ddata->propertyCache->method(d->notifyIndex); + return; + } + } + + } else { + QMetaMethod method = findSignalByName(currentObject->metaObject(), + signalName.toLatin1().constData()); + if (method.isValid()) { + object = currentObject; + core.load(method); + return; + } } } @@ -735,8 +768,7 @@ QQmlPropertyPrivate::binding(QObject *object, int coreIndex, int valueTypeIndex) QQmlPropertyData *propertyData = data->propertyCache?data->propertyCache->property(coreIndex):0; if (propertyData && propertyData->isAlias()) { - const QQmlVMEMetaObject *vme = - static_cast<const QQmlVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex)); + QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex) || aCoreIndex == -1) @@ -777,8 +809,8 @@ void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex, QQmlPropertyData *propertyData = data->propertyCache?data->propertyCache->property(coreIndex):0; if (propertyData && propertyData->isAlias()) { - const QQmlVMEMetaObject *vme = - static_cast<const QQmlVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex)); + QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); + QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; if (vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) { // This will either be a value type sub-reference or an alias to a value-type sub-reference not both @@ -811,8 +843,7 @@ QQmlPropertyPrivate::setBinding(QObject *object, int coreIndex, int valueTypeInd QQmlPropertyData *propertyData = data->propertyCache?data->propertyCache->property(coreIndex):0; if (propertyData && propertyData->isAlias()) { - const QQmlVMEMetaObject *vme = - static_cast<const QQmlVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex)); + QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) { @@ -871,8 +902,7 @@ QQmlPropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valu QQmlPropertyData *propertyData = data->propertyCache?data->propertyCache->property(coreIndex):0; if (propertyData && propertyData->isAlias()) { - const QQmlVMEMetaObject *vme = - static_cast<const QQmlVMEMetaObject *>(metaObjectForProperty(object->metaObject(), coreIndex)); + QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); QObject *aObject = 0; int aCoreIndex = -1; int aValueTypeIndex = -1; if (!vme->aliasTarget(coreIndex, &aObject, &aCoreIndex, &aValueTypeIndex)) { @@ -988,7 +1018,7 @@ QQmlPropertyPrivate::takeSignalExpression(const QQmlProperty &that, return signalHandler->takeExpression(expr); if (expr) { - QQmlBoundSignal *signal = new QQmlBoundSignal(that.d->object, that.method(), that.d->object, + QQmlBoundSignal *signal = new QQmlBoundSignal(that.d->object, that.index(), that.d->object, expr->context()->engine); signal->takeExpression(expr); } @@ -1096,8 +1126,23 @@ QVariant QQmlPropertyPrivate::readValueProperty() } else { - return object->metaObject()->property(core.coreIndex).read(object.data()); + if (!core.propType) // Unregistered type + return object->metaObject()->property(core.coreIndex).read(object); + + QVariant value; + int status = -1; + void *args[] = { 0, &value, &status }; + if (core.propType == QMetaType::QVariant) { + args[0] = &value; + } else { + value = QVariant(core.propType, (void*)0); + args[0] = value.data(); + } + QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args); + if (core.propType != QMetaType::QVariant && args[0] != value.data()) + return QVariant((QVariant::Type)core.propType, args[0]); + return value; } } @@ -1293,34 +1338,33 @@ bool QQmlPropertyPrivate::write(QObject *object, } else if (property.isQObject()) { - const QMetaObject *valMo = rawMetaObjectForType(enginePriv, value.userType()); + QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, value.userType()); - if (!valMo) + if (valMo.isNull()) return false; QObject *o = *(QObject **)value.constData(); - const QMetaObject *propMo = rawMetaObjectForType(enginePriv, propertyType); + QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType); - if (o) valMo = o->metaObject(); + if (o) valMo = o; - if (canConvert(valMo, propMo)) { + if (QQmlMetaObject::canConvert(valMo, propMo)) { void *args[] = { &o, 0, &status, &flags }; - QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, - args); - } else if (!o && canConvert(propMo, valMo)) { + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, args); + } else if (!o && QQmlMetaObject::canConvert(propMo, valMo)) { // In the case of a null QObject, we assign the null if there is // any change that the null variant type could be up or down cast to // the property type. void *args[] = { &o, 0, &status, &flags }; - QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, - args); + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, args); } else { return false; } } else if (property.isQList()) { - const QMetaObject *listType = 0; + QQmlMetaObject listType; + if (enginePriv) { listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType)); } else { @@ -1328,7 +1372,7 @@ bool QQmlPropertyPrivate::write(QObject *object, if (!type) return false; listType = type->baseMetaObject(); } - if (!listType) return false; + if (listType.isNull()) return false; QQmlListProperty<void> prop; void *args[] = { &prop, 0 }; @@ -1343,7 +1387,7 @@ bool QQmlPropertyPrivate::write(QObject *object, for (int ii = 0; ii < qdlr.count(); ++ii) { QObject *o = qdlr.at(ii); - if (o && !canConvert(o->metaObject(), listType)) + if (o && !QQmlMetaObject::canConvert(o, listType)) o = 0; prop.append(&prop, (void *)o); } @@ -1352,13 +1396,13 @@ bool QQmlPropertyPrivate::write(QObject *object, for (int ii = 0; ii < list.count(); ++ii) { QObject *o = list.at(ii); - if (o && !canConvert(o->metaObject(), listType)) + if (o && !QQmlMetaObject::canConvert(o, listType)) o = 0; prop.append(&prop, (void *)o); } } else { QObject *o = enginePriv?enginePriv->toQObject(value):QQmlMetaType::toQObject(value); - if (o && !canConvert(o->metaObject(), listType)) + if (o && !QQmlMetaObject::canConvert(o, listType)) o = 0; prop.append(&prop, (void *)o); } @@ -1481,7 +1525,7 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, QQmlJavaScriptExpression::DeleteWatcher watcher(expression); QVariant value; - bool isVmeProperty = core.isVMEProperty(); + bool isVarProperty = core.isVarProperty(); if (isUndefined) { } else if (core.isQList()) { @@ -1490,13 +1534,13 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, value = QVariant::fromValue((QObject *)0); } else if (core.propType == qMetaTypeId<QList<QUrl> >()) { value = resolvedUrlSequence(v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context); - } else if (!isVmeProperty && type != qMetaTypeId<QJSValue>()) { + } else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) { value = v8engine->toVariant(result, type); } if (expression->hasError()) { return false; - } else if (isVmeProperty) { + } else if (isVarProperty) { if (!result.IsEmpty() && result->IsFunction() && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) { // we explicitly disallow this case to avoid confusion. Users can still store one @@ -1504,6 +1548,8 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, expression->delayedError()->error.setDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); return false; } + + typedef QQmlVMEMetaObject VMEMO; QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); Q_ASSERT(vmemo); vmemo->setVMEProperty(core.coreIndex, result); @@ -1540,9 +1586,9 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, if (QObject *o = *(QObject **)value.constData()) { valueType = o->metaObject()->className(); - if (const QMetaObject *propertyMetaObject = rawMetaObjectForType(QQmlEnginePrivate::get(engine), type)) { - propertyType = propertyMetaObject->className(); - } + QQmlMetaObject propertyMetaObject = rawMetaObjectForType(QQmlEnginePrivate::get(engine), type); + if (!propertyMetaObject.isNull()) + propertyType = propertyMetaObject.className(); } } else if (value.userType() != QVariant::Invalid) { valueType = QMetaType::typeName(value.userType()); @@ -1563,13 +1609,13 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object, return true; } -const QMetaObject *QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType) +QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engine, int userType) { if (engine) { return engine->rawMetaObjectForType(userType); } else { QQmlType *type = QQmlMetaType::qmlType(userType); - return type?type->baseMetaObject():0; + return QQmlMetaObject(type?type->baseMetaObject():0); } } @@ -1762,14 +1808,13 @@ int QQmlPropertyPrivate::bindingIndex(const QQmlPropertyData &that) } QQmlPropertyData -QQmlPropertyPrivate::saveValueType(const QMetaObject *metaObject, int index, - const QMetaObject *subObject, int subIndex, - QQmlEngine *) +QQmlPropertyPrivate::saveValueType(const QQmlPropertyData &base, + const QMetaObject *subObject, int subIndex, + QQmlEngine *) { QMetaProperty subProp = subObject->property(subIndex); - QQmlPropertyData core; - core.load(metaObject->property(index)); + QQmlPropertyData core = base; core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual); core.valueTypeFlags = QQmlPropertyData::flagsForProperty(subProp); core.valueTypeCoreIndex = subIndex; @@ -1795,31 +1840,6 @@ QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data, } /*! - Returns true if lhs and rhs refer to the same metaobject data -*/ -bool QQmlPropertyPrivate::equal(const QMetaObject *lhs, const QMetaObject *rhs) -{ - return lhs == rhs || (1 && lhs && rhs && lhs->d.stringdata == rhs->d.stringdata); -} - -/*! - Returns true if from inherits to. -*/ -bool QQmlPropertyPrivate::canConvert(const QMetaObject *from, const QMetaObject *to) -{ - if (from && to == &QObject::staticMetaObject) - return true; - - while (from) { - if (equal(from, to)) - return true; - from = from->superClass(); - } - - return false; -} - -/*! Return the signal corresponding to \a name */ QMetaMethod QQmlPropertyPrivate::findSignalByName(const QMetaObject *mo, const QByteArray &name) @@ -1883,17 +1903,8 @@ static inline void flush_vme_signal(const QObject *object, int index) QQmlPropertyData *property = data->propertyCache->method(index); if (property && property->isVMESignal()) { - const QMetaObject *metaObject = object->metaObject(); - int methodOffset = metaObject->methodOffset(); - - while (methodOffset > index) { - metaObject = metaObject->d.superdata; - methodOffset -= QMetaObject_methods(metaObject); - } - - QQmlVMEMetaObject *vme = - static_cast<QQmlVMEMetaObject *>(const_cast<QMetaObject *>(metaObject)); - + QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForMethod(const_cast<QObject *>(object), + index); vme->connectAliasSignal(index); } } @@ -1921,19 +1932,4 @@ void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index) flush_vme_signal(sender, signal_index); } -/*! -Return \a metaObject's [super] meta object that provides data for \a property. -*/ -const QMetaObject *QQmlPropertyPrivate::metaObjectForProperty(const QMetaObject *metaObject, int property) -{ - int propertyOffset = metaObject->propertyOffset(); - - while (propertyOffset > property) { - metaObject = metaObject->d.superdata; - propertyOffset -= QMetaObject_properties(metaObject); - } - - return metaObject; -} - QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h index cba7849ea0..4f0db342c2 100644 --- a/src/qml/qml/qqmlproperty_p.h +++ b/src/qml/qml/qqmlproperty_p.h @@ -101,7 +101,7 @@ public: QVariant readValueProperty(); bool writeValueProperty(const QVariant &, WriteFlags); - static const QMetaObject *rawMetaObjectForType(QQmlEnginePrivate *, int); + static QQmlMetaObject rawMetaObjectForType(QQmlEnginePrivate *, int); static bool writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags); static bool writeValueProperty(QObject *, QQmlEngine *, @@ -122,15 +122,13 @@ public: static QQmlAbstractBinding *binding(QObject *, int coreIndex, int valueTypeIndex /* -1 */); - static QQmlPropertyData saveValueType(const QMetaObject *, int, - const QMetaObject *, int, - QQmlEngine *); + static QQmlPropertyData saveValueType(const QQmlPropertyData &, + const QMetaObject *, int, + QQmlEngine *); static QQmlProperty restore(QObject *, const QQmlPropertyData &, QQmlContextData *); - static bool equal(const QMetaObject *, const QMetaObject *); - static bool canConvert(const QMetaObject *from, const QMetaObject *to); static inline QQmlPropertyPrivate *get(const QQmlProperty &p) { return p.d; } @@ -158,7 +156,6 @@ public: static bool connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, int type = 0, int *types = 0); - static const QMetaObject *metaObjectForProperty(const QMetaObject *, int); static void flushSignal(const QObject *sender, int signal_index); }; diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 491629bc0a..86c0d715af 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -47,6 +47,7 @@ #include <private/qmetaobject_p.h> #include <private/qqmlaccessors_p.h> +#include <private/qmetaobjectbuilder_p.h> #include <QtCore/qdebug.h> @@ -68,6 +69,8 @@ class QQmlPropertyCacheMethodArguments { public: QQmlPropertyCacheMethodArguments *next; + + QList<QByteArray> *names; int arguments[0]; }; @@ -190,6 +193,9 @@ void QQmlPropertyData::load(const QMetaMethod &m) } } + if (m.attributes() & QMetaMethod::Cloned) + flags |= IsCloned; + Q_ASSERT(m.revision() <= Q_INT16_MAX); revision = m.revision(); } @@ -217,6 +223,9 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m) } } + if (m.attributes() & QMetaMethod::Cloned) + flags |= IsCloned; + Q_ASSERT(m.revision() <= Q_INT16_MAX); revision = m.revision(); } @@ -225,8 +234,8 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m) Creates a new empty QQmlPropertyCache. */ QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e) -: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), - signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0) +: engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), + signalHandlerIndexCacheStart(0), _ownMetaObject(false), _metaObject(0), argumentsCache(0) { Q_ASSERT(engine); } @@ -235,8 +244,8 @@ QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e) Creates a new QQmlPropertyCache of \a metaObject. */ QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e, const QMetaObject *metaObject) -: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), - signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0) +: engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), + signalHandlerIndexCacheStart(0), _ownMetaObject(false), _metaObject(0), argumentsCache(0) { Q_ASSERT(engine); Q_ASSERT(metaObject); @@ -251,6 +260,7 @@ QQmlPropertyCache::~QQmlPropertyCache() QQmlPropertyCacheMethodArguments *args = argumentsCache; while (args) { QQmlPropertyCacheMethodArguments *next = args->next; + if (args->names) delete args->names; free(args); args = next; } @@ -258,8 +268,11 @@ QQmlPropertyCache::~QQmlPropertyCache() // We must clear this prior to releasing the parent incase it is a // linked hash stringCache.clear(); - if (parent) parent->release(); - parent = 0; + if (_parent) _parent->release(); + + if (_ownMetaObject) free((void *)_metaObject); + _metaObject = 0; + _parent = 0; engine = 0; } @@ -283,14 +296,15 @@ void QQmlPropertyCache::clear() QQmlPropertyCache *QQmlPropertyCache::copy(int reserve) { QQmlPropertyCache *cache = new QQmlPropertyCache(engine); - cache->parent = this; - cache->parent->addref(); + cache->_parent = this; + cache->_parent->addref(); cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart; cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart; - cache->signalHanderIndexCacheStart = signalHandlerIndexCache.count() + signalHanderIndexCacheStart; + cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.count() + signalHandlerIndexCacheStart; cache->stringCache.linkAndReserve(stringCache, reserve); cache->allowedRevisionCache = allowedRevisionCache; - cache->metaObject = metaObject; + cache->_metaObject = _metaObject; + cache->_defaultPropertyName = _defaultPropertyName; // We specifically do *NOT* copy the constructor @@ -302,6 +316,247 @@ QQmlPropertyCache *QQmlPropertyCache::copy() return copy(0); } +QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(QQmlEngine *, int propertyCount, int methodCount, + int signalCount) +{ + QQmlPropertyCache *rv = copy(propertyCount + methodCount + signalCount); + rv->propertyIndexCache.reserve(propertyCount); + rv->methodIndexCache.reserve(methodCount); + rv->signalHandlerIndexCache.reserve(signalCount); + rv->_metaObject = 0; + + return rv; +} + +void QQmlPropertyCache::appendProperty(const QString &name, + quint32 flags, int coreIndex, int propType, int notifyIndex) +{ + QQmlPropertyData data; + data.propType = propType; + data.coreIndex = coreIndex; + data.notifyIndex = notifyIndex; + data.flags = flags; + + QHashedString string(name); + if (QQmlPropertyData **old = stringCache.value(string)) { + data.overrideIndexIsProperty = !(*old)->isFunction(); + data.overrideIndex = (*old)->coreIndex; + } + + propertyIndexCache.append(data); + + stringCache.insert(string, propertyIndexCache.data() + propertyIndexCache.count() - 1); +} + +void QQmlPropertyCache::appendProperty(const QHashedCStringRef &name, + quint32 flags, int coreIndex, int propType, int notifyIndex) +{ + QQmlPropertyData data; + data.propType = propType; + data.coreIndex = coreIndex; + data.notifyIndex = notifyIndex; + data.flags = flags; + + if (QQmlPropertyData **old = stringCache.value(name)) { + data.overrideIndexIsProperty = !(*old)->isFunction(); + data.overrideIndex = (*old)->coreIndex; + } + + propertyIndexCache.append(data); + + stringCache.insert(name, propertyIndexCache.data() + propertyIndexCache.count() - 1); +} + +void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int coreIndex, + const int *types, const QList<QByteArray> &names) +{ + QQmlPropertyData data; + data.propType = QVariant::Invalid; + data.coreIndex = coreIndex; + data.flags = flags; + data.arguments = 0; + + QQmlPropertyData handler = data; + handler.flags |= QQmlPropertyData::IsSignalHandler; + + if (types) { + int argumentCount = *types; + typedef QQmlPropertyCacheMethodArguments A; + A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int))); + ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int)); + args->names = new QList<QByteArray>(names); + args->next = argumentsCache; + argumentsCache = args; + data.arguments = args; + } + + QString handlerName = QLatin1String("on") + name; + handlerName[2] = handlerName[2].toUpper(); + + QHashedString string(name); + if (QQmlPropertyData **old = stringCache.value(string)) { + data.overrideIndexIsProperty = !(*old)->isFunction(); + data.overrideIndex = (*old)->coreIndex; + } + + methodIndexCache.append(data); + signalHandlerIndexCache.append(handler); + + stringCache.insert(string, methodIndexCache.data() + methodIndexCache.count() - 1); + stringCache.insert(handlerName, signalHandlerIndexCache.data() + signalHandlerIndexCache.count() - 1); +} + +void QQmlPropertyCache::appendSignal(const QHashedCStringRef &name, quint32 flags, int coreIndex, + const int *types, const QList<QByteArray> &names) +{ + QQmlPropertyData data; + data.propType = QVariant::Invalid; + data.coreIndex = coreIndex; + data.flags = flags; + data.arguments = 0; + + QQmlPropertyData handler = data; + handler.flags |= QQmlPropertyData::IsSignalHandler; + + if (types) { + int argumentCount = *types; + typedef QQmlPropertyCacheMethodArguments A; + A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int))); + ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int)); + args->names = new QList<QByteArray>(names); + args->next = argumentsCache; + argumentsCache = args; + data.arguments = args; + } + + QString handlerName = QLatin1String("on") + name.toUtf16(); + handlerName[2] = handlerName[2].toUpper(); + + if (QQmlPropertyData **old = stringCache.value(name)) { + data.overrideIndexIsProperty = !(*old)->isFunction(); + data.overrideIndex = (*old)->coreIndex; + } + + methodIndexCache.append(data); + signalHandlerIndexCache.append(handler); + + stringCache.insert(name, methodIndexCache.data() + methodIndexCache.count() - 1); + stringCache.insert(handlerName, signalHandlerIndexCache.data() + signalHandlerIndexCache.count() - 1); +} + +void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int coreIndex, + const QList<QByteArray> &names) +{ + int argumentCount = names.count(); + + QQmlPropertyData data; + data.propType = QMetaType::QVariant; + data.coreIndex = coreIndex; + + typedef QQmlPropertyCacheMethodArguments A; + A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int))); + args->arguments[0] = argumentCount; + for (int ii = 0; ii < argumentCount; ++ii) + args->arguments[ii + 1] = QMetaType::QVariant; + args->names = 0; + if (argumentCount) + args->names = new QList<QByteArray>(names); + args->next = argumentsCache; + argumentsCache = args; + data.arguments = args; + + data.flags = flags; + + QHashedString string(name); + if (QQmlPropertyData **old = stringCache.value(string)) { + data.overrideIndexIsProperty = !(*old)->isFunction(); + data.overrideIndex = (*old)->coreIndex; + } + + methodIndexCache.append(data); + + stringCache.insert(string, methodIndexCache.data() + methodIndexCache.count() - 1); +} + +void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flags, int coreIndex, + const QList<QByteArray> &names) +{ + int argumentCount = names.count(); + + QQmlPropertyData data; + data.propType = QMetaType::QVariant; + data.coreIndex = coreIndex; + + typedef QQmlPropertyCacheMethodArguments A; + A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int))); + args->arguments[0] = argumentCount; + for (int ii = 0; ii < argumentCount; ++ii) + args->arguments[ii + 1] = QMetaType::QVariant; + args->names = 0; + if (argumentCount) + args->names = new QList<QByteArray>(names); + args->next = argumentsCache; + argumentsCache = args; + data.arguments = args; + + data.flags = flags; + + if (QQmlPropertyData **old = stringCache.value(name)) { + data.overrideIndexIsProperty = !(*old)->isFunction(); + data.overrideIndex = (*old)->coreIndex; + } + + methodIndexCache.append(data); + + stringCache.insert(name, methodIndexCache.data() + methodIndexCache.count() - 1); +} + +// Returns this property cache's metaObject. May be null if it hasn't been created yet. +const QMetaObject *QQmlPropertyCache::metaObject() const +{ + return _metaObject; +} + +// Returns this property cache's metaObject, creating it if necessary. +const QMetaObject *QQmlPropertyCache::createMetaObject() +{ + if (!_metaObject) { + _ownMetaObject = true; + + QMetaObjectBuilder builder; + toMetaObjectBuilder(builder); + builder.setSuperClass(_parent->createMetaObject()); + _metaObject = builder.toMetaObject(); + } + + return _metaObject; +} + +// Returns the name of the default property for this cache +QString QQmlPropertyCache::defaultPropertyName() const +{ + return _defaultPropertyName; +} + +QQmlPropertyData *QQmlPropertyCache::defaultProperty() const +{ + return property(defaultPropertyName()); +} + +QQmlPropertyCache *QQmlPropertyCache::parent() const +{ + return _parent; +} + +// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by +// QML +const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const +{ + while (_parent && (_metaObject == 0 || _ownMetaObject)) + return _parent->firstCppMetaObject(); + return _metaObject; +} + QQmlPropertyCache * QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject, QQmlPropertyData::Flag propertyFlags, @@ -333,14 +588,6 @@ QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObje } void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject, - QQmlPropertyData::Flag propertyFlags, - QQmlPropertyData::Flag methodFlags, - QQmlPropertyData::Flag signalFlags) -{ - append(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags); -} - -void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject, int revision, QQmlPropertyData::Flag propertyFlags, QQmlPropertyData::Flag methodFlags, @@ -349,7 +596,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject Q_UNUSED(revision); Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache - this->metaObject = metaObject; + _metaObject = metaObject; bool dynamicMetaObject = isDynamicMetaObject(metaObject); @@ -370,7 +617,8 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) { hasFastProperty = true; - break; + } else if (0 == qstrcmp(metaObject->classInfo(idx).name(), "DefaultProperty")) { + _defaultPropertyName = QString::fromUtf8(metaObject->classInfo(idx).value()); } } @@ -400,7 +648,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject // update() should have reserved enough space in the vector that this doesn't cause a realloc // and invalidate the stringCache. methodIndexCache.resize(methodCount - methodIndexCacheStart); - signalHandlerIndexCache.resize(signalCount - signalHanderIndexCacheStart); + signalHandlerIndexCache.resize(signalCount - signalHandlerIndexCacheStart); int signalHandlerIndex = signalOffset; for (int ii = methodOffset; ii < methodCount; ++ii) { if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx) @@ -443,7 +691,7 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject data->metaObjectOffset = allowedRevisionCache.count() - 1; if (data->isSignal()) { - sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHanderIndexCacheStart]; + sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart]; *sigdata = *data; sigdata->flags |= QQmlPropertyData::IsSignalHandler; } @@ -572,7 +820,7 @@ void QQmlPropertyCache::updateRecur(QQmlEngine *engine, const QMetaObject *metaO updateRecur(engine, metaObject->superClass()); - append(engine, metaObject); + append(engine, metaObject, -1); } void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject) @@ -589,7 +837,7 @@ void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject int sc = metaObjectSignalCount(metaObject); propertyIndexCache.reserve(pc - propertyIndexCacheStart); methodIndexCache.reserve(mc - methodIndexCacheStart); - signalHandlerIndexCache.reserve(sc - signalHanderIndexCacheStart); + signalHandlerIndexCache.reserve(sc - signalHandlerIndexCacheStart); // Reserve enough space in the stringCache for all properties/methods/signals including those // cached in a parent cache. @@ -605,7 +853,7 @@ QQmlPropertyCache::property(int index) const return 0; if (index < propertyIndexCacheStart) - return parent->property(index); + return _parent->property(index); QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart)); if (rv->notFullyResolved()) resolve(rv); @@ -619,7 +867,7 @@ QQmlPropertyCache::method(int index) const return 0; if (index < methodIndexCacheStart) - return parent->method(index); + return _parent->method(index); QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart)); if (rv->notFullyResolved()) resolve(rv); @@ -711,6 +959,18 @@ static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type) return type; } +QList<QByteArray> QQmlPropertyCache::methodParameterNames(QObject *object, int index) +{ + QQmlData *data = QQmlData::get(object, false); + if (data->propertyCache) { + QQmlPropertyData *p = data->propertyCache->method(index); + if (!p->hasArguments()) + return QList<QByteArray>(); + } + + return object->metaObject()->method(index).parameterNames(); +} + // Returns an array of the arguments for method \a index. The first entry in the array // is the number of arguments. int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, @@ -728,19 +988,21 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count()); while (index < c->methodIndexCacheStart) - c = c->parent; + c = c->_parent; QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart)); if (rv->arguments) return static_cast<A *>(rv->arguments)->arguments; - const QMetaObject *metaObject = object->metaObject(); + const QMetaObject *metaObject = c->createMetaObject(); + Q_ASSERT(metaObject); QMetaMethod m = metaObject->method(index); int argc = m.parameterCount(); A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int))); args->arguments[0] = argc; + args->names = 0; QList<QByteArray> argTypeNames; // Only loaded if needed for (int ii = 0; ii < argc; ++ii) { @@ -800,8 +1062,7 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, } } -QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, - const QString &property) +QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QString &property) { Q_ASSERT(metaObject); @@ -861,24 +1122,21 @@ inline QString qQmlPropertyCacheToString(const QHashedV8String &string) template<typename T> QQmlPropertyData * -qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, - const T &name, QQmlPropertyData &local) +qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name, QQmlPropertyData &local) { QQmlPropertyCache *cache = 0; - if (engine) { - QQmlData *ddata = QQmlData::get(obj); - - if (ddata && ddata->propertyCache) { - cache = ddata->propertyCache; - } else if (engine) { - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); - cache = ep->cache(obj); - if (cache) { - ddata = QQmlData::get(obj, true); - cache->addref(); - ddata->propertyCache = cache; - } + QQmlData *ddata = QQmlData::get(obj, false); + + if (ddata && ddata->propertyCache) { + cache = ddata->propertyCache; + } else if (engine) { + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine); + cache = ep->cache(obj); + if (cache) { + ddata = QQmlData::get(obj, true); + cache->addref(); + ddata->propertyCache = cache; } } @@ -887,8 +1145,7 @@ qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, if (cache) { rv = cache->property(name); } else { - local = qQmlPropertyCacheCreate(obj->metaObject(), - qQmlPropertyCacheToString(name)); + local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name)); if (local.isValid()) rv = &local; } @@ -918,4 +1175,183 @@ bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo) return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject; } +const char *QQmlPropertyCache::className() const +{ + if (!_ownMetaObject && _metaObject) + return _metaObject->className(); + else + return _dynamicClassName.constData(); +} + +void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) +{ + struct Sort { static bool lt(const QPair<QString, QQmlPropertyData *> &lhs, + const QPair<QString, QQmlPropertyData *> &rhs) { + return lhs.second->coreIndex < rhs.second->coreIndex; + } }; + + struct Insert { static void in(QQmlPropertyCache *This, + QList<QPair<QString, QQmlPropertyData *> > &properties, + QList<QPair<QString, QQmlPropertyData *> > &methods, + StringCache::ConstIterator iter, QQmlPropertyData *data) { + if (data->isSignalHandler()) + return; + + if (data->isFunction()) { + if (data->coreIndex < This->methodIndexCacheStart) + return; + + QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data); + // Overrides can cause the entry to already exist + if (!methods.contains(entry)) methods.append(entry); + + QQmlPropertyData *olddata = data; + data = This->overrideData(data); + if (data) Insert::in(This, properties, methods, iter, data); + } else { + if (data->coreIndex < This->propertyIndexCacheStart) + return; + + QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data); + // Overrides can cause the entry to already exist + if (!properties.contains(entry)) properties.append(entry); + + QQmlPropertyData *olddata = data; + data = This->overrideData(data); + if (data) Insert::in(This, properties, methods, iter, data); + } + + } }; + + builder.setClassName(_dynamicClassName); + + QList<QPair<QString, QQmlPropertyData *> > properties; + QList<QPair<QString, QQmlPropertyData *> > methods; + + for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) + Insert::in(this, properties, methods, iter, iter.value()); + + Q_ASSERT(properties.count() == propertyIndexCache.count()); + Q_ASSERT(methods.count() == methodIndexCache.count()); + + qSort(properties.begin(), properties.end(), Sort::lt); + qSort(methods.begin(), methods.end(), Sort::lt); + + for (int ii = 0; ii < properties.count(); ++ii) { + QQmlPropertyData *data = properties.at(ii).second; + + int notifierId = -1; + if (data->notifyIndex != -1) + notifierId = data->notifyIndex - methodIndexCacheStart; + + QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(), + QMetaType::typeName(data->propType), + notifierId); + + property.setReadable(true); + property.setWritable(data->isWritable()); + property.setResettable(data->isResettable()); + } + + for (int ii = 0; ii < methods.count(); ++ii) { + QQmlPropertyData *data = methods.at(ii).second; + + QByteArray returnType; + if (data->propType != 0) + returnType = QMetaType::typeName(data->propType); + + QByteArray signature = methods.at(ii).first.toUtf8() + "("; + + QQmlPropertyCacheMethodArguments *arguments = 0; + if (data->hasArguments()) { + arguments = (QQmlPropertyCacheMethodArguments *)data->arguments; + + for (int ii = 0; ii < arguments->arguments[0]; ++ii) { + if (ii != 0) signature.append(","); + signature.append(QMetaType::typeName(arguments->arguments[1 + ii])); + } + } + + signature.append(")"); + + QMetaMethodBuilder method; + if (data->isSignal()) { + method = builder.addSignal(signature); + } else { + method = builder.addSlot(signature); + } + method.setAccess(QMetaMethod::Protected); + + if (arguments && arguments->names) + method.setParameterNames(*arguments->names); + + if (!returnType.isEmpty()) + method.setReturnType(returnType); + } + + if (!_defaultPropertyName.isEmpty()) { + QQmlPropertyData *dp = property(_defaultPropertyName); + if (dp && dp->coreIndex >= propertyIndexCacheStart) { + Q_ASSERT(!dp->isFunction()); + builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8()); + } + } +} + +// Returns true if \a from is assignable to a property of type \a to +bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to) +{ + Q_ASSERT(!from.isNull() && !to.isNull()); + + struct I { static bool equal(const QMetaObject *lhs, const QMetaObject *rhs) { + return lhs == rhs || (lhs && rhs && lhs->d.stringdata == rhs->d.stringdata); + } }; + + const QMetaObject *tom = to._m.isT1()?to._m.asT1()->metaObject():to._m.asT2(); + if (tom == &QObject::staticMetaObject) return true; + + if (from._m.isT1() && to._m.isT1()) { // QQmlPropertyCache -> QQmlPropertyCache + QQmlPropertyCache *fromp = from._m.asT1(); + QQmlPropertyCache *top = to._m.asT1(); + + while (fromp) { + if (fromp == top) return true; + fromp = fromp->parent(); + } + } else if (from._m.isT1() && to._m.isT2()) { // QQmlPropertyCache -> QMetaObject + QQmlPropertyCache *fromp = from._m.asT1(); + + while (fromp) { + const QMetaObject *fromm = fromp->metaObject(); + if (fromm && I::equal(fromm, tom)) return true; + fromp = fromp->parent(); + } + } else if (from._m.isT2() && to._m.isT1()) { // QMetaObject -> QQmlPropertyCache + const QMetaObject *fromm = from._m.asT2(); + + if (!tom) return false; + + while (fromm) { + if (I::equal(fromm, tom)) return true; + fromm = fromm->superClass(); + } + } else { // QMetaObject -> QMetaObject + const QMetaObject *fromm = from._m.asT2(); + + while (fromm) { + if (I::equal(fromm, tom)) return true; + fromm = fromm->superClass(); + } + } + + return false; +} + +QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const +{ + if (_m.isNull()) return 0; + if (_m.isT1()) return _m.asT1(); + else return e->cache(_m.asT2()); +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 98322b0275..3be85c7003 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -54,6 +54,7 @@ // #include <private/qqmlrefcount_p.h> +#include <private/qflagpointer_p.h> #include "qqmlcleanup_p.h" #include "qqmlnotifier_p.h" @@ -69,6 +70,7 @@ class QV8QObjectWrapper; class QQmlEngine; class QQmlPropertyData; class QQmlAccessors; +class QMetaObjectBuilder; class QQmlPropertyCacheMethodArguments; // We have this somewhat awful split between RawData and Data so that RawData can be @@ -98,7 +100,7 @@ public: IsQmlBinding = 0x00000800, // Property type is a QQmlBinding* IsQJSValue = 0x00001000, // Property type is a QScriptValue IsV8Handle = 0x00002000, // Property type is a QQmlV8Handle - IsVMEProperty = 0x00004000, // Property type is a "var" property of VMEMO + IsVarProperty = 0x00004000, // Property type is a "var" property of VMEMO IsValueTypeVirtual = 0x00008000, // Property is a value type "virtual" property IsQVariant = 0x00010000, // Property is a QVariant @@ -110,9 +112,14 @@ public: IsV8Function = 0x00200000, // Function takes QQmlV8Function* args IsSignalHandler = 0x00400000, // Function is a signal handler IsOverload = 0x00800000, // Function is an overload of another function + IsCloned = 0x01000000, // The function was marked as cloned // Internal QQmlPropertyCache flags - NotFullyResolved = 0x01000000 // True if the type data is to be lazily resolved + NotFullyResolved = 0x02000000, // True if the type data is to be lazily resolved + + // Flags that are set based on the propType field + PropTypeFlagMask = IsQObjectDerived | IsEnumType | IsQList | IsQmlBinding | IsQJSValue | + IsV8Handle | IsQVariant, }; Q_DECLARE_FLAGS(Flags, Flag) @@ -135,7 +142,7 @@ public: bool isQmlBinding() const { return flags & IsQmlBinding; } bool isQJSValue() const { return flags & IsQJSValue; } bool isV8Handle() const { return flags & IsV8Handle; } - bool isVMEProperty() const { return flags & IsVMEProperty; } + bool isVarProperty() const { return flags & IsVarProperty; } bool isValueTypeVirtual() const { return flags & IsValueTypeVirtual; } bool isQVariant() const { return flags & IsQVariant; } bool isVMEFunction() const { return flags & IsVMEFunction; } @@ -145,6 +152,7 @@ public: bool isV8Function() const { return flags & IsV8Function; } bool isSignalHandler() const { return flags & IsSignalHandler; } bool isOverload() const { return flags & IsOverload; } + bool isCloned() const { return flags & IsCloned; } bool hasOverride() const { return !(flags & IsValueTypeVirtual) && !(flags & HasAccessors) && @@ -243,14 +251,24 @@ public: QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags, QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags); - void append(QQmlEngine *, const QMetaObject *, - QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags, - QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags, - QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags); - void append(QQmlEngine *, const QMetaObject *, int revision, - QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags, - QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags, - QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags); + QQmlPropertyCache *copyAndReserve(QQmlEngine *, int propertyCount, + int methodCount, int signalCount); + void appendProperty(const QString &, + quint32 flags, int coreIndex, int propType, int notifyIndex); + void appendProperty(const QHashedCStringRef &, + quint32 flags, int coreIndex, int propType, int notifyIndex); + void appendSignal(const QString &, quint32, int coreIndex, const int *types = 0, + const QList<QByteArray> &names = QList<QByteArray>()); + void appendSignal(const QHashedCStringRef &, quint32, int coreIndex, const int *types = 0, + const QList<QByteArray> &names = QList<QByteArray>()); + void appendMethod(const QString &, quint32 flags, int coreIndex, + const QList<QByteArray> &names = QList<QByteArray>()); + void appendMethod(const QHashedCStringRef &, quint32 flags, int coreIndex, + const QList<QByteArray> &names = QList<QByteArray>()); + + const QMetaObject *metaObject() const; + const QMetaObject *createMetaObject(); + const QMetaObject *firstCppMetaObject() const; inline QQmlPropertyData *property(const QHashedV8String &) const; QQmlPropertyData *property(const QHashedStringRef &) const; @@ -260,6 +278,10 @@ public: QQmlPropertyData *method(int) const; QStringList propertyNames() const; + QString defaultPropertyName() const; + QQmlPropertyData *defaultProperty() const; + QQmlPropertyCache *parent() const; + inline QQmlPropertyData *overrideData(QQmlPropertyData *) const; inline bool isAllowedInRevision(QQmlPropertyData *) const; @@ -270,8 +292,21 @@ public: QQmlPropertyData &); static int *methodParameterTypes(QObject *, int index, QVarLengthArray<int, 9> &dummy, QByteArray *unknownTypeError); + static QList<QByteArray> methodParameterNames(QObject *, int index); + + const char *className() const; + + inline int propertyCount() const; + inline int propertyOffset() const; + inline int methodCount() const; + inline int methodOffset() const; + inline int signalCount() const; + inline int signalOffset() const; static bool isDynamicMetaObject(const QMetaObject *); + + void toMetaObjectBuilder(QMetaObjectBuilder &); + protected: virtual void destroy(); virtual void clear(); @@ -279,9 +314,15 @@ protected: private: friend class QQmlEnginePrivate; friend class QV8QObjectWrapper; + friend class QQmlCompiler; inline QQmlPropertyCache *copy(int reserve); + void append(QQmlEngine *, const QMetaObject *, int revision, + QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags, + QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags, + QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags); + // Implemented in v8/qv8qobjectwrapper.cpp v8::Local<v8::Object> newQObject(QObject *, QV8Engine *); @@ -293,11 +334,11 @@ private: void updateRecur(QQmlEngine *, const QMetaObject *); QQmlEngine *engine; - - QQmlPropertyCache *parent; + + QQmlPropertyCache *_parent; int propertyIndexCacheStart; int methodIndexCacheStart; - int signalHanderIndexCacheStart; + int signalHandlerIndexCacheStart; IndexCache propertyIndexCache; IndexCache methodIndexCache; @@ -306,9 +347,47 @@ private: AllowedRevisionCache allowedRevisionCache; v8::Persistent<v8::Function> constructor; - const QMetaObject *metaObject; + bool _ownMetaObject; + const QMetaObject *_metaObject; + QByteArray _dynamicClassName; + QByteArray _dynamicStringData; + QString _defaultPropertyName; QQmlPropertyCacheMethodArguments *argumentsCache; }; + +// QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache. +// This is necessary as we delay creation of QMetaObject for synthesized QObjects, but +// we don't want to needlessly generate QQmlPropertyCaches every time we encounter a +// QObject type used in assignment or when we don't have a QQmlEngine etc. +// +// This class does NOT reference the propertycache. +class QQmlEnginePrivate; +class Q_QML_EXPORT QQmlMetaObject +{ +public: + inline QQmlMetaObject(); + inline QQmlMetaObject(QObject *); + inline QQmlMetaObject(const QMetaObject *); + inline QQmlMetaObject(QQmlPropertyCache *); + inline QQmlMetaObject(const QQmlMetaObject &); + + inline QQmlMetaObject &operator=(const QQmlMetaObject &); + + inline bool isNull() const; + + inline const char *className() const; + inline int propertyCount() const; + + inline bool hasMetaObject() const; + inline const QMetaObject *metaObject() const; + + QQmlPropertyCache *propertyCache(QQmlEnginePrivate *) const; + + static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to); + +private: + QBiPointer<QQmlPropertyCache, const QMetaObject> _m; +}; QQmlPropertyData::QQmlPropertyData() { @@ -379,6 +458,109 @@ QQmlPropertyData *QQmlPropertyCache::property(const QHashedV8String &str) const return rv?*rv:0; } +int QQmlPropertyCache::propertyCount() const +{ + return propertyIndexCacheStart + propertyIndexCache.count(); +} + +int QQmlPropertyCache::propertyOffset() const +{ + return propertyIndexCacheStart; +} + +int QQmlPropertyCache::methodCount() const +{ + return methodIndexCacheStart + methodIndexCache.count(); +} + +int QQmlPropertyCache::methodOffset() const +{ + return methodIndexCacheStart; +} + +int QQmlPropertyCache::signalCount() const +{ + return signalHandlerIndexCacheStart + signalHandlerIndexCache.count(); +} + +int QQmlPropertyCache::signalOffset() const +{ + return signalHandlerIndexCacheStart; +} + +QQmlMetaObject::QQmlMetaObject() +{ +} + +QQmlMetaObject::QQmlMetaObject(QObject *o) +{ + if (o) { + QQmlData *ddata = QQmlData::get(o, false); + if (ddata && ddata->propertyCache) _m = ddata->propertyCache; + else _m = o->metaObject(); + } +} + +QQmlMetaObject::QQmlMetaObject(const QMetaObject *m) +: _m(m) +{ +} + +QQmlMetaObject::QQmlMetaObject(QQmlPropertyCache *m) +: _m(m) +{ +} + +QQmlMetaObject::QQmlMetaObject(const QQmlMetaObject &o) +: _m(o._m) +{ +} + +QQmlMetaObject &QQmlMetaObject::operator=(const QQmlMetaObject &o) +{ + _m = o._m; + return *this; +} + +bool QQmlMetaObject::isNull() const +{ + return _m.isNull(); +} + +const char *QQmlMetaObject::className() const +{ + if (_m.isNull()) { + return 0; + } else if (_m.isT1()) { + return _m.asT1()->className(); + } else { + return _m.asT2()->className(); + } +} + +int QQmlMetaObject::propertyCount() const +{ + if (_m.isNull()) { + return 0; + } else if (_m.isT1()) { + return _m.asT1()->propertyCount(); + } else { + return _m.asT2()->propertyCount(); + } +} + +bool QQmlMetaObject::hasMetaObject() const +{ + return _m.isT2() || (!_m.isNull() && _m.asT1()->metaObject()); +} + +const QMetaObject *QQmlMetaObject::metaObject() const +{ + if (_m.isNull()) return 0; + if (_m.isT1()) return _m.asT1()->createMetaObject(); + else return _m.asT2(); +} + QT_END_NAMESPACE #endif // QQMLPROPERTYCACHE_P_H diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp index 555eb44e0b..cd32c0d8f8 100644 --- a/src/qml/qml/qqmlscript.cpp +++ b/src/qml/qml/qqmlscript.cpp @@ -63,16 +63,10 @@ using namespace QQmlScript; // Parser IR classes // QQmlScript::Object::Object() -: type(-1), typeReference(0), idIndex(-1), metatype(0), synthCache(0), defaultProperty(0), - parserStatusCast(-1), componentCompileState(0), nextAliasingObject(0), nextIdObject(0) +: type(-1), typeReference(0), idIndex(-1), metatype(0), synthCache(0), + defaultProperty(0), parserStatusCast(-1), componentCompileState(0), nextAliasingObject(0), + nextIdObject(0) { - // initialize the members in the meta object - extObject.d.superdata = 0; - extObject.d.stringdata = 0; - extObject.d.data = 0; - extObject.d.extradata = 0; - extObject.d.static_metacall = 0; - extObject.d.relatedMetaObjects = 0; } QQmlScript::Object::~Object() @@ -89,14 +83,6 @@ void Object::setBindingBit(int b) bits[b / 32] |= (1 << (b % 32)); } -const QMetaObject *Object::metaObject() const -{ - if (!metadata.isEmpty() && metatype) - return &extObject; - else - return metatype; -} - QQmlScript::Property *Object::getDefaultProperty() { if (!defaultProperty) { @@ -206,17 +192,18 @@ int QQmlScript::Object::aggregateDynamicSlotParameterCount() const } QQmlScript::Object::DynamicProperty::DynamicProperty() -: isDefaultProperty(false), isReadOnly(false), type(Variant), defaultValue(0), nextProperty(0) +: isDefaultProperty(false), isReadOnly(false), type(Variant), defaultValue(0), nextProperty(0), + nameIndex(-1) { } QQmlScript::Object::DynamicSignal::DynamicSignal() -: nextSignal(0) +: nextSignal(0), nameIndex(-1) { } QQmlScript::Object::DynamicSlot::DynamicSlot() -: nextSlot(0) +: nextSlot(0), nameIndex(-1) { } diff --git a/src/qml/qml/qqmlscript_p.h b/src/qml/qml/qqmlscript_p.h index daf9fdce14..486c573754 100644 --- a/src/qml/qml/qqmlscript_p.h +++ b/src/qml/qml/qqmlscript_p.h @@ -56,7 +56,6 @@ #include <private/qfieldlist_p.h> #include <private/qhashfield_p.h> -#include <private/qfastmetabuilder_p.h> #include <private/qqmlpool_p.h> #include <private/qqmlpropertycache_p.h> @@ -320,17 +319,12 @@ public: // Bit mask of the properties assigned bindings QByteArray bindingBitmask; void setBindingBit(int); - // Returns the metaobject for this type, or 0 if not available. - // Internally selectd between the metatype and extObject variables - const QMetaObject *metaObject() const; - // The compile time metaobject for this type - const QMetaObject *metatype; + QQmlPropertyCache *metatype; + // The synthesized metaobject, if QML added signals or properties to // this type. Otherwise null - QAbstractDynamicMetaObject extObject; - QByteArray metadata; // Generated by compiler - QByteArray synthdata; // Generated by compiler + QByteArray synthdata; // Generated by compiler QQmlPropertyCache *synthCache; // Generated by compiler Property *getDefaultProperty(); @@ -404,8 +398,7 @@ public: DynamicProperty *nextProperty; // Used by the compiler - QFastMetaBuilder::StringRef nameRef; - QFastMetaBuilder::StringRef changedNameRef; + int nameIndex; // Points at the name and name + "Changed()" strings }; struct DynamicSignal : public QQmlPool::POD @@ -420,8 +413,7 @@ public: DynamicSignal *nextSignal; // Used by the compiler - QFastMetaBuilder::StringRef nameRef; - QQmlPool::List<QFastMetaBuilder::StringRef> parameterNamesRef; + int nameIndex; LocationSpan location; }; @@ -440,8 +432,7 @@ public: DynamicSlot *nextSlot; // Used by the compiler - QFastMetaBuilder::StringRef nameRef; - QQmlPool::List<QFastMetaBuilder::StringRef> parameterNamesRef; + int nameIndex; }; // The list of dynamic properties diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index f76ded631c..97b8634f39 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1215,7 +1215,7 @@ loaded files. */ QQmlTypeLoader::~QQmlTypeLoader() { - clearCache(0, 0); + clearCache(); } /*! @@ -1563,12 +1563,9 @@ const QQmlDirParser *QQmlTypeLoader::qmlDirParser(const QString &filePath, Clears cached information about loaded files, including any type data, scripts and qmldir information. */ -void QQmlTypeLoader::clearCache(void (*callback)(void *, QQmlTypeData *), void *arg) +void QQmlTypeLoader::clearCache() { for (TypeCache::Iterator iter = m_typeCache.begin(); iter != m_typeCache.end(); ++iter) { - if (callback) - (*callback)(arg, iter.value()); - (*iter)->release(); } for (ScriptCache::Iterator iter = m_scriptCache.begin(); iter != m_scriptCache.end(); ++iter) @@ -1585,7 +1582,7 @@ void QQmlTypeLoader::clearCache(void (*callback)(void *, QQmlTypeData *), void * m_importQmlDirCache.clear(); } -void QQmlTypeLoader::trimCache(void (*callback)(void *, QQmlTypeData *), void *arg) +void QQmlTypeLoader::trimCache() { while (true) { QList<TypeCache::Iterator> unneededTypes; @@ -1604,11 +1601,8 @@ void QQmlTypeLoader::trimCache(void (*callback)(void *, QQmlTypeData *), void *a TypeCache::Iterator iter = unneededTypes.last(); unneededTypes.removeLast(); - QQmlTypeData *typeData = iter.value(); - if (callback) - (*callback)(arg, typeData); + iter.value()->release(); m_typeCache.erase(iter); - typeData->release(); } } diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index a795d3c816..b16421a8ee 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -279,17 +279,8 @@ public: bool directoryExists(const QString &path); const QQmlDirParser *qmlDirParser(const QString &filePath, const QString &uriHint, QString *outUrl); - template<typename T> - void clearCache(T *o, void (T::*callback)(QQmlTypeData *)) { - TypedCallback<T> cb(o, callback); - clearCache(&TypedCallback<T>::redirect, &cb); - } - - template<typename T> - void trimCache(T *o, void (T::*callback)(QQmlTypeData *)) { - TypedCallback<T> cb(o, callback); - trimCache(&TypedCallback<T>::redirect, &cb); - } + void clearCache(); + void trimCache(); bool isTypeLoaded(const QUrl &url) const; bool isScriptLoaded(const QUrl &url) const; @@ -314,9 +305,6 @@ private: void (T::*mf)(QQmlTypeData *); }; - void clearCache(void (*callback)(void *, QQmlTypeData *), void *); - void trimCache(void (*callback)(void *, QQmlTypeData *), void *); - struct DirParser : public QQmlDirParser { QString adjustedUrl; }; typedef QHash<QUrl, QQmlTypeData *> TypeCache; diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp index 1665342ffd..c09971bede 100644 --- a/src/qml/qml/qqmlvme.cpp +++ b/src/qml/qml/qqmlvme.cpp @@ -45,7 +45,6 @@ #include "qqmlboundsignal_p.h" #include "qqmlstringconverters_p.h" #include <private/qmetaobjectbuilder_p.h> -#include <private/qfastmetabuilder_p.h> #include "qqmldata_p.h" #include "qqml.h" #include "qqmlcustomparser_p.h" @@ -691,21 +690,18 @@ QObject *QQmlVME::run(QList<QQmlError> *errors, QML_BEGIN_INSTR(StoreMetaObject) QObject *target = objects.top(); - QMetaObject mo; - const QByteArray &metadata = DATAS.at(instr.data); - QFastMetaBuilder::fromData(&mo, 0, metadata); + QQmlPropertyCache *propertyCache = PROPERTYCACHES.at(instr.propertyCache); const QQmlVMEMetaData *data = (const QQmlVMEMetaData *)DATAS.at(instr.aliasData).constData(); - (void)new QQmlVMEMetaObject(target, &mo, data); + (void)new QQmlVMEMetaObject(target, propertyCache, data); + + QQmlData *ddata = QQmlData::get(target, true); + if (ddata->propertyCache) ddata->propertyCache->release(); + ddata->propertyCache = propertyCache; + ddata->propertyCache->addref(); - if (instr.propertyCache != -1) { - QQmlData *ddata = QQmlData::get(target, true); - if (ddata->propertyCache) ddata->propertyCache->release(); - ddata->propertyCache = PROPERTYCACHES.at(instr.propertyCache); - ddata->propertyCache->addref(); - } QML_END_INSTR(StoreMetaObject) QML_BEGIN_INSTR(AssignCustomType) @@ -761,9 +757,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors, QObject *target = objects.top(); QObject *context = objects.at(objects.count() - 1 - instr.context); - QMetaMethod signal = target->metaObject()->method(instr.signalIndex); - - QQmlBoundSignal *bs = new QQmlBoundSignal(target, signal, target, engine); + QQmlBoundSignal *bs = new QQmlBoundSignal(target, instr.signalIndex, target, engine); QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(CTXT, context, DATAS.at(instr.value), true, COMP->name, instr.line, instr.column); bs->takeExpression(expr); diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 77a0482edf..e0d797269c 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -69,7 +69,7 @@ QQmlVMEVariantQObjectPtr::~QQmlVMEVariantQObjectPtr() void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *) { if (m_target && m_index >= 0) - m_target->activate(m_target->object, m_target->methodOffset + m_index, 0); + m_target->activate(m_target->object, m_target->methodOffset() + m_index, 0); } void QQmlVMEVariantQObjectPtr::setGuardedValue(QObject *obj, QQmlVMEMetaObject *target, int index) @@ -461,8 +461,8 @@ void QQmlVMEMetaObjectEndpoint::tryConnect() if (metaObject.flag()) { // This is actually notify - int sigIdx = metaObject->methodOffset + aliasId + metaObject->metaData->propertyCount; - QMetaObject::activate(metaObject->object, sigIdx, 0); + int sigIdx = metaObject->methodOffset() + aliasId + metaObject->metaData->propertyCount; + metaObject->activate(metaObject->object, sigIdx, 0); } else { QQmlVMEMetaData::AliasData *d = metaObject->metaData->aliasData() + aliasId; if (!d->isObjectAlias()) { @@ -471,33 +471,46 @@ void QQmlVMEMetaObjectEndpoint::tryConnect() if (!target) return; - QMetaProperty prop = target->metaObject()->property(d->propertyIndex()); - if (prop.hasNotifySignal()) - connect(target, prop.notifySignalIndex(), ctxt->engine); + if (d->notifySignal != -1) + connect(target, d->notifySignal, ctxt->engine); } metaObject.setFlag(); } } -QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, const QMetaObject *other, const QQmlVMEMetaData *meta) -: QV8GCCallback::Node(GcPrologueCallback), object(obj), - ctxt(QQmlData::get(obj, true)->outerContext), metaData(meta), data(0), - aliasEndpoints(0), firstVarPropertyIndex(-1), varPropertiesInitialized(false), - interceptors(0), v8methods(0), parent(0) +QAbstractDynamicMetaObject *QQmlVMEMetaObject::toDynamicMetaObject(QObject *o) { - *static_cast<QMetaObject *>(this) = *other; - this->d.superdata = obj->metaObject(); + if (!hasAssignedMetaObjectData) { + *static_cast<QMetaObject *>(this) = *cache->createMetaObject(); + + if (parent.isT1()) + this->d.superdata = parent.asT1()->toDynamicMetaObject(o); + else + this->d.superdata = parent.asT2(); + + hasAssignedMetaObjectData = true; + } + + return this; +} +QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, + QQmlPropertyCache *cache, + const QQmlVMEMetaData *meta) +: QV8GCCallback::Node(GcPrologueCallback), object(obj), + ctxt(QQmlData::get(obj, true)->outerContext), cache(cache), metaData(meta), + hasAssignedMetaObjectData(false), data(0), aliasEndpoints(0), firstVarPropertyIndex(-1), + varPropertiesInitialized(false), interceptors(0), v8methods(0) +{ QObjectPrivate *op = QObjectPrivate::get(obj); - if (op->metaObject) - parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject); + + if (op->metaObject) parent = op->metaObject; + else parent = obj->metaObject(); + op->metaObject = this; QQmlData::get(obj)->hasVMEMetaObject = true; - propOffset = QAbstractDynamicMetaObject::propertyOffset(); - methodOffset = QAbstractDynamicMetaObject::methodOffset(); - data = new QQmlVMEVariant[metaData->propertyCount - metaData->varPropertyCount]; aConnected.resize(metaData->aliasCount); @@ -507,7 +520,7 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, const QMetaObject *other, con for (int ii = 0; ii < metaData->propertyCount - metaData->varPropertyCount; ++ii) { int t = (metaData->propertyData() + ii)->propertyType; if (t == list_type) { - listProperties.append(List(methodOffset + ii)); + listProperties.append(List(methodOffset() + ii, this)); data[ii].setValue(listProperties.count() - 1); } } @@ -519,7 +532,7 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, const QMetaObject *other, con QQmlVMEMetaObject::~QQmlVMEMetaObject() { - delete parent; + if (parent.isT1()) parent.asT1()->objectDestroyed(object); delete [] data; delete [] aliasEndpoints; @@ -543,7 +556,7 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) continue; int valueIndex = vi->m_valueTypeCoreIndex; - int type = property(id).userType(); + int type = QQmlData::get(object)->propertyCache->property(id)->propType; if (type != QVariant::Invalid) { if (valueIndex != -1) { @@ -567,8 +580,8 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) } } if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty) { - if (id >= propOffset) { - id -= propOffset; + if (id >= propOffset()) { + id -= propOffset(); if (id < metaData->propertyCount) { int t = (metaData->propertyData() + id)->propertyType; @@ -692,7 +705,7 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) } if (c == QMetaObject::WriteProperty && needActivate) { - activate(object, methodOffset + id, 0); + activate(object, methodOffset() + id, 0); } return -1; @@ -761,13 +774,13 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) } else if(c == QMetaObject::InvokeMetaMethod) { - if (id >= methodOffset) { + if (id >= methodOffset()) { - id -= methodOffset; + id -= methodOffset(); int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; if (id < plainSignals) { - QMetaObject::activate(object, _id, a); + activate(object, _id, a); return -1; } @@ -827,8 +840,8 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) } } - if (parent) - return parent->metaCall(c, _id, a); + if (parent.isT1()) + return parent.asT1()->metaCall(object, c, _id, a); else return object->qt_metacall(c, _id, a); } @@ -912,7 +925,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, v8::Handle<v8::Value> value) // Write the value and emit change signal as appropriate. varProperties->Set(id - firstVarPropertyIndex, value); - activate(object, methodOffset + id, 0); + activate(object, methodOffset() + id, 0); } void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) @@ -945,13 +958,13 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) QVariant currentValue = readPropertyAsVariant(id); varProperties->Set(id - firstVarPropertyIndex, newv); if ((currentValue.userType() != value.userType() || currentValue != value)) - activate(object, methodOffset + id, 0); + activate(object, methodOffset() + id, 0); } else { bool needActivate = false; if (value.userType() == QMetaType::QObjectStar) { - QObject *o = qvariant_cast<QObject *>(value); + QObject *o = *(QObject **)value.data(); needActivate = (data[id].dataType() != QMetaType::QObjectStar || data[id].asQObject() != o); - data[id].setValue(qvariant_cast<QObject *>(value), this, id); + data[id].setValue(o, this, id); } else { needActivate = (data[id].dataType() != qMetaTypeId<QVariant>() || data[id].asQVariant().userType() != value.userType() || @@ -960,20 +973,20 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) } if (needActivate) - activate(object, methodOffset + id, 0); + activate(object, methodOffset() + id, 0); } } void QQmlVMEMetaObject::listChanged(int id) { - activate(object, methodOffset + id, 0); + activate(object, methodOffset() + id, 0); } void QQmlVMEMetaObject::list_append(QQmlListProperty<QObject> *prop, QObject *o) { List *list = static_cast<List *>(prop->data); list->append(o); - QMetaObject::activate(prop->object, list->notifyIndex, 0); + list->mo->activate(prop->object, list->notifyIndex, 0); } int QQmlVMEMetaObject::list_count(QQmlListProperty<QObject> *prop) @@ -990,7 +1003,7 @@ void QQmlVMEMetaObject::list_clear(QQmlListProperty<QObject> *prop) { List *list = static_cast<List *>(prop->data); list->clear(); - QMetaObject::activate(prop->object, list->notifyIndex, 0); + list->mo->activate(prop->object, list->notifyIndex, 0); } void QQmlVMEMetaObject::registerInterceptor(int index, int valueIndex, QQmlPropertyValueInterceptor *interceptor) @@ -1003,15 +1016,15 @@ void QQmlVMEMetaObject::registerInterceptor(int index, int valueIndex, QQmlPrope int QQmlVMEMetaObject::vmeMethodLineNumber(int index) { - if (index < methodOffset) { - Q_ASSERT(parent); - return static_cast<QQmlVMEMetaObject *>(parent)->vmeMethodLineNumber(index); + if (index < methodOffset()) { + Q_ASSERT(parent.isT1()); + return static_cast<QQmlVMEMetaObject *>(parent.asT1())->vmeMethodLineNumber(index); } int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; - Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount)); + Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount)); - int rawIndex = index - methodOffset - plainSignals; + int rawIndex = index - methodOffset() - plainSignals; QQmlVMEMetaData::MethodData *data = metaData->methodData() + rawIndex; return data->lineNumber; @@ -1019,29 +1032,29 @@ int QQmlVMEMetaObject::vmeMethodLineNumber(int index) v8::Handle<v8::Function> QQmlVMEMetaObject::vmeMethod(int index) { - if (index < methodOffset) { - Q_ASSERT(parent); - return static_cast<QQmlVMEMetaObject *>(parent)->vmeMethod(index); + if (index < methodOffset()) { + Q_ASSERT(parent.isT1()); + return static_cast<QQmlVMEMetaObject *>(parent.asT1())->vmeMethod(index); } int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; - Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount)); - return method(index - methodOffset - plainSignals); + Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount)); + return method(index - methodOffset() - plainSignals); } // Used by debugger void QQmlVMEMetaObject::setVmeMethod(int index, v8::Persistent<v8::Function> value) { - if (index < methodOffset) { - Q_ASSERT(parent); - return static_cast<QQmlVMEMetaObject *>(parent)->setVmeMethod(index, value); + if (index < methodOffset()) { + Q_ASSERT(parent.isT1()); + return static_cast<QQmlVMEMetaObject *>(parent.asT1())->setVmeMethod(index, value); } int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; - Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount)); + Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount)); if (!v8methods) v8methods = new v8::Persistent<v8::Function>[metaData->methodCount]; - int methodIndex = index - methodOffset - plainSignals; + int methodIndex = index - methodOffset() - plainSignals; if (!v8methods[methodIndex].IsEmpty()) qPersistentDispose(v8methods[methodIndex]); v8methods[methodIndex] = value; @@ -1049,21 +1062,21 @@ void QQmlVMEMetaObject::setVmeMethod(int index, v8::Persistent<v8::Function> val v8::Handle<v8::Value> QQmlVMEMetaObject::vmeProperty(int index) { - if (index < propOffset) { - Q_ASSERT(parent); - return static_cast<QQmlVMEMetaObject *>(parent)->vmeProperty(index); + if (index < propOffset()) { + Q_ASSERT(parent.isT1()); + return static_cast<QQmlVMEMetaObject *>(parent.asT1())->vmeProperty(index); } - return readVarProperty(index - propOffset); + return readVarProperty(index - propOffset()); } void QQmlVMEMetaObject::setVMEProperty(int index, v8::Handle<v8::Value> v) { - if (index < propOffset) { - Q_ASSERT(parent); - static_cast<QQmlVMEMetaObject *>(parent)->setVMEProperty(index, v); + if (index < propOffset()) { + Q_ASSERT(parent.isT1()); + static_cast<QQmlVMEMetaObject *>(parent.asT1())->setVMEProperty(index, v); return; } - return writeVarProperty(index - propOffset, v); + return writeVarProperty(index - propOffset(), v); } bool QQmlVMEMetaObject::ensureVarPropertiesAllocated() @@ -1116,7 +1129,7 @@ void QQmlVMEMetaObject::GcPrologueCallback(QV8GCCallback::Node *node) bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const { - Q_ASSERT(index >= propOffset + metaData->propertyCount); + Q_ASSERT(index >= propOffset() + metaData->propertyCount); *target = 0; *coreIndex = -1; @@ -1125,7 +1138,7 @@ bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, if (!ctxt) return false; - QQmlVMEMetaData::AliasData *d = metaData->aliasData() + (index - propOffset - metaData->propertyCount); + QQmlVMEMetaData::AliasData *d = metaData->aliasData() + (index - propOffset() - metaData->propertyCount); QQmlContext *context = ctxt->asQQmlContext(); QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context); @@ -1166,11 +1179,39 @@ void QQmlVMEMetaObject::connectAlias(int aliasId) void QQmlVMEMetaObject::connectAliasSignal(int index) { - int aliasId = (index - methodOffset) - metaData->propertyCount; + int aliasId = (index - methodOffset()) - metaData->propertyCount; if (aliasId < 0 || aliasId >= metaData->aliasCount) return; connectAlias(aliasId); } +void QQmlVMEMetaObject::activate(QObject *object, int index, void **args) +{ + int signalOffset = cache->signalOffset(); + int methodOffset = cache->methodOffset(); + + QMetaObject::activate(object, methodOffset, signalOffset, index - methodOffset, args); +} + +QQmlVMEMetaObject *QQmlVMEMetaObject::getForProperty(QObject *o, int coreIndex) +{ + QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o); + while (vme->propOffset() > coreIndex) { + Q_ASSERT(vme->parent.isT1()); + vme = static_cast<QQmlVMEMetaObject *>(vme->parent.asT1()); + } + return vme; +} + +QQmlVMEMetaObject *QQmlVMEMetaObject::getForMethod(QObject *o, int coreIndex) +{ + QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o); + while (vme->methodOffset() > coreIndex) { + Q_ASSERT(vme->parent.isT1()); + vme = static_cast<QQmlVMEMetaObject *>(vme->parent.asT1()); + } + return vme; +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h index c9992471d4..9927de0b43 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -69,6 +69,7 @@ #include "qqmlcontext_p.h" #include <private/qv8engine_p.h> +#include <private/qflagpointer_p.h> #include <private/qv8_p.h> @@ -90,6 +91,7 @@ struct QQmlVMEMetaData int contextIdx; int propertyIdx; int flags; + int notifySignal; bool isObjectAlias() const { return propertyIdx == -1; @@ -156,7 +158,7 @@ class Q_AUTOTEST_EXPORT QQmlVMEMetaObject : public QAbstractDynamicMetaObject, public QV8GCCallback::Node { public: - QQmlVMEMetaObject(QObject *obj, const QMetaObject *other, const QQmlVMEMetaData *data); + QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, const QQmlVMEMetaData *data); ~QQmlVMEMetaObject(); bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const; @@ -169,22 +171,28 @@ public: void connectAliasSignal(int index); - static inline QQmlVMEMetaObject *get(const QObject *obj); + virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *o); + + static inline QQmlVMEMetaObject *get(QObject *o); + static QQmlVMEMetaObject *getForProperty(QObject *o, int coreIndex); + static QQmlVMEMetaObject *getForMethod(QObject *o, int coreIndex); protected: virtual int metaCall(QMetaObject::Call _c, int _id, void **_a); -private: +public: friend class QQmlVMEMetaObjectEndpoint; friend class QQmlVMEVariantQObjectPtr; QObject *object; QQmlGuardedContextData ctxt; + QQmlPropertyCache *cache; const QQmlVMEMetaData *metaData; - int propOffset; - int methodOffset; + inline int propOffset() const; + inline int methodOffset() const; + bool hasAssignedMetaObjectData; QQmlVMEVariant *data; QQmlVMEMetaObjectEndpoint *aliasEndpoints; @@ -209,14 +217,15 @@ private: QVariant readPropertyAsVariant(int); void writeProperty(int, const QVariant &); - QAbstractDynamicMetaObject *parent; + QBiPointer<QDynamicMetaObjectData, const QMetaObject> parent; void listChanged(int); class List : public QList<QObject*> { public: - List(int lpi) : notifyIndex(lpi) {} + List(int lpi, QQmlVMEMetaObject *mo) : notifyIndex(lpi), mo(mo) {} int notifyIndex; + QQmlVMEMetaObject *mo; }; QList<List> listProperties; @@ -225,11 +234,13 @@ private: static QObject *list_at(QQmlListProperty<QObject> *, int); static void list_clear(QQmlListProperty<QObject> *); + void activate(QObject *, int, void **); + friend class QV8GCCallback; friend class QV8QObjectWrapper; }; -QQmlVMEMetaObject *QQmlVMEMetaObject::get(const QObject *obj) +QQmlVMEMetaObject *QQmlVMEMetaObject::get(QObject *obj) { if (obj) { if (QQmlData *data = QQmlData::get(obj)) { @@ -241,6 +252,16 @@ QQmlVMEMetaObject *QQmlVMEMetaObject::get(const QObject *obj) return 0; } +int QQmlVMEMetaObject::propOffset() const +{ + return cache->propertyOffset(); +} + +int QQmlVMEMetaObject::methodOffset() const +{ + return cache->methodOffset(); +} + QT_END_NAMESPACE #endif // QQMLVMEMETAOBJECT_P_H diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp index 3c03edbca6..95eb0b9984 100644 --- a/src/qml/qml/v4/qv4bindings.cpp +++ b/src/qml/qml/v4/qv4bindings.cpp @@ -424,7 +424,7 @@ void QV4Bindings::run(Binding *binding, QQmlPropertyPrivate::WriteFlags flags) QQmlData *data = QQmlData::get(*binding->target); QQmlPropertyData *propertyData = (data && data->propertyCache ? data->propertyCache->property(binding->property) : 0); - if (propertyData && propertyData->isVMEProperty()) { + if (propertyData && propertyData->isVarProperty()) { // We will allocate a V8 handle in this conversion/store v8::HandleScope handle_scope; v8::Context::Scope context_scope(QQmlEnginePrivate::get(context->engine)->v8engine()->context()); @@ -2116,18 +2116,27 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, if (data.gettype() == QObjectStarType) { if (QObject *dataObject = data.getQObject()) { - const QMetaObject *dataMo = dataObject->metaObject(); + QQmlMetaObject dataMo(dataObject); QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine); - QMetaProperty receiver = output->metaObject()->property(instr->store.index); - const QMetaObject *receiverMo = QQmlPropertyPrivate::rawMetaObjectForType(ep, receiver.userType()); + + QQmlMetaObject receiverMo; + + if (QQmlData::get(output, false) && QQmlData::get(output, false)->propertyCache) { + QQmlPropertyData *receiver = + QQmlData::get(output, false)->propertyCache->property(instr->store.index); + receiverMo = ep->rawMetaObjectForType(receiver->propType); + } else { + QMetaProperty receiver = output->metaObject()->property(instr->store.index); + receiverMo = ep->rawMetaObjectForType(receiver.userType()); + } // Verify that these types are compatible - if (!QQmlPropertyPrivate::canConvert(dataMo, receiverMo)) { + if (!QQmlMetaObject::canConvert(dataMo, receiverMo)) { THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign ") + - QLatin1String(dataMo->className()) + + QLatin1String(dataMo.className()) + QLatin1String(" to ") + - QLatin1String(receiverMo->className())); + QLatin1String(receiverMo.className())); } } } diff --git a/src/qml/qml/v4/qv4compiler.cpp b/src/qml/qml/v4/qv4compiler.cpp index 1c163364a3..bac1f2c131 100644 --- a/src/qml/qml/v4/qv4compiler.cpp +++ b/src/qml/qml/v4/qv4compiler.cpp @@ -386,7 +386,7 @@ void QV4CompilerPrivate::visitName(IR::Name *e) default: if (propTy == QQmlMetaType::QQuickAnchorLineMetaTypeId()) { regType = PODValueType; - } else if (engine->metaObjectForType(propTy)) { + } else if (!engine->metaObjectForType(propTy).isNull()) { regType = QObjectStarType; } else { if (qmlVerboseCompiler()) diff --git a/src/qml/qml/v4/qv4ir.cpp b/src/qml/qml/v4/qv4ir.cpp index bb4a0d8df0..ed25f28fa3 100644 --- a/src/qml/qml/v4/qv4ir.cpp +++ b/src/qml/qml/v4/qv4ir.cpp @@ -496,7 +496,7 @@ Name *BasicBlock::NAME(Name *base, const QString &id, quint32 line, quint32 colu return e; } -Name *BasicBlock::SYMBOL(Type type, const QString &id, const QMetaObject *meta, QQmlPropertyData *property, Name::Storage storage, +Name *BasicBlock::SYMBOL(Type type, const QString &id, const QQmlMetaObject &meta, QQmlPropertyData *property, Name::Storage storage, quint32 line, quint32 column) { Name *name = SYMBOL(/*base = */ 0, type, id, meta, property, line, column); @@ -504,7 +504,7 @@ Name *BasicBlock::SYMBOL(Type type, const QString &id, const QMetaObject *meta, return name; } -Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, QQmlPropertyData *property, Name::Storage storage, +Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QQmlMetaObject &meta, QQmlPropertyData *property, Name::Storage storage, quint32 line, quint32 column) { Name *name = function->pool->New<Name>(); @@ -516,7 +516,7 @@ Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaOb return name; } -Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, QQmlPropertyData *property, +Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QQmlMetaObject &meta, QQmlPropertyData *property, quint32 line, quint32 column) { Name *name = function->pool->New<Name>(); @@ -551,7 +551,7 @@ Name *BasicBlock::ATTACH_TYPE(const QString &id, const QQmlType *attachType, Nam return name; } -Name *BasicBlock::MODULE_OBJECT(const QString &id, const QMetaObject *meta, Name::Storage storage, +Name *BasicBlock::MODULE_OBJECT(const QString &id, const QQmlMetaObject &meta, Name::Storage storage, quint32 line, quint32 column) { Name *name = function->pool->New<Name>(); diff --git a/src/qml/qml/v4/qv4ir_p.h b/src/qml/qml/v4/qv4ir_p.h index 982acc5a44..9b36762356 100644 --- a/src/qml/qml/v4/qv4ir_p.h +++ b/src/qml/qml/v4/qv4ir_p.h @@ -275,10 +275,11 @@ struct Name: Expr { Symbol symbol; union { void *ptr; - const QMetaObject *meta; const QQmlType *declarativeType; const QQmlScript::Object *idObject; }; + + QQmlMetaObject meta; QQmlPropertyData *property; Storage storage; BuiltinSymbol builtin; @@ -539,12 +540,12 @@ struct BasicBlock { Name *NAME(const QString &id, quint32 line, quint32 column); Name *NAME(Name *base, const QString &id, quint32 line, quint32 column); - Name *SYMBOL(Type type, const QString &id, const QMetaObject *meta, QQmlPropertyData *property, Name::Storage storage, quint32 line, quint32 column); - Name *SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, QQmlPropertyData *property, quint32 line, quint32 column); - Name *SYMBOL(Name *base, Type type, const QString &id, const QMetaObject *meta, QQmlPropertyData *property, Name::Storage storage, quint32 line, quint32 column); + Name *SYMBOL(Type type, const QString &id, const QQmlMetaObject &meta, QQmlPropertyData *property, Name::Storage storage, quint32 line, quint32 column); + Name *SYMBOL(Name *base, Type type, const QString &id, const QQmlMetaObject &meta, QQmlPropertyData *property, quint32 line, quint32 column); + Name *SYMBOL(Name *base, Type type, const QString &id, const QQmlMetaObject &meta, QQmlPropertyData *property, Name::Storage storage, quint32 line, quint32 column); Name *ID_OBJECT(const QString &id, const QQmlScript::Object *object, quint32 line, quint32 column); Name *ATTACH_TYPE(const QString &id, const QQmlType *attachType, Name::Storage storage, quint32 line, quint32 column); - Name *MODULE_OBJECT(const QString &id, const QMetaObject *meta, Name::Storage storage, quint32 line, quint32 column); + Name *MODULE_OBJECT(const QString &id, const QQmlMetaObject &meta, Name::Storage storage, quint32 line, quint32 column); Expr *UNOP(AluOp op, Expr *expr); Expr *BINOP(AluOp op, Expr *left, Expr *right); diff --git a/src/qml/qml/v4/qv4irbuilder.cpp b/src/qml/qml/v4/qv4irbuilder.cpp index 47acaaf67c..354a8cd70c 100644 --- a/src/qml/qml/v4/qv4irbuilder.cpp +++ b/src/qml/qml/v4/qv4irbuilder.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE using namespace QQmlJS; -static IR::Type irTypeFromVariantType(int t, QQmlEnginePrivate *engine, const QMetaObject * /* meta */) +static IR::Type irTypeFromVariantType(int t, QQmlEnginePrivate *engine) { switch (t) { case QMetaType::Bool: @@ -81,7 +81,7 @@ static IR::Type irTypeFromVariantType(int t, QQmlEnginePrivate *engine, const QM default: if (t == QQmlMetaType::QQuickAnchorLineMetaTypeId()) { return IR::SGAnchorLineType; - } else if (engine->metaObjectForType(t)) { + } else if (!engine->metaObjectForType(t).isNull()) { return IR::ObjectType; } else if (t == qMetaTypeId<QJSValue>()) { return IR::JSValueType; @@ -125,9 +125,9 @@ bool QV4IRBuilder::operator()(QQmlJS::IR::Function *function, // This is the only operation where variant is supported: QQmlPropertyData *data = &m_expression->property->core; if (data->propType == QMetaType::QVariant) { - targetType = (data->isVMEProperty() ? IR::VarType : IR::VariantType); + targetType = (data->isVarProperty() ? IR::VarType : IR::VariantType); } else { - targetType = irTypeFromVariantType(data->propType, m_engine, 0); + targetType = irTypeFromVariantType(data->propType, m_engine); } if (targetType != r.type()) { @@ -462,8 +462,7 @@ bool QV4IRBuilder::visit(AST::IdentifierExpression *ast) if (m_expression->context != m_expression->component) { // RootStorage is more efficient than ScopeStorage, so prefer that if they are the same QQmlPropertyCache *cache = m_expression->context->synthCache; - const QMetaObject *metaObject = m_expression->context->metaObject(); - if (!cache) cache = m_engine->cache(metaObject); + if (!cache) cache = m_expression->context->metatype; QQmlPropertyData *data = cache->property(name); @@ -475,16 +474,15 @@ bool QV4IRBuilder::visit(AST::IdentifierExpression *ast) } if (data && !data->isFunction()) { - IR::Type irType = irTypeFromVariantType(data->propType, m_engine, metaObject); - _expr.code = _block->SYMBOL(irType, name, metaObject, data, IR::Name::ScopeStorage, line, column); + IR::Type irType = irTypeFromVariantType(data->propType, m_engine); + _expr.code = _block->SYMBOL(irType, name, QQmlMetaObject(), data, IR::Name::ScopeStorage, line, column); found = true; } } if (!found) { QQmlPropertyCache *cache = m_expression->component->synthCache; - const QMetaObject *metaObject = m_expression->component->metaObject(); - if (!cache) cache = m_engine->cache(metaObject); + if (!cache) cache = m_expression->component->metatype; QQmlPropertyData *data = cache->property(name); @@ -496,8 +494,8 @@ bool QV4IRBuilder::visit(AST::IdentifierExpression *ast) } if (data && !data->isFunction()) { - IR::Type irType = irTypeFromVariantType(data->propType, m_engine, metaObject); - _expr.code = _block->SYMBOL(irType, name, metaObject, data, IR::Name::RootStorage, line, column); + IR::Type irType = irTypeFromVariantType(data->propType, m_engine); + _expr.code = _block->SYMBOL(irType, name, QQmlMetaObject(), data, IR::Name::RootStorage, line, column); found = true; } } @@ -624,7 +622,7 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast) return false; // We don't know enough about this property } - IR::Type irType = irTypeFromVariantType(data->propType, m_engine, attachedMeta); + IR::Type irType = irTypeFromVariantType(data->propType, m_engine); _expr.code = _block->SYMBOL(baseName, irType, name, attachedMeta, data, line, column); } break; @@ -634,7 +632,7 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast) QByteArray utf8Name = name.toUtf8(); const char *enumName = utf8Name.constData(); - const QMetaObject *meta = baseName->meta; + const QMetaObject *meta = baseName->meta.metaObject(); // XXX - firstCppMetaObject bool found = false; for (int ii = 0; !found && ii < meta->enumeratorCount(); ++ii) { QMetaEnum e = meta->enumerator(ii); @@ -649,7 +647,7 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast) qWarning() << "*** unresolved enum:" << (*baseName->id + QLatin1Char('.') + ast->name.toString()); } else { - QQmlPropertyCache *cache = m_engine->cache(baseName->meta); + QQmlPropertyCache *cache = baseName->meta.propertyCache(m_engine); if (!cache) return false; QQmlPropertyData *data = cache->property(name); @@ -663,7 +661,7 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast) return false; // We don't know enough about this property } - IR::Type irType = irTypeFromVariantType(data->propType, m_engine, baseName->meta); + IR::Type irType = irTypeFromVariantType(data->propType, m_engine); _expr.code = _block->SYMBOL(baseName, irType, name, baseName->meta, data, line, column); } } @@ -672,7 +670,7 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast) case IR::Name::IdObject: { const QQmlScript::Object *idObject = baseName->idObject; QQmlPropertyCache *cache = - idObject->synthCache?idObject->synthCache:m_engine->cache(idObject->metaObject()); + idObject->synthCache?idObject->synthCache:idObject->metatype; QQmlPropertyData *data = cache->property(name); @@ -686,16 +684,16 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast) return false; } - IR::Type irType = irTypeFromVariantType(data->propType, m_engine, idObject->metaObject()); - _expr.code = _block->SYMBOL(baseName, irType, name, - idObject->metaObject(), data, line, column); + IR::Type irType = irTypeFromVariantType(data->propType, m_engine); + _expr.code = _block->SYMBOL(baseName, irType, name, QQmlMetaObject(), data, line, column); } break; case IR::Name::Property: - if (baseName->type == IR::ObjectType && baseName->meta && baseName->property->isFinal()) { - const QMetaObject *meta = m_engine->metaObjectForType(baseName->property->propType); - QQmlPropertyCache *cache = m_engine->cache(meta); + if (baseName->type == IR::ObjectType && !baseName->meta.isNull() && + baseName->property->isFinal()) { + QQmlMetaObject meta = m_engine->metaObjectForType(baseName->property->propType); + QQmlPropertyCache *cache = meta.propertyCache(m_engine); if (!cache) return false; @@ -707,7 +705,7 @@ bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast) return false; // We don't know enough about this property } - IR::Type irType = irTypeFromVariantType(data->propType, m_engine, meta); + IR::Type irType = irTypeFromVariantType(data->propType, m_engine); _expr.code = _block->SYMBOL(baseName, irType, name, meta, data, line, column); } diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp index d7e55e2816..0c656631f7 100644 --- a/src/qml/qml/v8/qv8qobjectwrapper.cpp +++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp @@ -535,7 +535,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject return v8::Handle<v8::Value>(); } - if (result->isFunction() && !result->isVMEProperty()) { + if (result->isFunction() && !result->isVarProperty()) { if (result->isVMEFunction()) { QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); Q_ASSERT(vmemo); @@ -576,7 +576,7 @@ v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject if (ep && !result->isConstant()) ep->captureProperty(object, result->coreIndex, result->notifyIndex); - if (result->isVMEProperty()) { + if (result->isVarProperty()) { QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); Q_ASSERT(vmemo); return vmemo->vmeProperty(result->coreIndex); @@ -594,7 +594,7 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert QQmlBinding *newBinding = 0; if (value->IsFunction()) { if (value->ToObject()->GetHiddenValue(engine->bindingFlagKey()).IsEmpty()) { - if (!property->isVMEProperty() && property->propType != qMetaTypeId<QJSValue>()) { + if (!property->isVarProperty() && property->propType != qMetaTypeId<QJSValue>()) { // assigning a JS function to a non var or QJSValue property or is not allowed. QString error = QLatin1String("Cannot assign JavaScript function to ") + QLatin1String(QMetaType::typeName(property->propType)); @@ -626,7 +626,7 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert if (oldBinding) oldBinding->destroy(); - if (!newBinding && property->isVMEProperty()) { + if (!newBinding && property->isVarProperty()) { // allow assignment of "special" values (null, undefined, function) to var properties QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); Q_ASSERT(vmemo); @@ -641,7 +641,6 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert void *argv[] = { &o, 0, &status, &flags }; \ QMetaObject::metacall(object, QMetaObject::WriteProperty, property->coreIndex, argv); - if (value->IsNull() && property->isQObject()) { PROPERTY_STORE(QObject*, 0); } else if (value->IsUndefined() && property->isResettable()) { @@ -669,7 +668,7 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert PROPERTY_STORE(double, double(value->ToNumber()->Value())); } else if (property->propType == QMetaType::QString && value->IsString()) { PROPERTY_STORE(QString, engine->toString(value->ToString())); - } else if (property->isVMEProperty()) { + } else if (property->isVarProperty()) { QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object); Q_ASSERT(vmemo); vmemo->setVMEProperty(property->coreIndex, value); @@ -2146,18 +2145,18 @@ void CallArgument::fromValue(int callType, QV8Engine *engine, v8::Handle<v8::Val } else if (v.canConvert(callType)) { *qvariantPtr = v; qvariantPtr->convert(callType); - } else if (const QMetaObject *mo = ep ? ep->rawMetaObjectForType(callType) : 0) { - QObject *obj = ep->toQObject(v); - - if (obj) { - const QMetaObject *objMo = obj->metaObject(); - while (objMo && objMo != mo) objMo = objMo->superClass(); - if (!objMo) obj = 0; - } - - *qvariantPtr = QVariant(callType, &obj); } else { - *qvariantPtr = QVariant(callType, (void *)0); + QQmlMetaObject mo = ep ? ep->rawMetaObjectForType(callType) : QQmlMetaObject(); + if (!mo.isNull()) { + QObject *obj = ep->toQObject(v); + + if (obj != 0 && !QQmlMetaObject::canConvert(obj, mo)) + obj = 0; + + *qvariantPtr = QVariant(callType, &obj); + } else { + *qvariantPtr = QVariant(callType, (void *)0); + } } } } |