From d2e557c2c2d7fcf3bf7c1676df3902e115986dc2 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 11 May 2012 12:01:41 +0100 Subject: [PATCH] Lazily create QMetaObjects For internal QML built types, creating a metaobject each time is just wasteful. Additionally, as the property caches were always created from the intermediate QMetaObject, it was difficult to pass information directly from the compiler to the property cache. Change-Id: I769526b0edaaf16a86883f3065b75618b94e4077 Reviewed-by: Roberto Raggi --- src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro | 2 +- src/qml/qml/ftw/ftw.pri | 2 - src/qml/qml/ftw/qfastmetabuilder.cpp | 343 ------- src/qml/qml/ftw/qfastmetabuilder_p.h | 234 ----- src/qml/qml/ftw/qhashedstring_p.h | 9 + src/qml/qml/qqmlboundsignal.cpp | 23 +- src/qml/qml/qqmlboundsignal_p.h | 2 +- src/qml/qml/qqmlcompileddata.cpp | 31 +- src/qml/qml/qqmlcompiler.cpp | 1049 ++++++++++---------- src/qml/qml/qqmlcompiler_p.h | 20 +- src/qml/qml/qqmlengine.cpp | 97 +- src/qml/qml/qqmlengine_p.h | 17 +- src/qml/qml/qqmlglobal_p.h | 96 +- src/qml/qml/qqmlinstruction.cpp | 2 +- src/qml/qml/qqmlinstruction_p.h | 1 - src/qml/qml/qqmllist.cpp | 6 +- src/qml/qml/qqmllist_p.h | 3 +- src/qml/qml/qqmlproperty.cpp | 184 ++-- src/qml/qml/qqmlproperty_p.h | 11 +- src/qml/qml/qqmlpropertycache.cpp | 530 +++++++++- src/qml/qml/qqmlpropertycache_p.h | 212 +++- src/qml/qml/qqmlscript.cpp | 27 +- src/qml/qml/qqmlscript_p.h | 21 +- src/qml/qml/qqmltypeloader.cpp | 14 +- src/qml/qml/qqmltypeloader_p.h | 16 +- src/qml/qml/qqmlvme.cpp | 22 +- src/qml/qml/qqmlvmemetaobject.cpp | 167 ++-- src/qml/qml/qqmlvmemetaobject_p.h | 37 +- src/qml/qml/v4/qv4bindings.cpp | 23 +- src/qml/qml/v4/qv4compiler.cpp | 2 +- src/qml/qml/v4/qv4ir.cpp | 8 +- src/qml/qml/v4/qv4ir_p.h | 11 +- src/qml/qml/v4/qv4irbuilder.cpp | 46 +- src/qml/qml/v8/qv8qobjectwrapper.cpp | 33 +- src/quick/items/qquickborderimage.cpp | 3 +- src/quick/items/qquickborderimage_p_p.h | 3 +- src/quick/items/qquickflickable.cpp | 6 +- src/quick/items/qquickitem.cpp | 21 +- src/quick/items/qquickitemsmodule.cpp | 4 +- src/quick/items/qquickloader.cpp | 4 +- src/quick/items/qquickpathview.cpp | 32 +- src/quick/items/qquicktext.cpp | 3 +- src/quick/items/qquicktextedit.cpp | 26 +- src/quick/items/qquickvisualadaptormodel.cpp | 40 +- src/quick/items/qquickvisualdatamodel.cpp | 28 +- src/quick/util/qquickanimation.cpp | 4 +- src/quick/util/qquickconnections.cpp | 2 +- tests/auto/qml/qqmlcpputils/qqmlcpputils.pro | 2 +- tests/auto/qml/qqmlcpputils/tst_qqmlcpputils.cpp | 6 +- tests/auto/qml/qqmlecmascript/data/secondAlias.qml | 15 + tests/auto/qml/qqmlecmascript/data/varAlias.qml | 9 + .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 21 + tests/auto/qml/qqmlglobal/qqmlglobal.pro | 2 +- .../qml/qqmlinstruction/tst_qqmlinstruction.cpp | 3 +- .../qqmllistreference/tst_qqmllistreference.cpp | 2 +- .../auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp | 1 - tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp | 2 +- tests/auto/qmltest/buttonclick/tst_buttonclick.qml | 2 + 58 files changed, 1842 insertions(+), 1700 deletions(-) delete mode 100644 src/qml/qml/ftw/qfastmetabuilder.cpp delete mode 100644 src/qml/qml/ftw/qfastmetabuilder_p.h create mode 100644 tests/auto/qml/qqmlecmascript/data/secondAlias.qml create mode 100644 tests/auto/qml/qqmlecmascript/data/varAlias.qml diff --git a/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro b/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro index fdd1f6e..ed4d6b4 100644 --- a/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro +++ b/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro @@ -1,7 +1,7 @@ load(qt_module) TARGET = qmldbg_tcp -QT += qml-private network +QT += qml-private network v8-private core-private load(qt_plugin) diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri index f2fec4e..c2409c6 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 b22be84..0000000 --- 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 -#include -#include - -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(data.data()) + FMBHEADER_FIELD_COUNT; } - -static inline const uint *fieldPointer(const QByteArray &data) -{ return reinterpret_cast(data.constData()) + FMBHEADER_FIELD_COUNT; } - -static inline QMetaObjectPrivate *priv(QByteArray &data) -{ return reinterpret_cast(fieldPointer(data)); } - -static inline const QMetaObjectPrivate *priv(const QByteArray &data) -{ return reinterpret_cast(fieldPointer(data)); } - -static inline QFastMetaBuilderHeader *header(QByteArray &data) -{ return reinterpret_cast(data.data()); } - -static inline const QFastMetaBuilderHeader *header(const QByteArray &data) -{ return reinterpret_cast(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(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(rawStringData); - } -} - -void QFastMetaBuilder::fromData(QMetaObject *output, const QMetaObject *parent, const QByteArray &data) -{ - output->d.superdata = parent; - output->d.stringdata = reinterpret_cast(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 aebafc8..0000000 --- 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 -#include -#include - -#include - -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(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(&_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 f8099d5..cdc1577 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 9a3ce65..1a16c07 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 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 e3ef65e..b7f3e5f 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 6e6da6a..49f0094 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 b00f4b3..2e26d94 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -44,7 +44,6 @@ #include "qqmlpropertyvaluesource.h" #include "qqmlcomponent.h" #include -#include #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(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(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(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(); component->type = componentTypeRef(); - component->metatype = &QQmlComponent::staticMetaObject; + component->metatype = enginePrivate->cache(&QQmlComponent::staticMetaObject); component->location = root->location; QQmlScript::Value *componentValue = pool->New(); 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 + +static QStringList astNodeToStringList(QQmlJS::AST::Node *node) +{ + if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) { + QString name = + static_cast(node)->name.toString(); + return QStringList() << name; + } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) { + QQmlJS::AST::FieldMemberExpression *expr = static_cast(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 >(); - } + 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 names; + QVarLengthArray paramTypes(paramCount?(paramCount + 1):0); - int paramCount = s->parameterNames.count(); - QVarLengthArray paramTypes(paramCount); if (paramCount) { - s->parameterNamesRef = pool->NewRawList(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 paramTypes(paramCount); - if (paramCount) { - s->parameterNamesRef = pool->NewRawList(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 >(); + } - // 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 >(); + } + } - 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 + 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(node)->name.toString(); - return QStringList() << name; - } else if (node->kind == QQmlJS::AST::Node::Kind_FieldMemberExpression) { - QQmlJS::AST::FieldMemberExpression *expr = static_cast(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 , . or ..")); - 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 , . or ..")); + 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 a326344..c5d319c 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 programs; - const QMetaObject *root; - QAbstractDynamicMetaObject rootData; QQmlPropertyCache *rootPropertyCache; QList primitives; QList 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 352030d..e3fc083 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::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::ConstIterator iter = m_compositeTypes.find(t); + QHash::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::ConstIterator iter = m_compositeTypes.find(t); + QHash::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::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::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, sizeof(QObject*), static_cast >(QtPrivate::QMetaTypeTypeFlags::Flags), - mo); + 0); int lst_type = QMetaType::registerNormalizedType(lst, qMetaTypeDeleteHelper >, qMetaTypeCreateHelper >, @@ -1926,48 +1954,27 @@ void QQmlEnginePrivate::registerCompositeType(const QMetaObject *mo) static_cast >(QtPrivate::QMetaTypeTypeFlags >::Flags), static_cast(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 8048e40..0631fe0 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 moduleApiInstances; QHash propertyCache; QHash, QQmlPropertyCache *> typePropertyCache; QHash m_qmlLists; - QHash m_compositeTypes; + QHash m_compositeTypes; QHash 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 6e233c9..3ed7286 100644 --- a/src/qml/qml/qqmlglobal_p.h +++ b/src/qml/qml/qqmlglobal_p.h @@ -44,6 +44,7 @@ #include #include +#include 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() 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(object)) { + // ...Do something... + } + \endcode +*/ +template +T qmlobject_cast(QObject *object) +{ + if (QQmlMetaObject::canConvert(object, &reinterpret_cast(object)->staticMetaObject)) + return static_cast(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 5715d7a..da5e9aa 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 04f419d..bd279d6 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 c3537da..14425f2 100644 --- a/src/qml/qml/qqmllist.cpp +++ b/src/qml/qml/qqmllist.cpp @@ -64,7 +64,7 @@ QQmlListReference QQmlListReferencePrivate::init(const QQmlListProperty 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 0fe0ed3..e9a613a 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 &, int, QQmlEngine *); QQmlGuard object; - const QMetaObject *elementType; + QQmlMetaObject elementType; QQmlListProperty property; int propertyType; diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 087fbaa..7af7848 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(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(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(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(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 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 >()) { value = resolvedUrlSequence(v8engine->toVariant(result, qMetaTypeId >()), context); - } else if (!isVmeProperty && type != qMetaTypeId()) { + } else if (!isVarProperty && type != qMetaTypeId()) { 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(const_cast(metaObject)); - + QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForMethod(const_cast(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 cba7849..4f0db34 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 491629b..86c0d71 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -47,6 +47,7 @@ #include #include +#include #include @@ -68,6 +69,8 @@ class QQmlPropertyCacheMethodArguments { public: QQmlPropertyCacheMethodArguments *next; + + QList *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 &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(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int))); + ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int)); + args->names = new QList(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 &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(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int))); + ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int)); + args->names = new QList(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 &names) +{ + int argumentCount = names.count(); + + QQmlPropertyData data; + data.propType = QMetaType::QVariant; + data.coreIndex = coreIndex; + + typedef QQmlPropertyCacheMethodArguments A; + A *args = static_cast(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(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 &names) +{ + int argumentCount = names.count(); + + QQmlPropertyData data; + data.propType = QMetaType::QVariant; + data.coreIndex = coreIndex; + + typedef QQmlPropertyCacheMethodArguments A; + A *args = static_cast(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(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(&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(&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 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(); + } + + 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(&c->methodIndexCache.at(index - c->methodIndexCacheStart)); if (rv->arguments) return static_cast(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(malloc(sizeof(A) + (argc + 1) * sizeof(int))); args->arguments[0] = argc; + args->names = 0; QList 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 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 &lhs, + const QPair &rhs) { + return lhs.second->coreIndex < rhs.second->coreIndex; + } }; + + struct Insert { static void in(QQmlPropertyCache *This, + QList > &properties, + QList > &methods, + StringCache::ConstIterator iter, QQmlPropertyData *data) { + if (data->isSignalHandler()) + return; + + if (data->isFunction()) { + if (data->coreIndex < This->methodIndexCacheStart) + return; + + QPair 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 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 > properties; + QList > 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 98322b0..3be85c7 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -54,6 +54,7 @@ // #include +#include #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 &names = QList()); + void appendSignal(const QHashedCStringRef &, quint32, int coreIndex, const int *types = 0, + const QList &names = QList()); + void appendMethod(const QString &, quint32 flags, int coreIndex, + const QList &names = QList()); + void appendMethod(const QHashedCStringRef &, quint32 flags, int coreIndex, + const QList &names = QList()); + + 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 &dummy, QByteArray *unknownTypeError); + static QList 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 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 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 _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 555eb44..cd32c0d 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 daf9fdc..486c573 100644 --- a/src/qml/qml/qqmlscript_p.h +++ b/src/qml/qml/qqmlscript_p.h @@ -56,7 +56,6 @@ #include #include -#include #include #include @@ -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 parameterNamesRef; + int nameIndex; LocationSpan location; }; @@ -440,8 +432,7 @@ public: DynamicSlot *nextSlot; // Used by the compiler - QFastMetaBuilder::StringRef nameRef; - QQmlPool::List parameterNamesRef; + int nameIndex; }; // The list of dynamic properties diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index f76ded6..97b8634 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 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 a795d3c..b16421a 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 - void clearCache(T *o, void (T::*callback)(QQmlTypeData *)) { - TypedCallback cb(o, callback); - clearCache(&TypedCallback::redirect, &cb); - } - - template - void trimCache(T *o, void (T::*callback)(QQmlTypeData *)) { - TypedCallback cb(o, callback); - trimCache(&TypedCallback::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 TypeCache; diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp index 1665342..c09971b 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 -#include #include "qqmldata_p.h" #include "qqml.h" #include "qqmlcustomparser_p.h" @@ -691,21 +690,18 @@ QObject *QQmlVME::run(QList *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 *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 77a0482..e0d7972 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(this) = *other; - this->d.superdata = obj->metaObject(); + if (!hasAssignedMetaObjectData) { + *static_cast(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(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 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(value); + QObject *o = *(QObject **)value.data(); needActivate = (data[id].dataType() != QMetaType::QObjectStar || data[id].asQObject() != o); - data[id].setValue(qvariant_cast(value), this, id); + data[id].setValue(o, this, id); } else { needActivate = (data[id].dataType() != qMetaTypeId() || 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 *prop, QObject *o) { List *list = static_cast(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 *prop) @@ -990,7 +1003,7 @@ void QQmlVMEMetaObject::list_clear(QQmlListProperty *prop) { List *list = static_cast(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(parent)->vmeMethodLineNumber(index); + if (index < methodOffset()) { + Q_ASSERT(parent.isT1()); + return static_cast(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 QQmlVMEMetaObject::vmeMethod(int index) { - if (index < methodOffset) { - Q_ASSERT(parent); - return static_cast(parent)->vmeMethod(index); + if (index < methodOffset()) { + Q_ASSERT(parent.isT1()); + return static_cast(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 value) { - if (index < methodOffset) { - Q_ASSERT(parent); - return static_cast(parent)->setVmeMethod(index, value); + if (index < methodOffset()) { + Q_ASSERT(parent.isT1()); + return static_cast(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[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 val v8::Handle QQmlVMEMetaObject::vmeProperty(int index) { - if (index < propOffset) { - Q_ASSERT(parent); - return static_cast(parent)->vmeProperty(index); + if (index < propOffset()) { + Q_ASSERT(parent.isT1()); + return static_cast(parent.asT1())->vmeProperty(index); } - return readVarProperty(index - propOffset); + return readVarProperty(index - propOffset()); } void QQmlVMEMetaObject::setVMEProperty(int index, v8::Handle v) { - if (index < propOffset) { - Q_ASSERT(parent); - static_cast(parent)->setVMEProperty(index, v); + if (index < propOffset()) { + Q_ASSERT(parent.isT1()); + static_cast(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(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(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 c999247..9927de0 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -69,6 +69,7 @@ #include "qqmlcontext_p.h" #include +#include #include @@ -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 parent; void listChanged(int); class List : public QList { public: - List(int lpi) : notifyIndex(lpi) {} + List(int lpi, QQmlVMEMetaObject *mo) : notifyIndex(lpi), mo(mo) {} int notifyIndex; + QQmlVMEMetaObject *mo; }; QList listProperties; @@ -225,11 +234,13 @@ private: static QObject *list_at(QQmlListProperty *, int); static void list_clear(QQmlListProperty *); + 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 3c03edb..95eb0b9 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 1c16336..bac1f2c 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 bb4a0d8..ed25f28 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(); @@ -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(); @@ -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(); diff --git a/src/qml/qml/v4/qv4ir_p.h b/src/qml/qml/v4/qv4ir_p.h index 982acc5..9b36762 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 47acaaf..354a8cd 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()) { 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 d7e55e2..0c65663 100644 --- a/src/qml/qml/v8/qv8qobjectwrapper.cpp +++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp @@ -535,7 +535,7 @@ v8::Handle QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject return v8::Handle(); } - 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 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()) { + if (!property->isVarProperty() && property->propType != qMetaTypeId()) { // 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::Handleconvert(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); + } } } } diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp index b4efa50..5b48a6f 100644 --- a/src/quick/items/qquickborderimage.cpp +++ b/src/quick/items/qquickborderimage.cpp @@ -316,7 +316,8 @@ void QQuickBorderImage::load() } else { QNetworkRequest req(d->url); d->sciReply = qmlEngine(this)->networkAccessManager()->get(req); - FAST_CONNECT(d->sciReply, SIGNAL(finished()), this, SLOT(sciRequestFinished())) + qmlobject_connect(d->sciReply, QNetworkReply, SIGNAL(finished()), + this, QQuickBorderImage, SLOT(sciRequestFinished())) } } else { diff --git a/src/quick/items/qquickborderimage_p_p.h b/src/quick/items/qquickborderimage_p_p.h index 07a62b4..a55bd56 100644 --- a/src/quick/items/qquickborderimage_p_p.h +++ b/src/quick/items/qquickborderimage_p_p.h @@ -84,7 +84,8 @@ public: Q_Q(QQuickBorderImage); if (!border) { border = new QQuickScaleGrid(q); - FAST_CONNECT(border, SIGNAL(borderChanged()), q, SLOT(doUpdate())) + qmlobject_connect(border, QQuickScaleGrid, SIGNAL(borderChanged()), + q, QQuickBorderImage, SLOT(doUpdate())) } return border; } diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index e8558de..e4e0799 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -208,7 +208,8 @@ void QQuickFlickablePrivate::init() Q_Q(QQuickFlickable); QQml_setParent_noEvent(contentItem, q); contentItem->setParentItem(q); - FAST_CONNECT(&timeline, SIGNAL(completed()), q, SLOT(movementEnding())) + qmlobject_connect(&timeline, QQuickTimeLine, SIGNAL(completed()), + q, QQuickFlickable, SLOT(movementEnding())) q->setAcceptedMouseButtons(Qt::LeftButton); q->setFiltersChildMouseEvents(true); QQuickItemPrivate *viewportPrivate = QQuickItemPrivate::get(contentItem); @@ -1420,8 +1421,7 @@ void QQuickFlickable::cancelFlick() void QQuickFlickablePrivate::data_append(QQmlListProperty *prop, QObject *o) { - QQuickItem *i = qobject_cast(o); - if (i) { + if (QQuickItem *i = qmlobject_cast(o)) { i->setParentItem(static_cast(prop->data)->contentItem); } else { o->setParent(prop->object); // XXX todo - do we want this? diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index b7e6f07..e83fee3 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -566,7 +566,7 @@ void QQuickItemKeyFilter::componentComplete() QQuickKeyNavigationAttached::QQuickKeyNavigationAttached(QObject *parent) : QObject(*(new QQuickKeyNavigationAttachedPrivate), parent), - QQuickItemKeyFilter(qobject_cast(parent)) + QQuickItemKeyFilter(qmlobject_cast(parent)) { m_processPost = true; } @@ -1305,11 +1305,11 @@ bool QQuickKeysAttached::isConnected(const char *signalName) QQuickKeysAttached::QQuickKeysAttached(QObject *parent) : QObject(*(new QQuickKeysAttachedPrivate), parent), - QQuickItemKeyFilter(qobject_cast(parent)) + QQuickItemKeyFilter(qmlobject_cast(parent)) { Q_D(QQuickKeysAttached); m_processPost = false; - d->item = qobject_cast(parent); + d->item = qmlobject_cast(parent); } QQuickKeysAttached::~QQuickKeysAttached() @@ -1604,7 +1604,7 @@ void QQuickItemPrivate::setImplicitLayoutMirror(bool mirror, bool inherit) if (isMirrorImplicit) setLayoutMirror(inherit ? inheritedLayoutMirror : false); for (int i = 0; i < childItems.count(); ++i) { - if (QQuickItem *child = qobject_cast(childItems.at(i))) { + if (QQuickItem *child = qmlobject_cast(childItems.at(i))) { QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child); childPrivate->setImplicitLayoutMirror(inheritedLayoutMirror, inheritMirrorFromParent); } @@ -2496,14 +2496,7 @@ void QQuickItemPrivate::data_append(QQmlListProperty *prop, QObject *o) QQuickItem *that = static_cast(prop->object); - // This test is measurably (albeit only slightly) faster than qobject_cast<>() - const QMetaObject *mo = o->metaObject(); - while (mo && mo != &QQuickItem::staticMetaObject) { - mo = mo->d.superdata; - } - - if (mo) { - QQuickItem *item = static_cast(o); + if (QQuickItem *item = qmlobject_cast(o)) { item->setParentItem(that); } else { if (o->inherits("QGraphicsItem")) @@ -3696,8 +3689,8 @@ QQuickStateGroup *QQuickItemPrivate::_states() _stateGroup = new QQuickStateGroup; if (!componentComplete) _stateGroup->classBegin(); - FAST_CONNECT(_stateGroup, SIGNAL(stateChanged(QString)), - q, SIGNAL(stateChanged(QString))) + qmlobject_connect(_stateGroup, QQuickStateGroup, SIGNAL(stateChanged(QString)), + q, QQuickItem, SIGNAL(stateChanged(QString))) } return _stateGroup; diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 3348122..bb13055 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -88,11 +88,11 @@ static QQmlPrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject *parent) { - QQuickItem *item = qobject_cast(obj); + QQuickItem *item = qmlobject_cast(obj); if (!item) return QQmlPrivate::IncompatibleObject; - QQuickItem *parentItem = qobject_cast(parent); + QQuickItem *parentItem = qmlobject_cast(parent); if (!parentItem) return QQmlPrivate::IncompatibleParent; diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index 1d01cb1..fdc3db9 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -588,7 +588,7 @@ void QQuickLoaderPrivate::setInitialState(QObject *obj) { Q_Q(QQuickLoader); - QQuickItem *item = qobject_cast(obj); + QQuickItem *item = qmlobject_cast(obj); if (item) { // If the item doesn't have an explicit size, but the Loader // does, then set the item's size now before bindings are @@ -625,7 +625,7 @@ void QQuickLoaderPrivate::incubatorStateChanged(QQmlIncubator::Status status) if (status == QQmlIncubator::Ready) { QObject *obj = incubator->object(); - item = qobject_cast(obj); + item = qmlobject_cast(obj); if (item) { emit q->itemChanged(); initResize(); diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp index 1bc3a3a..18c8cee 100644 --- a/src/quick/items/qquickpathview.cpp +++ b/src/quick/items/qquickpathview.cpp @@ -138,9 +138,11 @@ void QQuickPathViewPrivate::init() q->setAcceptedMouseButtons(Qt::LeftButton); q->setFlag(QQuickItem::ItemIsFocusScope); q->setFiltersChildMouseEvents(true); - FAST_CONNECT(&tl, SIGNAL(updated()), q, SLOT(ticked())) + qmlobject_connect(&tl, QQuickTimeLine, SIGNAL(updated()), + q, QQuickPathView, SLOT(ticked())) timer.invalidate(); - FAST_CONNECT(&tl, SIGNAL(completed()), q, SLOT(movementEnding())) + qmlobject_connect(&tl, QQuickTimeLine, SIGNAL(completed()), + q, QQuickPathView, SLOT(movementEnding())) } QQuickItem *QQuickPathViewPrivate::getItem(int modelIndex, qreal z, bool onPath) @@ -578,10 +580,12 @@ void QQuickPathView::setModel(const QVariant &model) return; if (d->model) { - disconnect(d->model, SIGNAL(modelUpdated(QQuickChangeSet,bool)), - this, SLOT(modelUpdated(QQuickChangeSet,bool))); - disconnect(d->model, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(createdItem(int,QQuickItem*))); - disconnect(d->model, SIGNAL(initItem(int,QQuickItem*)), this, SLOT(initItem(int,QQuickItem*))); + qmlobject_disconnect(d->model, QQuickVisualModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), + this, QQuickPathView, SLOT(modelUpdated(QQuickChangeSet,bool))); + qmlobject_disconnect(d->model, QQuickVisualModel, SIGNAL(createdItem(int,QQuickItem*)), + this, QQuickPathView, SLOT(createdItem(int,QQuickItem*))); + qmlobject_disconnect(d->model, QQuickVisualModel, SIGNAL(initItem(int,QQuickItem*)), + this, QQuickPathView, SLOT(initItem(int,QQuickItem*))); for (int i=0; iitems.count(); i++){ QQuickItem *p = d->items[i]; d->releaseItem(p); @@ -610,10 +614,12 @@ void QQuickPathView::setModel(const QVariant &model) } d->modelCount = 0; if (d->model) { - connect(d->model, SIGNAL(modelUpdated(QQuickChangeSet,bool)), - this, SLOT(modelUpdated(QQuickChangeSet,bool))); - connect(d->model, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(createdItem(int,QQuickItem*))); - connect(d->model, SIGNAL(initItem(int,QQuickItem*)), this, SLOT(initItem(int,QQuickItem*))); + qmlobject_connect(d->model, QQuickVisualModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), + this, QQuickPathView, SLOT(modelUpdated(QQuickChangeSet,bool))); + qmlobject_connect(d->model, QQuickVisualModel, SIGNAL(createdItem(int,QQuickItem*)), + this, QQuickPathView, SLOT(createdItem(int,QQuickItem*))); + qmlobject_connect(d->model, QQuickVisualModel, SIGNAL(initItem(int,QQuickItem*)), + this, QQuickPathView, SLOT(initItem(int,QQuickItem*))); d->modelCount = d->model->count(); if (d->model->count()) d->offset = qmlMod(d->offset, qreal(d->model->count())); @@ -656,9 +662,11 @@ void QQuickPathView::setPath(QQuickPath *path) if (d->path == path) return; if (d->path) - disconnect(d->path, SIGNAL(changed()), this, SLOT(pathUpdated())); + qmlobject_disconnect(d->path, QQuickPath, SIGNAL(changed()), + this, QQuickPathView, SLOT(pathUpdated())); d->path = path; - connect(d->path, SIGNAL(changed()), this, SLOT(pathUpdated())); + qmlobject_connect(d->path, QQuickPath, SIGNAL(changed()), + this, QQuickPathView, SLOT(pathUpdated())); if (d->isValid() && isComponentComplete()) { d->clear(); if (d->attType) { diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index b6ccc5e..b61d329 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -1131,7 +1131,8 @@ void QQuickTextPrivate::ensureDoc() extra.value().doc = new QQuickTextDocumentWithImageResources(q); extra->doc->setDocumentMargin(0); extra->doc->setBaseUrl(q->baseUrl()); - FAST_CONNECT(extra->doc, SIGNAL(imagesLoaded()), q, SLOT(q_imagesLoaded())); + qmlobject_connect(extra->doc, QQuickTextDocumentWithImageResources, SIGNAL(imagesLoaded()), + q, QQuickText, SLOT(q_imagesLoaded())); } } diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 2d16c02..a3dd772 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -1746,21 +1746,21 @@ void QQuickTextEditPrivate::init() control->setAcceptRichText(false); control->setCursorIsFocusIndicator(true); - FAST_CONNECT(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateDocument())); - FAST_CONNECT(control, SIGNAL(updateCursorRequest()), q, SLOT(updateCursor())); - FAST_CONNECT(control, SIGNAL(textChanged()), q, SLOT(q_textChanged())); - FAST_CONNECT(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged())); - FAST_CONNECT(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers())); - FAST_CONNECT(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers())); - FAST_CONNECT(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged())); - FAST_CONNECT(control, SIGNAL(cursorRectangleChanged()), q, SLOT(moveCursorDelegate())); - FAST_CONNECT(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString))); + qmlobject_connect(control, QQuickTextControl, SIGNAL(updateRequest(QRectF)), q, QQuickTextEdit, SLOT(updateDocument())); + qmlobject_connect(control, QQuickTextControl, SIGNAL(updateCursorRequest()), q, QQuickTextEdit, SLOT(updateCursor())); + qmlobject_connect(control, QQuickTextControl, SIGNAL(textChanged()), q, QQuickTextEdit, SLOT(q_textChanged())); + qmlobject_connect(control, QQuickTextControl, SIGNAL(selectionChanged()), q, QQuickTextEdit, SIGNAL(selectionChanged())); + qmlobject_connect(control, QQuickTextControl, SIGNAL(selectionChanged()), q, QQuickTextEdit, SLOT(updateSelectionMarkers())); + qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SLOT(updateSelectionMarkers())); + qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorPositionChanged()), q, QQuickTextEdit, SIGNAL(cursorPositionChanged())); + qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorRectangleChanged()), q, QQuickTextEdit, SLOT(moveCursorDelegate())); + qmlobject_connect(control, QQuickTextControl, SIGNAL(linkActivated(QString)), q, QQuickTextEdit, SIGNAL(linkActivated(QString))); #ifndef QT_NO_CLIPBOARD - FAST_CONNECT(QGuiApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged())); + qmlobject_connect(QGuiApplication::clipboard(), QClipboard, SIGNAL(dataChanged()), q, QQuickTextEdit, SLOT(q_canPasteChanged())); #endif - FAST_CONNECT(document, SIGNAL(undoAvailable(bool)), q, SIGNAL(canUndoChanged())); - FAST_CONNECT(document, SIGNAL(redoAvailable(bool)), q, SIGNAL(canRedoChanged())); - FAST_CONNECT(document, SIGNAL(imagesLoaded()), q, SLOT(updateSize())); + qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(undoAvailable(bool)), q, QQuickTextEdit, SIGNAL(canUndoChanged())); + qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(redoAvailable(bool)), q, QQuickTextEdit, SIGNAL(canRedoChanged())); + qmlobject_connect(document, QQuickTextDocumentWithImageResources, SIGNAL(imagesLoaded()), q, QQuickTextEdit, SLOT(updateSize())); document->setDefaultFont(font); document->setDocumentMargin(textMargin); diff --git a/src/quick/items/qquickvisualadaptormodel.cpp b/src/quick/items/qquickvisualadaptormodel.cpp index d772d67..99c44e3 100644 --- a/src/quick/items/qquickvisualadaptormodel.cpp +++ b/src/quick/items/qquickvisualadaptormodel.cpp @@ -996,29 +996,29 @@ void QQuickVisualAdaptorModel::setModel(const QVariant &variant, QQuickVisualDat if (QAbstractItemModel *model = qobject_cast(object)) { accessors = new VDMAbstractItemModelDataType(this); - FAST_CONNECT(model, SIGNAL(rowsInserted(QModelIndex,int,int)), - vdm, SLOT(_q_rowsInserted(QModelIndex,int,int))); - FAST_CONNECT(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), - vdm, SLOT(_q_rowsRemoved(QModelIndex,int,int))); - FAST_CONNECT(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), - vdm, SLOT(_q_dataChanged(QModelIndex,QModelIndex))); - FAST_CONNECT(model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), - vdm, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int))); - FAST_CONNECT(model, SIGNAL(modelReset()), - vdm, SLOT(_q_modelReset())); - FAST_CONNECT(model, SIGNAL(layoutChanged()), - vdm, SLOT(_q_layoutChanged())); + qmlobject_connect(model, QAbstractItemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), + vdm, QQuickVisualDataModel, SLOT(_q_rowsInserted(QModelIndex,int,int))); + qmlobject_connect(model, QAbstractItemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), + vdm, QQuickVisualDataModel, SLOT(_q_rowsRemoved(QModelIndex,int,int))); + qmlobject_connect(model, QAbstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), + vdm, QQuickVisualDataModel, SLOT(_q_dataChanged(QModelIndex,QModelIndex))); + qmlobject_connect(model, QAbstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), + vdm, QQuickVisualDataModel, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int))); + qmlobject_connect(model, QAbstractItemModel, SIGNAL(modelReset()), + vdm, QQuickVisualDataModel, SLOT(_q_modelReset())); + qmlobject_connect(model, QAbstractItemModel, SIGNAL(layoutChanged()), + vdm, QQuickVisualDataModel, SLOT(_q_layoutChanged())); } else if (QListModelInterface *model = qobject_cast(object)) { accessors = new VDMListModelInterfaceDataType(this); - FAST_CONNECT(model, SIGNAL(itemsChanged(int,int,QList)), - vdm, SLOT(_q_itemsChanged(int,int,QList))); - FAST_CONNECT(model, SIGNAL(itemsInserted(int,int)), - vdm, SLOT(_q_itemsInserted(int,int))); - FAST_CONNECT(model, SIGNAL(itemsRemoved(int,int)), - vdm, SLOT(_q_itemsRemoved(int,int))); - FAST_CONNECT(model, SIGNAL(itemsMoved(int,int,int)), - vdm, SLOT(_q_itemsMoved(int,int,int))); + qmlobject_connect(model, QListModelInterface, SIGNAL(itemsChanged(int,int,QList)), + vdm, QQuickVisualDataModel, SLOT(_q_itemsChanged(int,int,QList))); + qmlobject_connect(model, QListModelInterface, SIGNAL(itemsInserted(int,int)), + vdm, QQuickVisualDataModel, SLOT(_q_itemsInserted(int,int))); + qmlobject_connect(model, QListModelInterface, SIGNAL(itemsRemoved(int,int)), + vdm, QQuickVisualDataModel, SLOT(_q_itemsRemoved(int,int))); + qmlobject_connect(model, QListModelInterface, SIGNAL(itemsMoved(int,int,int)), + vdm, QQuickVisualDataModel, SLOT(_q_itemsMoved(int,int,int))); } else { accessors = new VDMObjectDelegateDataType; } diff --git a/src/quick/items/qquickvisualdatamodel.cpp b/src/quick/items/qquickvisualdatamodel.cpp index 79ddeca..d202c61 100644 --- a/src/quick/items/qquickvisualdatamodel.cpp +++ b/src/quick/items/qquickvisualdatamodel.cpp @@ -430,7 +430,7 @@ QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModelPrivate::release(QObjec if (QQuickVisualDataModelItem *cacheItem = QQuickVisualDataModelItem::dataForObject(object)) { if (cacheItem->releaseObject()) { cacheItem->destroyObject(); - if (QQuickItem *item = qobject_cast(object)) + if (QQuickItem *item = qmlobject_cast(object)) emitDestroyingItem(item); if (cacheItem->incubationTask) { releaseIncubator(cacheItem->incubationTask); @@ -477,9 +477,9 @@ void QQuickVisualDataModel::cancel(int index) if (cacheItem->object() && !cacheItem->isObjectReferenced()) { QObject *object = cacheItem->object(); cacheItem->destroyObject(); - if (QQuickPackage *package = qobject_cast(object)) + if (QQuickPackage *package = qmlobject_cast(object)) d->emitDestroyingPackage(package); - else if (QQuickItem *item = qobject_cast(object)) + else if (QQuickItem *item = qmlobject_cast(object)) d->emitDestroyingItem(item); cacheItem->scriptRef -= 1; } @@ -741,7 +741,7 @@ void QQuickVisualDataModelPrivate::incubatorStatusChanged(QVDMIncubationTask *in if (status == QQmlIncubator::Ready) { incubationTask->incubating = 0; releaseIncubator(incubationTask); - if (QQuickPackage *package = qobject_cast(cacheItem->object())) + if (QQuickPackage *package = qmlobject_cast(cacheItem->object())) emitCreatedPackage(cacheItem, package); else if (QQuickItem *item = qobject_cast(cacheItem->object())) emitCreatedItem(cacheItem, item); @@ -773,9 +773,9 @@ void QQuickVisualDataModelPrivate::setInitialState(QVDMIncubationTask *incubatio QQuickVisualDataModelItem *cacheItem = incubationTask->incubating; cacheItem->setObject(o); - if (QQuickPackage *package = qobject_cast(cacheItem->object())) + if (QQuickPackage *package = qmlobject_cast(cacheItem->object())) emitInitPackage(cacheItem, package); - else if (QQuickItem *item = qobject_cast(cacheItem->object())) + else if (QQuickItem *item = qmlobject_cast(cacheItem->object())) emitInitItem(cacheItem, item); } @@ -868,7 +868,7 @@ QQuickItem *QQuickVisualDataModel::item(int index, bool asynchronous) if (!object) return 0; - if (QQuickItem *item = qobject_cast(object)) + if (QQuickItem *item = qmlobject_cast(object)) return item; d->release(object); @@ -1117,9 +1117,9 @@ void QQuickVisualDataModelPrivate::itemsRemoved( if (remove.inGroup(Compositor::Persisted) && cacheItem->objectRef == 0 && cacheItem->object()) { QObject *object = cacheItem->object(); cacheItem->destroyObject(); - if (QQuickPackage *package = qobject_cast(object)) + if (QQuickPackage *package = qmlobject_cast(object)) emitDestroyingPackage(package); - else if (QQuickItem *item = qobject_cast(object)) + else if (QQuickItem *item = qmlobject_cast(object)) emitDestroyingItem(item); cacheItem->setObject(0); cacheItem->scriptRef -= 1; @@ -2767,11 +2767,11 @@ QQuickItem *QQuickVisualPartsModel::item(int index, bool asynchronous) QObject *object = model->object(m_compositorGroup, index, asynchronous, true); - if (QQuickPackage *package = qobject_cast(object)) { + if (QQuickPackage *package = qmlobject_cast(object)) { QObject *part = package->part(m_part); if (!part) return 0; - if (QQuickItem *item = qobject_cast(part)) { + if (QQuickItem *item = qmlobject_cast(part)) { m_packaged.insertMulti(item, package); return item; } @@ -2830,19 +2830,19 @@ int QQuickVisualPartsModel::indexOf(QQuickItem *item, QObject *) const void QQuickVisualPartsModel::createdPackage(int index, QQuickPackage *package) { - if (QQuickItem *item = qobject_cast(package->part(m_part))) + if (QQuickItem *item = qmlobject_cast(package->part(m_part))) emit createdItem(index, item); } void QQuickVisualPartsModel::initPackage(int index, QQuickPackage *package) { - if (QQuickItem *item = qobject_cast(package->part(m_part))) + if (QQuickItem *item = qmlobject_cast(package->part(m_part))) emit initItem(index, item); } void QQuickVisualPartsModel::destroyingPackage(QQuickPackage *package) { - if (QQuickItem *item = qobject_cast(package->part(m_part))) { + if (QQuickItem *item = qmlobject_cast(package->part(m_part))) { Q_ASSERT(!m_packaged.contains(item)); emit destroyingItem(item); item->setParentItem(0); diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp index 77d4809..4544df2 100644 --- a/src/quick/util/qquickanimation.cpp +++ b/src/quick/util/qquickanimation.cpp @@ -1601,10 +1601,8 @@ QQuickAnimationGroup::QQuickAnimationGroup(QQuickAnimationGroupPrivate &dd, QObj void QQuickAnimationGroupPrivate::append_animation(QQmlListProperty *list, QQuickAbstractAnimation *a) { - QQuickAnimationGroup *q = qobject_cast(list->object); - if (q) { + if (QQuickAnimationGroup *q = qmlobject_cast(list->object)) a->setGroup(q); - } } void QQuickAnimationGroupPrivate::clear_animation(QQmlListProperty *list) diff --git a/src/quick/util/qquickconnections.cpp b/src/quick/util/qquickconnections.cpp index d3c3361..934c59b 100644 --- a/src/quick/util/qquickconnections.cpp +++ b/src/quick/util/qquickconnections.cpp @@ -279,7 +279,7 @@ void QQuickConnections::connectSignals() QQmlProperty prop(target(), propName); if (prop.isValid() && (prop.type() & QQmlProperty::SignalProperty)) { QQmlBoundSignal *signal = - new QQmlBoundSignal(target(), prop.method(), this, qmlEngine(this)); + new QQmlBoundSignal(target(), prop.index(), this, qmlEngine(this)); QString location; QQmlContextData *ctxtdata = 0; diff --git a/tests/auto/qml/qqmlcpputils/qqmlcpputils.pro b/tests/auto/qml/qqmlcpputils/qqmlcpputils.pro index 1c08886..847665b 100644 --- a/tests/auto/qml/qqmlcpputils/qqmlcpputils.pro +++ b/tests/auto/qml/qqmlcpputils/qqmlcpputils.pro @@ -6,4 +6,4 @@ SOURCES += tst_qqmlcpputils.cpp CONFIG += parallel_test -QT += core-private gui-private qml-private testlib +QT += core-private gui-private qml-private testlib v8-private diff --git a/tests/auto/qml/qqmlcpputils/tst_qqmlcpputils.cpp b/tests/auto/qml/qqmlcpputils/tst_qqmlcpputils.cpp index 186b82a..4189f44 100644 --- a/tests/auto/qml/qqmlcpputils/tst_qqmlcpputils.cpp +++ b/tests/auto/qml/qqmlcpputils/tst_qqmlcpputils.cpp @@ -73,7 +73,7 @@ void tst_qqmlcpputils::fastConnect() { { MyObject *obj = new MyObject; - FAST_CONNECT(obj, SIGNAL(signal1()), obj, SLOT(slot1())); + qmlobject_connect(obj, MyObject, SIGNAL(signal1()), obj, MyObject, SLOT(slot1())); obj->signal1(); QCOMPARE(obj->slotCount, 1); @@ -83,7 +83,7 @@ void tst_qqmlcpputils::fastConnect() { MyObject obj; - FAST_CONNECT(&obj, SIGNAL(signal1()), &obj, SLOT(slot1())) + qmlobject_connect(&obj, MyObject, SIGNAL(signal1()), &obj, MyObject, SLOT(slot1())) obj.signal1(); QCOMPARE(obj.slotCount, 1); @@ -92,7 +92,7 @@ void tst_qqmlcpputils::fastConnect() { MyObject *obj = new MyObject; QSignalSpy spy(obj, SIGNAL(signal2())); - FAST_CONNECT(obj, SIGNAL(signal1()), obj, SIGNAL(signal2())); + qmlobject_connect(obj, MyObject, SIGNAL(signal1()), obj, MyObject, SIGNAL(signal2())); obj->signal1(); QCOMPARE(spy.count(), 1); diff --git a/tests/auto/qml/qqmlecmascript/data/secondAlias.qml b/tests/auto/qml/qqmlecmascript/data/secondAlias.qml new file mode 100644 index 0000000..d818be3 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/secondAlias.qml @@ -0,0 +1,15 @@ +import QtQuick 2.0 + +QtObject { + id: root + + property int prop1: 100 + property int prop2: 100 + + property alias alias1: root.prop1 + property alias alias2: root.prop2 + + property int test: root.alias2 + + Component.onCompleted: root.prop2 = 200 +} diff --git a/tests/auto/qml/qqmlecmascript/data/varAlias.qml b/tests/auto/qml/qqmlecmascript/data/varAlias.qml new file mode 100644 index 0000000..4d1aee2 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/varAlias.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +QtObject { + id: root + + property int test: root.aliasProperty.value + property alias aliasProperty: root.varProperty + property var varProperty: new Object({ value: 192 }); +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 30adb33..f907a1c 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -266,6 +266,8 @@ private slots: void signalEmitted(); void threadSignal(); void qqmldataDestroyed(); + void secondAlias(); + void varAlias(); private: static void propertyVarWeakRefCallback(v8::Persistent object, void* parameter); @@ -6852,6 +6854,25 @@ void tst_qqmlecmascript::qqmldataDestroyed() } } +void tst_qqmlecmascript::secondAlias() +{ + QQmlComponent c(&engine, testFileUrl("secondAlias.qml")); + QObject *object = c.create(); + QVERIFY(object != 0); + QCOMPARE(object->property("test").toInt(), 200); + delete object; +} + +// An alias to a var property works +void tst_qqmlecmascript::varAlias() +{ + QQmlComponent c(&engine, testFileUrl("varAlias.qml")); + QObject *object = c.create(); + QVERIFY(object != 0); + QCOMPARE(object->property("test").toInt(), 192); + delete object; +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" diff --git a/tests/auto/qml/qqmlglobal/qqmlglobal.pro b/tests/auto/qml/qqmlglobal/qqmlglobal.pro index b39c045..42ce3b5 100644 --- a/tests/auto/qml/qqmlglobal/qqmlglobal.pro +++ b/tests/auto/qml/qqmlglobal/qqmlglobal.pro @@ -4,4 +4,4 @@ SOURCES += tst_qqmlglobal.cpp macx:CONFIG -= app_bundle CONFIG += parallel_test -QT += qml-private testlib +QT += qml-private testlib v8-private core-private diff --git a/tests/auto/qml/qqmlinstruction/tst_qqmlinstruction.cpp b/tests/auto/qml/qqmlinstruction/tst_qqmlinstruction.cpp index 5fe15a6..b4c83b3 100644 --- a/tests/auto/qml/qqmlinstruction/tst_qqmlinstruction.cpp +++ b/tests/auto/qml/qqmlinstruction/tst_qqmlinstruction.cpp @@ -119,7 +119,6 @@ void tst_qqmlinstruction::dump() { QQmlCompiledData::Instruction::StoreMetaObject i; - i.data = 3; i.aliasData = 6; i.propertyCache = 7; @@ -512,7 +511,7 @@ void tst_qqmlinstruction::dump() << "2\t\tSETID\t\t\t0\t\t\t\"testId\"" << "3\t\tSET_DEFAULT" << "4\t\tCREATE_COMPONENT\t3" - << "5\t\tSTORE_META\t\t3" + << "5\t\tSTORE_META\t\t" << "6\t\tSTORE_FLOAT\t\t3\t11.3" << "7\t\tSTORE_DOUBLE\t\t4\t14.8" << "8\t\tSTORE_INTEGER\t\t5\t9" diff --git a/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp b/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp index bcb8ee8..b4e77dd 100644 --- a/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp +++ b/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp @@ -537,7 +537,7 @@ void tst_qqmllistreference::engineTypes() QVERIFY(o); QQmlProperty p1(o, QLatin1String("myList")); - QVERIFY(p1.propertyTypeCategory() == QQmlProperty::Normal); + QVERIFY(p1.propertyTypeCategory() == QQmlProperty::List); QQmlProperty p2(o, QLatin1String("myList"), engine.rootContext()); QVERIFY(p2.propertyTypeCategory() == QQmlProperty::List); diff --git a/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp index 8e35c24..d4f4fc0 100644 --- a/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp +++ b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp @@ -388,7 +388,6 @@ void tst_QQmlMetaObject::method() for (int i = 0; i < parameterTypes.size(); ++i) QCOMPARE(method.parameterType(i), parameterTypes.at(i)); QCOMPARE(method.parameterTypes(), parameterTypeNames); - QCOMPARE(method.parameterNames(), parameterNames); QCOMPARE(method.tag(), ""); QCOMPARE(QString::fromUtf8(method.typeName()), returnTypeName); diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 12a8325..248cc0d 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -1854,7 +1854,7 @@ void tst_qqmlproperty::warnOnInvalidBinding() QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData()); // V8 error message for invalid binding to anchor - expectedWarning = testUrl.toString() + QString::fromLatin1(":14: Unable to assign QQuickItem_QML_7 to QQuickAnchorLine"); + expectedWarning = testUrl.toString() + QString::fromLatin1(":14: Unable to assign QQuickItem_QML_6 to QQuickAnchorLine"); QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData()); QQmlComponent component(&engine, testUrl); diff --git a/tests/auto/qmltest/buttonclick/tst_buttonclick.qml b/tests/auto/qmltest/buttonclick/tst_buttonclick.qml index 840a7fd..1474ee7 100644 --- a/tests/auto/qmltest/buttonclick/tst_buttonclick.qml +++ b/tests/auto/qmltest/buttonclick/tst_buttonclick.qml @@ -57,9 +57,11 @@ Button { when: windowShown function test_click() { + compare(spy.count, 0) button.clicked(1, 2); compare(button.text, "Clicked"); + compare(spy.count, 1) compare(spy.signalArguments.length, 1) compare(spy.signalArguments[0][0], 1) -- 2.7.4