diff options
Diffstat (limited to 'src/qml/qml')
84 files changed, 4114 insertions, 3433 deletions
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri index a671cfa12d..87d80d04bc 100644 --- a/src/qml/qml/ftw/ftw.pri +++ b/src/qml/qml/ftw/ftw.pri @@ -8,12 +8,11 @@ HEADERS += \ $$PWD/qqmlthread_p.h \ $$PWD/qfinitestack_p.h \ $$PWD/qrecursionwatcher_p.h \ - $$PWD/qdeletewatcher_p.h \ $$PWD/qrecyclepool_p.h \ $$PWD/qflagpointer_p.h \ - $$PWD/qpointervaluepair_p.h \ $$PWD/qlazilyallocated_p.h \ $$PWD/qqmlnullablevalue_p.h \ + $$PWD/qdeferredcleanup_p.h \ SOURCES += \ $$PWD/qintrusivelist.cpp \ @@ -22,4 +21,4 @@ SOURCES += \ # mirrors logic in $$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri # clock_gettime() is implemented in librt on these systems -contains(QT_CONFIG, clock-gettime):linux-*|hpux-*|solaris-*:LIBS_PRIVATE *= -lrt +qtConfig(clock-gettime):linux-*|hpux-*|solaris-*:LIBS_PRIVATE *= -lrt diff --git a/src/qml/qml/qqmlmemoryprofiler_p.h b/src/qml/qml/ftw/qdeferredcleanup_p.h index 4b0ba823ba..6b59f04a77 100644 --- a/src/qml/qml/qqmlmemoryprofiler_p.h +++ b/src/qml/qml/ftw/qdeferredcleanup_p.h @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef QQMLMEMORYPROFILER_H -#define QQMLMEMORYPROFILER_H +#ifndef QDEFERREDCLEANUP_P_H +#define QDEFERREDCLEANUP_P_H // // W A R N I N G @@ -51,37 +51,24 @@ // We mean it. // -#include <private/qtqmlglobal_p.h> +#include <QtCore/qglobal.h> -QT_BEGIN_NAMESPACE - -class QUrl; +#include <functional> -class Q_QML_PRIVATE_EXPORT QQmlMemoryScope -{ -public: - explicit QQmlMemoryScope(const QUrl &url); - explicit QQmlMemoryScope(const char *string); - ~QQmlMemoryScope(); - -private: - bool pushed; -}; +QT_BEGIN_NAMESPACE -class Q_QML_PRIVATE_EXPORT QQmlMemoryProfiler +struct QDeferredCleanup { -public: - static void enable(); - static void disable(); - static bool isEnabled(); - - static void clear(); - static void stats(int *allocCount, int *bytesAllocated); - static void save(const char *filename); + std::function<void()> callback; + template <typename Callback> + QDeferredCleanup(Callback &&cb) + : callback(cb) + {} + ~QDeferredCleanup() { callback(); } + QDeferredCleanup(const QDeferredCleanup &) = delete; + QDeferredCleanup &operator=(const QDeferredCleanup &) = delete; }; -#define QML_MEMORY_SCOPE_URL(url) QQmlMemoryScope _qml_memory_scope(url) -#define QML_MEMORY_SCOPE_STRING(s) QQmlMemoryScope _qml_memory_scope(s) - QT_END_NAMESPACE -#endif // QQMLMEMORYPROFILER_H + +#endif // QDEFERREDCLEANUP_P_H diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp index 37c1003748..117670dbfc 100644 --- a/src/qml/qml/ftw/qhashedstring.cpp +++ b/src/qml/qml/ftw/qhashedstring.cpp @@ -39,30 +39,7 @@ #include "qhashedstring_p.h" -inline quint32 stringHash(const QChar* data, int length) -{ - return QV4::String::createHashValue(data, length); -} -inline quint32 stringHash(const char *data, int length) -{ - return QV4::String::createHashValue(data, length); -} - -void QHashedString::computeHash() const -{ - m_hash = stringHash(constData(), length()); -} - -void QHashedStringRef::computeHash() const -{ - m_hash = stringHash(m_data, m_length); -} - -void QHashedCStringRef::computeHash() const -{ - m_hash = stringHash(m_data, m_length); -} /* A QHash has initially around pow(2, MinNumBits) buckets. For diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h index 6ff3e4a11b..9ee50ec931 100644 --- a/src/qml/qml/ftw/qhashedstring_p.h +++ b/src/qml/qml/ftw/qhashedstring_p.h @@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE // #define QSTRINGHASH_LINK_DEBUG class QHashedStringRef; -class Q_AUTOTEST_EXPORT QHashedString : public QString +class Q_QML_PRIVATE_EXPORT QHashedString : public QString { public: inline QHashedString(); @@ -85,16 +85,20 @@ public: static bool compare(const QChar *lhs, const QChar *rhs, int length); static inline bool compare(const QChar *lhs, const char *rhs, int length); static inline bool compare(const char *lhs, const char *rhs, int length); + + static inline quint32 stringHash(const QChar* data, int length); + static inline quint32 stringHash(const char *data, int length); + private: friend class QHashedStringRef; friend class QStringHashNode; - void computeHash() const; + inline void computeHash() const; mutable quint32 m_hash; }; class QHashedCStringRef; -class Q_AUTOTEST_EXPORT QHashedStringRef +class Q_QML_PRIVATE_EXPORT QHashedStringRef { public: inline QHashedStringRef(); @@ -136,7 +140,7 @@ public: private: friend class QHashedString; - void computeHash() const; + inline void computeHash() const; const QChar *m_data; int m_length; @@ -163,7 +167,7 @@ public: private: friend class QHashedStringRef; - void computeHash() const; + inline void computeHash() const; const char *m_data; int m_length; @@ -1214,6 +1218,11 @@ bool QHashedStringRef::isLatin1() const return true; } +void QHashedStringRef::computeHash() const +{ + m_hash = QHashedString::stringHash(m_data, m_length); +} + bool QHashedStringRef::startsWithUpper() const { if (m_length < 1) return false; @@ -1280,6 +1289,11 @@ void QHashedCStringRef::writeUtf16(quint16 *output) const *output++ = *d++; } +void QHashedCStringRef::computeHash() const +{ + m_hash = QHashedString::stringHash(m_data, m_length); +} + bool QHashedString::compare(const QChar *lhs, const char *rhs, int length) { Q_ASSERT(lhs && rhs); @@ -1295,6 +1309,21 @@ bool QHashedString::compare(const char *lhs, const char *rhs, int length) return 0 == ::memcmp(lhs, rhs, length); } +quint32 QHashedString::stringHash(const QChar *data, int length) +{ + return QV4::String::createHashValue(data, length, Q_NULLPTR); +} + +quint32 QHashedString::stringHash(const char *data, int length) +{ + return QV4::String::createHashValue(data, length, Q_NULLPTR); +} + +void QHashedString::computeHash() const +{ + m_hash = stringHash(constData(), length()); +} + QT_END_NAMESPACE #endif // QHASHEDSTRING_P_H diff --git a/src/qml/qml/ftw/qpointervaluepair_p.h b/src/qml/qml/ftw/qpointervaluepair_p.h deleted file mode 100644 index 3d0644039f..0000000000 --- a/src/qml/qml/ftw/qpointervaluepair_p.h +++ /dev/null @@ -1,194 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPOINTERVALUEPAIR_P_H -#define QPOINTERVALUEPAIR_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/qglobal.h> -#include <private/qflagpointer_p.h> - -QT_BEGIN_NAMESPACE - -// QPointerValuePair is intended to help reduce the memory consumption of a class. -// In the common case, QPointerValuePair behaves like a pointer. In this mode, it -// consumes the same memory as a regular pointer. -// Additionally, QPointerValuePair can store an arbitrary value type in *addition* -// to the pointer. In this case, it uses slightly more memory than the pointer and -// value type combined. -// Consequently, this class is most useful in cases where a pointer is always stored -// and a value type is rarely stored. -template<typename P, typename V> -class QPointerValuePair { -public: - inline QPointerValuePair(); - inline QPointerValuePair(P *); - inline ~QPointerValuePair(); - - inline bool isNull() const; - - inline bool flag() const; - inline void setFlag(); - inline void clearFlag(); - inline void setFlagValue(bool); - - inline QPointerValuePair<P, V> &operator=(P *); - - inline P *operator->() const; - inline P *operator*() const; - - inline bool hasValue() const; - inline V &value(); - inline const V *constValue() const; - -private: - struct Value { P *pointer; V value; }; - QBiPointer<P, Value> d; -}; - -template<typename P, typename V> -QPointerValuePair<P, V>::QPointerValuePair() -{ -} - -template<typename P, typename V> -QPointerValuePair<P, V>::QPointerValuePair(P *p) -: d(p) -{ -} - -template<typename P, typename V> -QPointerValuePair<P, V>::~QPointerValuePair() -{ - if (d.isT2()) delete d.asT2(); -} - -template<typename P, typename V> -bool QPointerValuePair<P, V>::isNull() const -{ - if (d.isT1()) return 0 == d.asT1(); - else return d.asT2()->pointer == 0; -} - -template<typename P, typename V> -bool QPointerValuePair<P, V>::flag() const -{ - return d.flag(); -} - -template<typename P, typename V> -void QPointerValuePair<P, V>::setFlag() -{ - d.setFlag(); -} - -template<typename P, typename V> -void QPointerValuePair<P, V>::clearFlag() -{ - d.clearFlag(); -} - -template<typename P, typename V> -void QPointerValuePair<P, V>::setFlagValue(bool v) -{ - d.setFlagValue(v); -} - -template<typename P, typename V> -QPointerValuePair<P, V> &QPointerValuePair<P, V>::operator=(P *o) -{ - if (d.isT1()) d = o; - else d.asT2()->pointer = o; - return *this; -} - -template<typename P, typename V> -P *QPointerValuePair<P, V>::operator->() const -{ - if (d.isT1()) return d.asT1(); - else return d.asT2()->pointer; -} - -template<typename P, typename V> -P *QPointerValuePair<P, V>::operator*() const -{ - if (d.isT1()) return d.asT1(); - else return d.asT2()->pointer; -} - -template<typename P, typename V> -bool QPointerValuePair<P, V>::hasValue() const -{ - return d.isT2(); -} - -template<typename P, typename V> -V &QPointerValuePair<P, V>::value() -{ - if (d.isT1()) { - P *p = d.asT1(); - Value *value = new Value; - value->pointer = p; - d = value; - } - - return d.asT2()->value; -} - -// Will return null if hasValue() == false -template<typename P, typename V> -const V *QPointerValuePair<P, V>::constValue() const -{ - if (d.isT2()) return &d.asT2()->value; - else return 0; -} - -QT_END_NAMESPACE - -#endif // QPOINTERVALUEPAIR_P_H diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri index 4d84cc82ae..8d8da3742d 100644 --- a/src/qml/qml/qml.pri +++ b/src/qml/qml/qml.pri @@ -12,7 +12,6 @@ SOURCES += \ $$PWD/qqmlpropertyvalueinterceptor.cpp \ $$PWD/qqmlproxymetaobject.cpp \ $$PWD/qqmlvme.cpp \ - $$PWD/qqmlcompileddata.cpp \ $$PWD/qqmlboundsignal.cpp \ $$PWD/qqmlmetatype.cpp \ $$PWD/qqmlstringconverters.cpp \ @@ -21,7 +20,6 @@ SOURCES += \ $$PWD/qqmlinfo.cpp \ $$PWD/qqmlerror.cpp \ $$PWD/qqmlvaluetype.cpp \ - $$PWD/qqmlaccessors.cpp \ $$PWD/qqmlxmlhttprequest.cpp \ $$PWD/qqmlcleanup.cpp \ $$PWD/qqmlpropertycache.cpp \ @@ -39,7 +37,6 @@ SOURCES += \ $$PWD/qqmlvaluetypeproxybinding.cpp \ $$PWD/qqmlglobal.cpp \ $$PWD/qqmlfile.cpp \ - $$PWD/qqmlmemoryprofiler.cpp \ $$PWD/qqmlplatform.cpp \ $$PWD/qqmlbinding.cpp \ $$PWD/qqmlabstracturlinterceptor.cpp \ @@ -50,7 +47,9 @@ SOURCES += \ $$PWD/qqmltypewrapper.cpp \ $$PWD/qqmlfileselector.cpp \ $$PWD/qqmlobjectcreator.cpp \ - $$PWD/qqmldirparser.cpp + $$PWD/qqmldirparser.cpp \ + $$PWD/qqmldelayedcallqueue.cpp \ + $$PWD/qqmlloggingcategory.cpp HEADERS += \ $$PWD/qqmlglobal_p.h \ @@ -70,7 +69,6 @@ HEADERS += \ $$PWD/qqmlparserstatus.h \ $$PWD/qqmlproxymetaobject_p.h \ $$PWD/qqmlvme_p.h \ - $$PWD/qqmlcompiler_p.h \ $$PWD/qqmlengine_p.h \ $$PWD/qqmlexpression_p.h \ $$PWD/qqmlprivate.h \ @@ -88,10 +86,10 @@ HEADERS += \ $$PWD/qqmldata_p.h \ $$PWD/qqmlerror.h \ $$PWD/qqmlvaluetype_p.h \ - $$PWD/qqmlaccessors_p.h \ $$PWD/qqmlxmlhttprequest_p.h \ $$PWD/qqmlcleanup_p.h \ $$PWD/qqmlpropertycache_p.h \ + $$PWD/qqmlpropertyindex_p.h \ $$PWD/qqmlnotifier_p.h \ $$PWD/qqmltypenotavailable_p.h \ $$PWD/qqmltypenamecache_p.h \ @@ -108,7 +106,6 @@ HEADERS += \ $$PWD/qqmlabstractbinding_p.h \ $$PWD/qqmlvaluetypeproxybinding_p.h \ $$PWD/qqmlfile.h \ - $$PWD/qqmlmemoryprofiler_p.h \ $$PWD/qqmlplatform_p.h \ $$PWD/qqmlbinding_p.h \ $$PWD/qqmlextensionplugin_p.h \ @@ -122,7 +119,9 @@ HEADERS += \ $$PWD/qqmlfileselector_p.h \ $$PWD/qqmlfileselector.h \ $$PWD/qqmlobjectcreator_p.h \ - $$PWD/qqmldirparser_p.h + $$PWD/qqmldirparser_p.h \ + $$PWD/qqmldelayedcallqueue_p.h \ + $$PWD/qqmlloggingcategory_p.h include(ftw/ftw.pri) include(v8/v8.pri) diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index 8fb710ad9d..39764b8001 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -238,6 +238,9 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); } + +Q_QML_EXPORT int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject, const char *uri, int versionMajor, int versionMinor, const char *qmlName, const QString& reason); + template<typename T> int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName) { diff --git a/src/qml/qml/qqmlabstractbinding.cpp b/src/qml/qml/qqmlabstractbinding.cpp index abaf95fa11..39d609454f 100644 --- a/src/qml/qml/qqmlabstractbinding.cpp +++ b/src/qml/qml/qqmlabstractbinding.cpp @@ -78,24 +78,26 @@ void QQmlAbstractBinding::addToObject() QQmlData *data = QQmlData::get(obj, true); - int coreIndex; - if (QQmlPropertyData::decodeValueTypePropertyIndex(targetPropertyIndex(), &coreIndex) != -1) { + int coreIndex = targetPropertyIndex().coreIndex(); + if (targetPropertyIndex().hasValueTypeIndex()) { // Value type // Find the value type proxy (if there is one) QQmlValueTypeProxyBinding *proxy = 0; if (data->hasBindingBit(coreIndex)) { QQmlAbstractBinding *b = data->bindings; - while (b && b->targetPropertyIndex() != coreIndex) + while (b && (b->targetPropertyIndex().coreIndex() != coreIndex || + b->targetPropertyIndex().hasValueTypeIndex())) b = b->nextBinding(); Q_ASSERT(b && b->isValueTypeProxy()); proxy = static_cast<QQmlValueTypeProxyBinding *>(b); } if (!proxy) { - proxy = new QQmlValueTypeProxyBinding(obj, coreIndex); + proxy = new QQmlValueTypeProxyBinding(obj, QQmlPropertyIndex(coreIndex)); - Q_ASSERT(proxy->targetPropertyIndex() == coreIndex); + Q_ASSERT(proxy->targetPropertyIndex().coreIndex() == coreIndex); + Q_ASSERT(!proxy->targetPropertyIndex().hasValueTypeIndex()); Q_ASSERT(proxy->targetObject() == obj); proxy->addToObject(); @@ -137,12 +139,13 @@ void QQmlAbstractBinding::removeFromObject() next = nextBinding(); setNextBinding(0); - int coreIndex; - if (QQmlPropertyData::decodeValueTypePropertyIndex(targetPropertyIndex(), &coreIndex) != -1) { + int coreIndex = targetPropertyIndex().coreIndex(); + if (targetPropertyIndex().hasValueTypeIndex()) { // Find the value type binding QQmlAbstractBinding *vtbinding = data->bindings; - while (vtbinding->targetPropertyIndex() != coreIndex) { + while (vtbinding && (vtbinding->targetPropertyIndex().coreIndex() != coreIndex || + vtbinding->targetPropertyIndex().hasValueTypeIndex())) { vtbinding = vtbinding->nextBinding(); Q_ASSERT(vtbinding); } diff --git a/src/qml/qml/qqmlabstractbinding_p.h b/src/qml/qml/qqmlabstractbinding_p.h index 674178153a..bea2d253e4 100644 --- a/src/qml/qml/qqmlabstractbinding_p.h +++ b/src/qml/qml/qqmlabstractbinding_p.h @@ -55,7 +55,6 @@ #include <QtCore/qshareddata.h> #include <private/qtqmlglobal_p.h> #include <private/qqmlproperty_p.h> -#include <private/qpointervaluepair_p.h> QT_BEGIN_NAMESPACE @@ -77,13 +76,13 @@ public: // Should return the encoded property index for the binding. Should return this value // even if the binding is not enabled or added to an object. // Encoding is: coreIndex | (valueTypeIndex << 16) - int targetPropertyIndex() const { return m_targetIndex; } + QQmlPropertyIndex targetPropertyIndex() const { return m_targetIndex; } // Should return the object for the binding. Should return this object even if the // binding is not enabled or added to the object. QObject *targetObject() const { return m_target.data(); } - virtual void setEnabled(bool e, QQmlPropertyPrivate::WriteFlags f = QQmlPropertyPrivate::DontRemoveBinding) = 0; + virtual void setEnabled(bool e, QQmlPropertyData::WriteFlags f = QQmlPropertyData::DontRemoveBinding) = 0; void addToObject(); void removeFromObject(); @@ -92,6 +91,8 @@ public: inline QQmlAbstractBinding *nextBinding() const; + inline bool canUseAccessor() const + { return m_nextBinding.flag2(); } struct RefCount { RefCount() : refCount(0) {} @@ -112,9 +113,16 @@ protected: inline void setNextBinding(QQmlAbstractBinding *); - int m_targetIndex; + QQmlPropertyIndex m_targetIndex; + + // Pointer is the target object to which the binding binds + // flag1 is the updating flag + // flag2 is the enabled flag QFlagPointer<QObject> m_target; + // Pointer to the next binding in the linked list of bindings. + // flag1 is used for addedToObject + // flag2 indicates if an accessor is can be used (i.e. there is no interceptor on the target) QFlagPointer<QQmlAbstractBinding> m_nextBinding; }; diff --git a/src/qml/qml/qqmlaccessors_p.h b/src/qml/qml/qqmlaccessors_p.h deleted file mode 100644 index 55562a5307..0000000000 --- a/src/qml/qml/qqmlaccessors_p.h +++ /dev/null @@ -1,177 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLACCESSORS_P_H -#define QQMLACCESSORS_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <private/qtqmlglobal_p.h> -#include <QtCore/qbytearray.h> -#include <QtCore/qvector.h> -#include <QtCore/qhash.h> -#include <QtCore/QReadWriteLock> - -#if defined(Q_OS_QNX) || defined(Q_OS_LINUX) -#include <stdint.h> -#endif - -QT_BEGIN_NAMESPACE - -class QObject; -struct QMetaObject; -class QQmlNotifier; - -// QML "accessor properties" allow V4 and V8 to bypass Qt's meta system to read and, more -// importantly, subscribe to properties directly. Any property that is primarily read -// from bindings is a candidate for inclusion as an accessor property. -// -// To define accessor properties, use the QML_DECLARE_PROPERTIES() and QML_DEFINE_PROPERTIES() -// macros. The QML_DECLARE_PROPERTIES() macro is used to specify the properties, and the -// QML_DEFINE_PROPERTIES() macro to register the properties with the -// QQmlAccessorProperties singleton. -// -// A class with accessor properties must also add the Q_CLASSINFO("qt_HasQmlAccessors", "true") -// tag to its declaration. This is essential for QML to maintain internal consistency, -// and forgetting to do so will probably cause your application to qFatal() with a -// helpful reminder of this requirement. -// -// It is important that QML_DEFINE_PROPERTIES() has been called before QML ever sees -// the type with the accessor properties. As QML_DEFINE_PROPERTIES() is idempotent, it is -// recommended to call it in the type's constructor as well as when the type is registered -// as a QML element (if it ever is). QML_DEFINE_PROPERTIES() is a very cheap operation -// if registration has already occurred. - -#define QML_DECLARE_PROPERTIES(type) \ - static volatile bool qqml_accessor_properties_isregistered_ ## type = false; \ - static QQmlAccessorProperties::Property qqml_accessor_properties_ ## type[] = - -#define QML_DEFINE_PROPERTIES(type) \ - do { \ - if (!qqml_accessor_properties_isregistered_ ## type) { \ - int count = sizeof(qqml_accessor_properties_ ## type) / \ - sizeof(QQmlAccessorProperties::Property); \ - QQmlAccessorProperties::registerProperties(&type::staticMetaObject, count, \ - qqml_accessor_properties_ ## type);\ - qqml_accessor_properties_isregistered_ ## type = true; \ - } \ - } while (false); - -#define QML_PRIVATE_ACCESSOR(clazz, cpptype, name, variable) \ - static void clazz ## _ ## name ## Read(QObject *o, void *rv) \ - { \ - clazz ## Private *d = clazz ## Private::get(static_cast<clazz *>(o)); \ - *static_cast<cpptype *>(rv) = d->variable; \ - } - -#define QML_PROPERTY_NAME(name) #name, sizeof #name - 1 - -class QQmlAccessors -{ -public: - void (*read)(QObject *object, void *output); - void (*notifier)(QObject *object, QQmlNotifier **notifier); -}; - -namespace QQmlAccessorProperties { - struct Property { - const char *name; - unsigned int nameLength; - qintptr data; - QQmlAccessors *accessors; - }; - - struct Properties { - inline Properties(); - Properties(Property *, int); - - bool operator==(const Properties &o) const { - return count == o.count && properties == o.properties; - } - - inline Property *property(const char *name); - - int count; - Property *properties; - quint32 nameMask; - }; - - Properties properties(const QMetaObject *); - void Q_QML_PRIVATE_EXPORT registerProperties(const QMetaObject *, int, Property *); -}; - -QQmlAccessorProperties::Property * -QQmlAccessorProperties::Properties::property(const char *name) -{ - if (count == 0) - return 0; - - const unsigned int length = (unsigned int)strlen(name); - - Q_ASSERT(length); - - if (nameMask & (1 << qMin(31U, length - 1))) { - - for (int ii = 0; ii < count; ++ii) { - if (properties[ii].nameLength == length && 0 == qstrcmp(name, properties[ii].name)) - return &properties[ii]; - } - - } - - return 0; -} - -QQmlAccessorProperties::Properties::Properties() -: count(0), properties(0), nameMask(0) -{ -} - -QT_END_NAMESPACE - -#endif // QQMLACCESSORS_P_H diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp index 57cdd3f47f..fef2da753b 100644 --- a/src/qml/qml/qqmlapplicationengine.cpp +++ b/src/qml/qml/qqmlapplicationengine.cpp @@ -69,6 +69,7 @@ void QQmlApplicationEnginePrivate::init() q->connect(&statusMapper, SIGNAL(mapped(QObject*)), q, SLOT(_q_finishLoad(QObject*))); q->connect(q, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit())); + q->connect(q, &QQmlApplicationEngine::exit, QCoreApplication::instance(), &QCoreApplication::exit); #ifndef QT_NO_TRANSLATION QTranslator* qtTranslator = new QTranslator; if (qtTranslator->load(QLatin1String("qt_") + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath))) @@ -134,7 +135,7 @@ void QQmlApplicationEnginePrivate::_q_finishLoad(QObject *o) break; case QQmlComponent::Ready: objects << c->create(); - q->objectCreated(objects.last(), c->url()); + q->objectCreated(objects.constLast(), c->url()); break; case QQmlComponent::Loading: case QQmlComponent::Null: @@ -211,11 +212,8 @@ QQmlApplicationEngine::QQmlApplicationEngine(QObject *parent) This is provided as a convenience, and is the same as using the empty constructor and calling load afterwards. */ QQmlApplicationEngine::QQmlApplicationEngine(const QUrl &url, QObject *parent) - : QQmlEngine(*(new QQmlApplicationEnginePrivate(this)), parent) + : QQmlApplicationEngine(parent) { - Q_D(QQmlApplicationEngine); - d->init(); - QJSEnginePrivate::addToDebugServer(this); load(url); } @@ -228,12 +226,8 @@ QQmlApplicationEngine::QQmlApplicationEngine(const QUrl &url, QObject *parent) This is provided as a convenience, and is the same as using the empty constructor and calling load afterwards. */ QQmlApplicationEngine::QQmlApplicationEngine(const QString &filePath, QObject *parent) - : QQmlEngine(*(new QQmlApplicationEnginePrivate(this)), parent) + : QQmlApplicationEngine(QUrl::fromLocalFile(filePath), parent) { - Q_D(QQmlApplicationEngine); - d->init(); - QJSEnginePrivate::addToDebugServer(this); - load(QUrl::fromLocalFile(filePath)); } /*! diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index 1249e1b6c8..203bfec838 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -42,7 +42,6 @@ #include "qqml.h" #include "qqmlcontext.h" #include "qqmlinfo.h" -#include "qqmlcompiler_p.h" #include "qqmldata_p.h" #include <private/qqmlprofiler_p.h> #include <private/qqmlexpression_p.h> @@ -51,33 +50,36 @@ #include <private/qqmlbuiltinfunctions_p.h> #include <private/qqmlvmemetaobject_p.h> #include <private/qqmlvaluetypewrapper_p.h> +#include <private/qv4qobjectwrapper_p.h> +#include <private/qv4variantobject_p.h> #include <QVariant> #include <QtCore/qdebug.h> QT_BEGIN_NAMESPACE -QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContext *ctxt) - : QQmlJavaScriptExpression(), - QQmlAbstractBinding() +QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj, QQmlContext *ctxt) { - setNotifyOnValueChanged(true); - QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt)); - setScopeObject(obj); + QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property); + b->setNotifyOnValueChanged(true); + b->QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt)); + b->setScopeObject(obj); - createQmlBinding(context(), obj, str, QString(), 0); + b->createQmlBinding(b->context(), obj, str, QString(), 0); + + return b; } -QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt) - : QQmlJavaScriptExpression(), - QQmlAbstractBinding() +QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt) { + QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property); + if (ctxt && !ctxt->isValid()) - return; + return b; const QQmlScriptStringPrivate *scriptPrivate = script.d.data(); if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid())) - return; + return b; QString url; QV4::Function *runtimeFunction = 0; @@ -90,53 +92,61 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte runtimeFunction = ctxtdata->typeCompilationUnit->runtimeFunctions.at(scriptPrivate->bindingId); } - setNotifyOnValueChanged(true); - QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context)); - setScopeObject(obj ? obj : scriptPrivate->scope); + b->setNotifyOnValueChanged(true); + b->QQmlJavaScriptExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context)); + b->setScopeObject(obj ? obj : scriptPrivate->scope); - QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(context()->engine)->v4engine(); + QV4::ExecutionEngine *v4 = QQmlEnginePrivate::get(b->context()->engine)->v4engine(); if (runtimeFunction) { - m_function.set(v4, QV4::FunctionObject::createQmlFunction(ctxtdata, scopeObject(), runtimeFunction)); + b->m_function.set(v4, QV4::FunctionObject::createQmlFunction(ctxtdata, b->scopeObject(), runtimeFunction)); } else { QString code = scriptPrivate->script; - createQmlBinding(context(), scopeObject(), code, url, scriptPrivate->lineNumber); + b->createQmlBinding(b->context(), b->scopeObject(), code, url, scriptPrivate->lineNumber); } + + return b; } -QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt) - : QQmlJavaScriptExpression(), - QQmlAbstractBinding() +QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj, QQmlContextData *ctxt) { - setNotifyOnValueChanged(true); - QQmlJavaScriptExpression::setContext(ctxt); - setScopeObject(obj); + QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property); + + b->setNotifyOnValueChanged(true); + b->QQmlJavaScriptExpression::setContext(ctxt); + b->setScopeObject(obj); - createQmlBinding(ctxt, obj, str, QString(), 0); + b->createQmlBinding(ctxt, obj, str, QString(), 0); + + return b; } -QQmlBinding::QQmlBinding(const QString &str, QObject *obj, - QQmlContextData *ctxt, - const QString &url, quint16 lineNumber, quint16 columnNumber) - : QQmlJavaScriptExpression(), - QQmlAbstractBinding() +QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QString &str, QObject *obj, + QQmlContextData *ctxt, const QString &url, quint16 lineNumber, + quint16 columnNumber) { + QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property); + Q_UNUSED(columnNumber); - setNotifyOnValueChanged(true); - QQmlJavaScriptExpression::setContext(ctxt); - setScopeObject(obj); + b->setNotifyOnValueChanged(true); + b->QQmlJavaScriptExpression::setContext(ctxt); + b->setScopeObject(obj); - createQmlBinding(ctxt, obj, str, url, lineNumber); + b->createQmlBinding(ctxt, obj, str, url, lineNumber); + + return b; } -QQmlBinding::QQmlBinding(const QV4::Value &functionPtr, QObject *obj, QQmlContextData *ctxt) - : QQmlJavaScriptExpression(), - QQmlAbstractBinding() +QQmlBinding *QQmlBinding::create(const QQmlPropertyData *property, const QV4::Value &functionPtr, QObject *obj, QQmlContextData *ctxt) { - setNotifyOnValueChanged(true); - QQmlJavaScriptExpression::setContext(ctxt); - setScopeObject(obj); + QQmlBinding *b = newBinding(QQmlEnginePrivate::get(ctxt), property); + + b->setNotifyOnValueChanged(true); + b->QQmlJavaScriptExpression::setContext(ctxt); + b->setScopeObject(obj); - m_function.set(functionPtr.as<QV4::Object>()->engine(), functionPtr); + b->m_function.set(functionPtr.as<QV4::Object>()->engine(), functionPtr); + + return b; } QQmlBinding::~QQmlBinding() @@ -148,7 +158,7 @@ void QQmlBinding::setNotifyOnValueChanged(bool v) QQmlJavaScriptExpression::setNotifyOnValueChanged(v); } -void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) +void QQmlBinding::update(QQmlPropertyData::WriteFlags flags) { if (!enabledFlag() || !context() || !context()->isValid()) return; @@ -157,44 +167,75 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) if (QQmlData::wasDeleted(targetObject())) return; - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); - QV4::Scope scope(ep->v4engine()); - QV4::ScopedFunctionObject f(scope, m_function.value()); - Q_ASSERT(f); - - if (updatingFlag()) { - QQmlProperty p = QQmlPropertyPrivate::restore(targetObject(), getPropertyData(), 0); + // Check for a binding update loop + if (Q_UNLIKELY(updatingFlag())) { + QQmlPropertyData *d = nullptr; + QQmlPropertyData vtd; + getPropertyData(&d, &vtd); + Q_ASSERT(d); + QQmlProperty p = QQmlPropertyPrivate::restore(targetObject(), *d, &vtd, 0); QQmlAbstractBinding::printBindingLoopError(p); return; } - - QQmlBindingProfiler prof(ep->profiler, this, f); setUpdatingFlag(true); - QQmlJavaScriptExpression::DeleteWatcher watcher(this); + DeleteWatcher watcher(this); + + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()->engine); + QV4::Scope scope(ep->v4engine()); + QV4::ScopedFunctionObject f(scope, m_function.value()); + Q_ASSERT(f); - QQmlPropertyData pd = getPropertyData(); + if (canUseAccessor()) + flags.setFlag(QQmlPropertyData::BypassInterceptor); - if (pd.propType == qMetaTypeId<QQmlBinding *>()) { + QQmlBindingProfiler prof(ep->profiler, this, f); + doUpdate(watcher, flags, scope, f); - int idx = pd.coreIndex; - Q_ASSERT(idx != -1); + if (!watcher.wasDeleted()) + setUpdatingFlag(false); +} - QQmlBinding *t = this; - int status = -1; - void *a[] = { &t, 0, &status, &flags }; - QMetaObject::metacall(*m_target, QMetaObject::WriteProperty, idx, a); +// QQmlBindingBinding is for target properties which are of type "binding" (instead of, say, int or +// double). The reason for being is that GenericBinding::fastWrite needs a compile-time constant +// expression for the switch for the compiler to generate the optimal code, but +// qMetaTypeId<QQmlBinding *>() needs to be used for the ID. So QQmlBinding::newBinding uses that +// to instantiate this class. +class QQmlBindingBinding: public QQmlBinding +{ +protected: + void doUpdate(const DeleteWatcher &, + QQmlPropertyData::WriteFlags flags, QV4::Scope &, + const QV4::ScopedFunctionObject &) Q_DECL_OVERRIDE Q_DECL_FINAL + { + Q_ASSERT(!m_targetIndex.hasValueTypeIndex()); + QQmlPropertyData *pd = nullptr; + getPropertyData(&pd, nullptr); + QQmlBinding *thisPtr = this; + pd->writeProperty(*m_target, &thisPtr, flags); + } +}; - } else { +// For any target that's not a binding, we have a common doUpdate. However, depending on the type +// of the target property, there is a specialized write method. +class QQmlNonbindingBinding: public QQmlBinding +{ +protected: + void doUpdate(const DeleteWatcher &watcher, + QQmlPropertyData::WriteFlags flags, QV4::Scope &scope, + const QV4::ScopedFunctionObject &f) Q_DECL_OVERRIDE Q_DECL_FINAL + { + auto ep = QQmlEnginePrivate::get(scope.engine); ep->referenceScarceResources(); bool isUndefined = false; - QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined)); + QV4::ScopedCallData callData(scope); + QQmlJavaScriptExpression::evaluate(callData, &isUndefined, scope); bool error = false; if (!watcher.wasDeleted() && isAddedToObject() && !hasError()) - error = !write(pd, result, isUndefined, flags); + error = !write(scope.result, isUndefined, flags); if (!watcher.wasDeleted()) { @@ -211,66 +252,88 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) } + cancelPermanentGuards(); + ep->dereferenceScarceResources(); } - if (!watcher.wasDeleted()) - setUpdatingFlag(false); -} + virtual bool write(const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags) = 0; +}; -// Returns true if successful, false if an error description was set on expression -bool QQmlBinding::write(const QQmlPropertyData &core, - const QV4::Value &result, bool isUndefined, - QQmlPropertyPrivate::WriteFlags flags) +template<int StaticPropType> +class GenericBinding: public QQmlNonbindingBinding { - Q_ASSERT(m_target.data()); - Q_ASSERT(core.coreIndex != -1); - -#define QUICK_STORE(cpptype, conversion) \ - { \ - cpptype o = (conversion); \ - int status = -1; \ - void *argv[] = { &o, 0, &status, &flags }; \ - QMetaObject::metacall(m_target.data(), QMetaObject::WriteProperty, core.coreIndex, argv); \ - return true; \ - } \ - - - if (Q_LIKELY(!isUndefined && !core.isValueTypeVirtual())) { - switch (core.propType) { - case QMetaType::Int: - if (result.isInteger()) - QUICK_STORE(int, result.integerValue()) - else if (result.isNumber()) - QUICK_STORE(int, result.doubleValue()) - break; - case QMetaType::Double: - if (result.isNumber()) - QUICK_STORE(double, result.asDouble()) - break; - case QMetaType::Float: - if (result.isNumber()) - QUICK_STORE(float, result.asDouble()) - break; - case QMetaType::QString: - if (result.isString()) - QUICK_STORE(QString, result.toQStringNoThrow()) - break; - default: - if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) { - if (vtw->d()->valueType->typeId == core.propType) { - return vtw->write(m_target.data(), core.coreIndex); +protected: + // Returns true if successful, false if an error description was set on expression + Q_ALWAYS_INLINE bool write(const QV4::Value &result, bool isUndefined, + QQmlPropertyData::WriteFlags flags) Q_DECL_OVERRIDE Q_DECL_FINAL + { + Q_ASSERT(targetObject()); + + QQmlPropertyData *pd; + QQmlPropertyData vpd; + getPropertyData(&pd, &vpd); + Q_ASSERT(pd); + + int propertyType = StaticPropType; // If the binding is specialized to a type, the if and switch below will be constant-folded. + if (propertyType == QMetaType::UnknownType) + propertyType = pd->propType(); + + if (Q_LIKELY(!isUndefined && !vpd.isValid())) { + switch (propertyType) { + case QMetaType::Bool: + if (result.isBoolean()) + return doStore<bool>(result.booleanValue(), pd, flags); + else + return doStore<bool>(result.toBoolean(), pd, flags); + case QMetaType::Int: + if (result.isInteger()) + return doStore<int>(result.integerValue(), pd, flags); + else if (result.isNumber()) + return doStore<int>(result.doubleValue(), pd, flags); + break; + case QMetaType::Double: + if (result.isNumber()) + return doStore<double>(result.asDouble(), pd, flags); + break; + case QMetaType::Float: + if (result.isNumber()) + return doStore<float>(result.asDouble(), pd, flags); + break; + case QMetaType::QString: + if (result.isString()) + return doStore<QString>(result.toQStringNoThrow(), pd, flags); + break; + default: + if (const QV4::QQmlValueTypeWrapper *vtw = result.as<const QV4::QQmlValueTypeWrapper>()) { + if (vtw->d()->valueType->typeId == pd->propType()) { + return vtw->write(m_target.data(), pd->coreIndex()); + } } + break; } - break; } + + return slowWrite(*pd, vpd, result, isUndefined, flags); + } + + template <typename T> + Q_ALWAYS_INLINE bool doStore(T value, const QQmlPropertyData *pd, QQmlPropertyData::WriteFlags flags) const + { + void *o = &value; + return pd->writeProperty(targetObject(), o, flags); } -#undef QUICK_STORE +}; +Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core, + const QQmlPropertyData &valueTypeData, + const QV4::Value &result, + bool isUndefined, QQmlPropertyData::WriteFlags flags) +{ QQmlEngine *engine = context()->engine; QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine); - int type = core.isValueTypeVirtual() ? core.valueTypePropType : core.propType; + int type = valueTypeData.isValid() ? valueTypeData.propType() : core.propType(); QQmlJavaScriptExpression::DeleteWatcher watcher(this); @@ -282,7 +345,7 @@ bool QQmlBinding::write(const QQmlPropertyData &core, value = QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QObject *> >()); } else if (result.isNull() && core.isQObject()) { value = QVariant::fromValue((QObject *)0); - } else if (core.propType == qMetaTypeId<QList<QUrl> >()) { + } else if (core.propType() == qMetaTypeId<QList<QUrl> >()) { value = QQmlPropertyPrivate::resolvedUrlSequence(QV8Engine::getV4(v8engine)->toVariant(result, qMetaTypeId<QList<QUrl> >()), context()); } else if (!isVarProperty && type != qMetaTypeId<QJSValue>()) { value = QV8Engine::getV4(v8engine)->toVariant(result, type); @@ -301,28 +364,27 @@ bool QQmlBinding::write(const QQmlPropertyData &core, QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_target.data()); Q_ASSERT(vmemo); - vmemo->setVMEProperty(core.coreIndex, result); + vmemo->setVMEProperty(core.coreIndex(), result); } else if (isUndefined && core.isResettable()) { void *args[] = { 0 }; - QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex, args); + QMetaObject::metacall(m_target.data(), QMetaObject::ResetProperty, core.coreIndex(), args); } else if (isUndefined && type == qMetaTypeId<QVariant>()) { - QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, QVariant(), context(), flags); + QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, QVariant(), context(), flags); } else if (type == qMetaTypeId<QJSValue>()) { const QV4::FunctionObject *f = result.as<QV4::FunctionObject>(); if (f && f->isBinding()) { delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration.")); return false; } - QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, QVariant::fromValue( + QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, QVariant::fromValue( QJSValue(QV8Engine::getV4(v8engine), result.asReturnedValue())), context(), flags); } else if (isUndefined) { - QString errorStr = QLatin1String("Unable to assign [undefined] to "); - if (!QMetaType::typeName(type)) - errorStr += QLatin1String("[unknown property type]"); - else - errorStr += QLatin1String(QMetaType::typeName(type)); - delayedError()->setErrorDescription(errorStr); + const QLatin1String typeName(QMetaType::typeName(type) + ? QMetaType::typeName(type) + : "[unknown property type]"); + delayedError()->setErrorDescription(QLatin1String("Unable to assign [undefined] to ") + + typeName); return false; } else if (const QV4::FunctionObject *f = result.as<QV4::FunctionObject>()) { if (f->isBinding()) @@ -330,7 +392,7 @@ bool QQmlBinding::write(const QQmlPropertyData &core, else delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var.")); return false; - } else if (!QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, value, context(), flags)) { + } else if (!QQmlPropertyPrivate::writeValueProperty(m_target.data(), core, valueTypeData, value, context(), flags)) { if (watcher.wasDeleted()) return true; @@ -338,7 +400,8 @@ bool QQmlBinding::write(const QQmlPropertyData &core, const char *valueType = 0; const char *propertyType = 0; - if (value.userType() == QMetaType::QObjectStar) { + const int userType = value.userType(); + if (userType == QMetaType::QObjectStar) { if (QObject *o = *(QObject *const *)value.constData()) { valueType = o->metaObject()->className(); @@ -346,11 +409,11 @@ bool QQmlBinding::write(const QQmlPropertyData &core, if (!propertyMetaObject.isNull()) propertyType = propertyMetaObject.className(); } - } else if (value.userType() != QVariant::Invalid) { - if (value.userType() == QMetaType::VoidStar) + } else if (userType != QVariant::Invalid) { + if (userType == QMetaType::Nullptr || userType == QMetaType::VoidStar) valueType = "null"; else - valueType = QMetaType::typeName(value.userType()); + valueType = QMetaType::typeName(userType); } if (!valueType) @@ -378,11 +441,12 @@ QVariant QQmlBinding::evaluate() bool isUndefined = false; QV4::Scope scope(ep->v4engine()); - QV4::ScopedValue result(scope, QQmlJavaScriptExpression::evaluate(&isUndefined)); + QV4::ScopedCallData callData(scope); + QQmlJavaScriptExpression::evaluate(callData, &isUndefined, scope); ep->dereferenceScarceResources(); - return scope.engine->toVariant(result, qMetaTypeId<QList<QObject*> >()); + return scope.engine->toVariant(scope.result, qMetaTypeId<QList<QObject*> >()); } QString QQmlBinding::expressionIdentifier() @@ -395,8 +459,7 @@ QString QQmlBinding::expressionIdentifier() QString url = function->sourceFile(); quint16 lineNumber = function->compiledFunction->location.line; quint16 columnNumber = function->compiledFunction->location.column; - - return url + QLatin1Char(':') + QString::number(lineNumber) + QLatin1Char(':') + QString::number(columnNumber); + return url + QString::asprintf(":%u:%u", uint(lineNumber), uint(columnNumber)); } void QQmlBinding::expressionChanged() @@ -409,11 +472,17 @@ void QQmlBinding::refresh() update(); } -void QQmlBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags) +void QQmlBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags) { setEnabledFlag(e); setNotifyOnValueChanged(e); + m_nextBinding.setFlag2(); // Always use accessors, only not when: + if (auto interceptorMetaObject = QQmlInterceptorMetaObject::get(targetObject())) { + if (!m_targetIndex.isValid() || interceptorMetaObject->intercepts(m_targetIndex)) + m_nextBinding.clearFlag2(); + } + if (e) update(flags); } @@ -427,29 +496,28 @@ QString QQmlBinding::expression() const void QQmlBinding::setTarget(const QQmlProperty &prop) { - setTarget(prop.object(), QQmlPropertyPrivate::get(prop)->core); + auto pd = QQmlPropertyPrivate::get(prop); + setTarget(prop.object(), pd->core, &pd->valueTypeData); } -void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core) +void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const QQmlPropertyData *valueType) { m_target = object; if (!object) { - m_targetIndex = -1; + m_targetIndex = QQmlPropertyIndex(); return; } - QQmlPropertyData pd = core; - - while (pd.isAlias()) { - int coreIndex = pd.coreIndex; - int valueTypeIndex = pd.getValueTypeCoreIndex(); + int coreIndex = core.coreIndex(); + int valueTypeIndex = valueType ? valueType->coreIndex() : -1; + for (bool isAlias = core.isAlias(); isAlias; ) { QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex); int aValueTypeIndex; if (!vme->aliasTarget(coreIndex, &object, &coreIndex, &aValueTypeIndex)) { m_target = 0; - m_targetIndex = -1; + m_targetIndex = QQmlPropertyIndex(); return; } if (valueTypeIndex == -1) @@ -458,25 +526,17 @@ void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core) QQmlData *data = QQmlData::get(object, false); if (!data || !data->propertyCache) { m_target = 0; - m_targetIndex = -1; + m_targetIndex = QQmlPropertyIndex(); return; } QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex); Q_ASSERT(propertyData); m_target = object; - pd = *propertyData; - if (valueTypeIndex != -1) { - const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(pd.propType); - Q_ASSERT(valueTypeMetaObject); - QMetaProperty vtProp = valueTypeMetaObject->property(valueTypeIndex); - pd.setFlags(pd.getFlags() | QQmlPropertyData::IsValueTypeVirtual); - pd.valueTypeFlags = QQmlPropertyData::flagsForProperty(vtProp); - pd.valueTypePropType = vtProp.userType(); - pd.valueTypeCoreIndex = valueTypeIndex; - } + isAlias = propertyData->isAlias(); + coreIndex = propertyData->coreIndex(); } - m_targetIndex = pd.encodedIndex(); + m_targetIndex = QQmlPropertyIndex(coreIndex, valueTypeIndex); QQmlData *data = QQmlData::get(*m_target, true); if (!data->propertyCache) { @@ -485,28 +545,110 @@ void QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core) } } -QQmlPropertyData QQmlBinding::getPropertyData() const +void QQmlBinding::getPropertyData(QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const { - int coreIndex; - int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(m_targetIndex, &coreIndex); + Q_ASSERT(propertyData); QQmlData *data = QQmlData::get(*m_target, false); Q_ASSERT(data && data->propertyCache); - QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex); - Q_ASSERT(propertyData); + *propertyData = data->propertyCache->property(m_targetIndex.coreIndex()); + Q_ASSERT(*propertyData); - QQmlPropertyData d = *propertyData; - if (Q_UNLIKELY(valueTypeIndex != -1)) { - const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(d.propType); + if (Q_UNLIKELY(m_targetIndex.hasValueTypeIndex() && valueTypeData)) { + const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType((*propertyData)->propType()); Q_ASSERT(valueTypeMetaObject); - QMetaProperty vtProp = valueTypeMetaObject->property(valueTypeIndex); - d.setFlags(d.getFlags() | QQmlPropertyData::IsValueTypeVirtual); - d.valueTypeFlags = QQmlPropertyData::flagsForProperty(vtProp); - d.valueTypePropType = vtProp.userType(); - d.valueTypeCoreIndex = valueTypeIndex; + QMetaProperty vtProp = valueTypeMetaObject->property(m_targetIndex.valueTypeIndex()); + valueTypeData->setFlags(QQmlPropertyData::flagsForProperty(vtProp)); + valueTypeData->setPropType(vtProp.userType()); + valueTypeData->setCoreIndex(m_targetIndex.valueTypeIndex()); + } +} + +class QObjectPointerBinding: public QQmlNonbindingBinding +{ + QQmlMetaObject targetMetaObject; + +public: + QObjectPointerBinding(QQmlEnginePrivate *engine, int propertyType) + : targetMetaObject(QQmlPropertyPrivate::rawMetaObjectForType(engine, propertyType)) + {} + +protected: + Q_ALWAYS_INLINE bool write(const QV4::Value &result, bool isUndefined, + QQmlPropertyData::WriteFlags flags) Q_DECL_OVERRIDE Q_DECL_FINAL + { + QQmlPropertyData *pd; + QQmlPropertyData vtpd; + getPropertyData(&pd, &vtpd); + if (Q_UNLIKELY(isUndefined || vtpd.isValid())) + return slowWrite(*pd, vtpd, result, isUndefined, flags); + + // Check if the result is a QObject: + QObject *resultObject = nullptr; + QQmlMetaObject resultMo; + if (result.isNull()) { + // Special case: we can always write a nullptr. Don't bother checking anything else. + return pd->writeProperty(targetObject(), &resultObject, flags); + } else if (auto wrapper = result.as<QV4::QObjectWrapper>()) { + resultObject = wrapper->object(); + if (!resultObject) + return pd->writeProperty(targetObject(), &resultObject, flags); + if (QQmlData *ddata = QQmlData::get(resultObject, false)) + resultMo = ddata->propertyCache; + if (resultMo.isNull()) { + resultMo = resultObject->metaObject(); + } + } else if (auto variant = result.as<QV4::VariantObject>()) { + QVariant value = variant->d()->data(); + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context()); + resultMo = QQmlPropertyPrivate::rawMetaObjectForType(ep, value.userType()); + if (resultMo.isNull()) + return slowWrite(*pd, vtpd, result, isUndefined, flags); + resultObject = *static_cast<QObject *const *>(value.constData()); + } else { + return slowWrite(*pd, vtpd, result, isUndefined, flags); + } + + // Compare & set: + if (QQmlMetaObject::canConvert(resultMo, targetMetaObject)) { + return pd->writeProperty(targetObject(), &resultObject, flags); + } else if (!resultObject && QQmlMetaObject::canConvert(targetMetaObject, resultMo)) { + // 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. + return pd->writeProperty(targetObject(), &resultObject, flags); + } else { + return slowWrite(*pd, vtpd, result, isUndefined, flags); + } + } +}; + +QQmlBinding *QQmlBinding::newBinding(QQmlEnginePrivate *engine, const QQmlPropertyData *property) +{ + if (property && property->isQObject()) + return new QObjectPointerBinding(engine, property->propType()); + + const int type = (property && property->isFullyResolved()) ? property->propType() : QMetaType::UnknownType; + + if (type == qMetaTypeId<QQmlBinding *>()) { + return new QQmlBindingBinding; + } + + switch (type) { + case QMetaType::Bool: + return new GenericBinding<QMetaType::Bool>; + case QMetaType::Int: + return new GenericBinding<QMetaType::Int>; + case QMetaType::Double: + return new GenericBinding<QMetaType::Double>; + case QMetaType::Float: + return new GenericBinding<QMetaType::Float>; + case QMetaType::QString: + return new GenericBinding<QMetaType::QString>; + default: + return new GenericBinding<QMetaType::UnknownType>; } - return d; } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h index 7814b9dee8..6d42a8ea8a 100644 --- a/src/qml/qml/qqmlbinding_p.h +++ b/src/qml/qml/qqmlbinding_p.h @@ -61,7 +61,6 @@ #include <QtCore/QObject> #include <QtCore/QMetaProperty> -#include <private/qpointervaluepair_p.h> #include <private/qqmlabstractbinding_p.h> #include <private/qqmljavascriptexpression_p.h> @@ -73,26 +72,24 @@ class Q_QML_PRIVATE_EXPORT QQmlBinding : public QQmlJavaScriptExpression, { friend class QQmlAbstractBinding; public: - QQmlBinding(const QString &, QObject *, QQmlContext *); - QQmlBinding(const QQmlScriptString &, QObject *, QQmlContext *); - QQmlBinding(const QString &, QObject *, QQmlContextData *); - QQmlBinding(const QString &, QObject *, QQmlContextData *, - const QString &url, quint16 lineNumber, quint16 columnNumber); - QQmlBinding(const QV4::Value &, QObject *, QQmlContextData *); + static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContext *); + static QQmlBinding *create(const QQmlPropertyData *, const QQmlScriptString &, QObject *, QQmlContext *); + static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContextData *); + static QQmlBinding *create(const QQmlPropertyData *, const QString &, QObject *, QQmlContextData *, + const QString &url, quint16 lineNumber, quint16 columnNumber); + static QQmlBinding *create(const QQmlPropertyData *, const QV4::Value &, QObject *, QQmlContextData *); ~QQmlBinding(); void setTarget(const QQmlProperty &); - void setTarget(QObject *, const QQmlPropertyData &); + void setTarget(QObject *, const QQmlPropertyData &, const QQmlPropertyData *valueType); void setNotifyOnValueChanged(bool); - // Inherited from QQmlJavaScriptExpression - virtual void refresh(); + void refresh() Q_DECL_OVERRIDE; - // Inherited from QQmlAbstractBinding - virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding); - virtual QString expression() const; - void update(QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding); + void setEnabled(bool, QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding) Q_DECL_OVERRIDE; + QString expression() const Q_DECL_OVERRIDE; + void update(QQmlPropertyData::WriteFlags flags = QQmlPropertyData::DontRemoveBinding); typedef int Identifier; enum { @@ -101,20 +98,27 @@ public: QVariant evaluate(); - virtual QString expressionIdentifier(); - virtual void expressionChanged(); + QString expressionIdentifier() Q_DECL_OVERRIDE; + void expressionChanged() Q_DECL_OVERRIDE; + +protected: + virtual void doUpdate(const DeleteWatcher &watcher, + QQmlPropertyData::WriteFlags flags, QV4::Scope &scope, + const QV4::ScopedFunctionObject &f) = 0; + + void getPropertyData(QQmlPropertyData **propertyData, QQmlPropertyData *valueTypeData) const; + int getPropertyType() const; + + bool slowWrite(const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData, + const QV4::Value &result, bool isUndefined, QQmlPropertyData::WriteFlags flags); private: inline bool updatingFlag() const; inline void setUpdatingFlag(bool); inline bool enabledFlag() const; inline void setEnabledFlag(bool); - QQmlPropertyData getPropertyData() const; - - bool write(const QQmlPropertyData &core, - const QV4::Value &result, bool isUndefined, - QQmlPropertyPrivate::WriteFlags flags); + static QQmlBinding *newBinding(QQmlEnginePrivate *engine, const QQmlPropertyData *property); }; bool QQmlBinding::updatingFlag() const diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index c6a7cde240..4e63790290 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -51,14 +51,12 @@ #include <private/qqmlprofiler_p.h> #include <private/qqmldebugconnector_p.h> #include <private/qqmldebugserviceinterfaces_p.h> -#include <private/qqmlcompiler_p.h> #include "qqmlinfo.h" #include <private/qjsvalue_p.h> #include <private/qv4value_p.h> #include <private/qv4qobjectwrapper_p.h> -#include <QtCore/qstringbuilder.h> #include <QtCore/qdebug.h> @@ -82,10 +80,8 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, // Add some leading whitespace to account for the binding's column offset. // It's 2 off because a, we start counting at 1 and b, the '(' below is not counted. - function.fill(QChar(QChar::Space), qMax(column, (quint16)2) - 2); - function += QStringLiteral("(function "); - function += handlerName; - function += QLatin1Char('('); + function += QString(qMax(column, (quint16)2) - 2, QChar(QChar::Space)) + + QLatin1String("(function ") + handlerName + QLatin1Char('('); if (parameterString.isEmpty()) { QString error; @@ -101,10 +97,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index, } else function += parameterString; - function += QStringLiteral(") { "); - function += expression; - function += QStringLiteral(" })"); - + function += QLatin1String(") { ") + expression + QLatin1String(" })"); m_function.set(v4, evalFunction(context(), scopeObject(), function, fileName, line)); if (m_function.isNullOrUndefined()) @@ -213,10 +206,10 @@ void QQmlBoundSignalExpression::evaluate(void **a) ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation. - QVarLengthArray<int, 9> dummy; + QQmlMetaObject::ArgTypeStorage storage; //TODO: lookup via signal index rather than method index as an optimization int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex(); - int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, dummy, 0); + int *argsTypes = QQmlMetaObject(m_target).methodParameterTypes(methodIndex, &storage, 0); int argCount = argsTypes ? *argsTypes : 0; QV4::ScopedCallData callData(scope, argCount); @@ -244,7 +237,7 @@ void QQmlBoundSignalExpression::evaluate(void **a) } } - QQmlJavaScriptExpression::evaluate(callData, 0); + QQmlJavaScriptExpression::evaluate(callData, 0, scope); ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. } @@ -266,7 +259,7 @@ void QQmlBoundSignalExpression::evaluate(const QList<QVariant> &args) callData->args[ii] = scope.engine->fromVariant(args[ii]); } - QQmlJavaScriptExpression::evaluate(callData, 0); + QQmlJavaScriptExpression::evaluate(callData, 0, scope); ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. } diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp deleted file mode 100644 index 28d599a593..0000000000 --- a/src/qml/qml/qqmlcompileddata.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlcompiler_p.h" -#include "qqmlengine.h" -#include "qqmlcomponent.h" -#include "qqmlcomponent_p.h" -#include "qqmlcontext.h" -#include "qqmlcontext_p.h" -#include "qqmlpropertymap.h" -#ifdef QML_THREADED_VME_INTERPRETER -#include "qqmlvme_p.h" -#endif - -#include <QtCore/qdebug.h> - -#include <private/qobject_p.h> - -QT_BEGIN_NAMESPACE - -QQmlCompiledData::QQmlCompiledData(QQmlEngine *engine) -: engine(engine), importCache(0), metaTypeId(-1), listMetaTypeId(-1), isRegisteredWithEngine(false), - rootPropertyCache(0), totalBindingsCount(0), totalParserStatusCount(0) -{ - Q_ASSERT(engine); -} - -void QQmlCompiledData::destroy() -{ - if (engine && hasEngine()) - QQmlEnginePrivate::deleteInEngineThread(engine, this); - else - delete this; -} - -QQmlCompiledData::~QQmlCompiledData() -{ - if (isRegisteredWithEngine) - QQmlEnginePrivate::get(engine)->unregisterInternalCompositeType(this); - - clear(); - - for (QHash<int, TypeReference*>::Iterator resolvedType = resolvedTypes.begin(), end = resolvedTypes.end(); - resolvedType != end; ++resolvedType) { - if ((*resolvedType)->component) - (*resolvedType)->component->release(); - if ((*resolvedType)->typePropertyCache) - (*resolvedType)->typePropertyCache->release(); - } - qDeleteAll(resolvedTypes); - resolvedTypes.clear(); - - for (int ii = 0; ii < propertyCaches.count(); ++ii) - if (propertyCaches.at(ii)) - propertyCaches.at(ii)->release(); - - for (int ii = 0; ii < scripts.count(); ++ii) - scripts.at(ii)->release(); - - if (importCache) - importCache->release(); - - if (rootPropertyCache) - rootPropertyCache->release(); -} - -void QQmlCompiledData::clear() -{ -} - -/*! -Returns the property cache, if one alread exists. The cache is not referenced. -*/ -QQmlPropertyCache *QQmlCompiledData::TypeReference::propertyCache() const -{ - if (type) - return typePropertyCache; - else - return component->rootPropertyCache; -} - -/*! -Returns the property cache, creating one if it doesn't already exist. The cache is not referenced. -*/ -QQmlPropertyCache *QQmlCompiledData::TypeReference::createPropertyCache(QQmlEngine *engine) -{ - if (typePropertyCache) { - return typePropertyCache; - } else if (type) { - typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type->metaObject()); - typePropertyCache->addref(); - return typePropertyCache; - } else { - return component->rootPropertyCache; - } -} - -template <typename T> -bool qtTypeInherits(const QMetaObject *mo) { - while (mo) { - if (mo == &T::staticMetaObject) - return true; - mo = mo->superClass(); - } - return false; -} - -void QQmlCompiledData::TypeReference::doDynamicTypeCheck() -{ - const QMetaObject *mo = 0; - if (typePropertyCache) - mo = typePropertyCache->firstCppMetaObject(); - else if (type) - mo = type->metaObject(); - else if (component) - mo = component->rootPropertyCache->firstCppMetaObject(); - isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo); -} - -void QQmlCompiledData::initialize(QQmlEngine *engine) -{ - Q_ASSERT(!hasEngine()); - QQmlCleanup::addToEngine(engine); - QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); - if (compilationUnit && !compilationUnit->engine) - compilationUnit->linkToEngine(v4); -} - -QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h deleted file mode 100644 index 1c43a85de3..0000000000 --- a/src/qml/qml/qqmlcompiler_p.h +++ /dev/null @@ -1,160 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLCOMPILER_P_H -#define QQMLCOMPILER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qqml.h" -#include "qqmlerror.h" -#include "qqmlengine_p.h" -#include <private/qbitfield_p.h> -#include "qqmlpropertycache_p.h" -#include "qqmltypenamecache_p.h" -#include "qqmltypeloader_p.h" -#include "private/qv4identifier_p.h" -#include <private/qqmljsastfwd_p.h> -#include "qqmlcustomparser_p.h" - -#include <QtCore/qbytearray.h> -#include <QtCore/qset.h> -#include <QtCore/QCoreApplication> - -QT_BEGIN_NAMESPACE - -namespace QV4 { -namespace CompiledData { -struct CompilationUnit; -struct Unit; -} -} - -class QQmlEngine; -class QQmlComponent; -class QQmlContext; -class QQmlContextData; - -// ### Merge with QV4::CompiledData::CompilationUnit -class Q_AUTOTEST_EXPORT QQmlCompiledData : public QQmlRefCount, public QQmlCleanup -{ -public: - QQmlCompiledData(QQmlEngine *engine); - virtual ~QQmlCompiledData(); - - QQmlEngine *engine; - - QString fileName() const { return compilationUnit->fileName(); } - QUrl url() const { return compilationUnit->url(); } - QQmlTypeNameCache *importCache; - - int metaTypeId; - int listMetaTypeId; - bool isRegisteredWithEngine; - - struct TypeReference - { - TypeReference() - : type(0), typePropertyCache(0), component(0) - , majorVersion(0) - , minorVersion(0) - , isFullyDynamicType(false) - {} - - QQmlType *type; - QQmlPropertyCache *typePropertyCache; - QQmlCompiledData *component; - - int majorVersion; - int minorVersion; - // Types such as QQmlPropertyMap can add properties dynamically at run-time and - // therefore cannot have a property cache installed when instantiated. - bool isFullyDynamicType; - - QQmlPropertyCache *propertyCache() const; - QQmlPropertyCache *createPropertyCache(QQmlEngine *); - - void doDynamicTypeCheck(); - }; - // map from name index - QHash<int, TypeReference*> resolvedTypes; - - QQmlPropertyCache *rootPropertyCache; - QVector<QByteArray> metaObjects; - QVector<QQmlPropertyCache *> propertyCaches; - QList<QQmlScriptData *> scripts; - - QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit; - // index in first hash is component index, hash inside maps from object index in that scope to integer id - QHash<int, QHash<int, int> > objectIndexToIdPerComponent; - QHash<int, int> objectIndexToIdForRoot; - // hash key is object index, value is indicies of bindings covered by custom parser - QHash<int, QBitArray> customParserBindings; - QHash<int, QBitArray> deferredBindingsPerObject; // index is object index - int totalBindingsCount; // Number of bindings used in this type - int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses - int totalObjectCount; // Number of objects explicitly instantiated - - bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); } - bool isCompositeType() const { return !metaObjects.at(compilationUnit->data->indexOfRootObject).isEmpty(); } - - bool isInitialized() const { return hasEngine(); } - void initialize(QQmlEngine *); - -protected: - virtual void destroy(); // From QQmlRefCount - virtual void clear(); // From QQmlCleanup - -private: - QQmlCompiledData(const QQmlCompiledData &other); - QQmlCompiledData &operator=(const QQmlCompiledData &other); -}; - -QT_END_NAMESPACE - -#endif // QQMLCOMPILER_P_H diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 747be3cb7f..8be5172cd4 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -41,7 +41,6 @@ #include "qqmlcomponent_p.h" #include "qqmlcomponentattached_p.h" -#include "qqmlcompiler_p.h" #include "qqmlcontext_p.h" #include "qqmlengine_p.h" #include "qqmlvme_p.h" @@ -336,14 +335,11 @@ void QQmlComponentPrivate::typeDataProgress(QQmlTypeData *, qreal p) void QQmlComponentPrivate::fromTypeData(QQmlTypeData *data) { url = data->finalUrl(); - QQmlCompiledData *c = data->compiledData(); + compilationUnit = data->compilationUnit(); - if (!c) { + if (!compilationUnit) { Q_ASSERT(data->isError()); state.errors = data->errors(); - } else { - cc = c; - cc->addref(); } data->release(); @@ -357,10 +353,7 @@ void QQmlComponentPrivate::clear() typeData = 0; } - if (cc) { - cc->release(); - cc = 0; - } + compilationUnit = nullptr; } /*! @@ -394,8 +387,6 @@ QQmlComponent::~QQmlComponent() d->typeData->unregisterCallback(d); d->typeData->release(); } - if (d->cc) - d->cc->release(); } /*! @@ -423,7 +414,7 @@ QQmlComponent::Status QQmlComponent::status() const return Loading; else if (!d->state.errors.isEmpty()) return Error; - else if (d->engine && d->cc) + else if (d->engine && d->compilationUnit) return Ready; else return Null; @@ -513,11 +504,8 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QObject *parent) \sa loadUrl() */ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *parent) -: QObject(*(new QQmlComponentPrivate), parent) + : QQmlComponent(engine, url, QQmlComponent::PreferSynchronous, parent) { - Q_D(QQmlComponent); - d->engine = engine; - d->loadUrl(url); } /*! @@ -532,10 +520,9 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, QObject *paren */ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, CompilationMode mode, QObject *parent) -: QObject(*(new QQmlComponentPrivate), parent) + : QQmlComponent(engine, parent) { Q_D(QQmlComponent); - d->engine = engine; d->loadUrl(url, mode); } @@ -547,12 +534,8 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QUrl &url, CompilationMod */ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName, QObject *parent) -: QObject(*(new QQmlComponentPrivate), parent) + : QQmlComponent(engine, fileName, QQmlComponent::PreferSynchronous, parent) { - Q_D(QQmlComponent); - d->engine = engine; - const QUrl url = QDir::isAbsolutePath(fileName) ? QUrl::fromLocalFile(fileName) : d->engine->baseUrl().resolved(QUrl(fileName)); - d->loadUrl(url); } /*! @@ -564,10 +547,9 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName, */ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName, CompilationMode mode, QObject *parent) -: QObject(*(new QQmlComponentPrivate), parent) + : QQmlComponent(engine, parent) { Q_D(QQmlComponent); - d->engine = engine; const QUrl url = QDir::isAbsolutePath(fileName) ? QUrl::fromLocalFile(fileName) : d->engine->baseUrl().resolved(QUrl(fileName)); d->loadUrl(url, mode); } @@ -575,15 +557,13 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName, /*! \internal */ -QQmlComponent::QQmlComponent(QQmlEngine *engine, QQmlCompiledData *cc, int start, QObject *parent) - : QObject(*(new QQmlComponentPrivate), parent) +QQmlComponent::QQmlComponent(QQmlEngine *engine, QV4::CompiledData::CompilationUnit *compilationUnit, int start, QObject *parent) + : QQmlComponent(engine, parent) { Q_D(QQmlComponent); - d->engine = engine; - d->cc = cc; - cc->addref(); + d->compilationUnit = compilationUnit; d->start = start; - d->url = cc->url(); + d->url = compilationUnit->url(); d->progress = 1.0; } @@ -876,7 +856,7 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context) enginePriv->referenceScarceResources(); QObject *rv = 0; - state.creator.reset(new QQmlObjectCreator(context, cc, creationContext)); + state.creator.reset(new QQmlObjectCreator(context, compilationUnit, creationContext)); rv = state.creator->create(start); if (!rv) state.errors = state.creator->errors; @@ -896,11 +876,13 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context) depthIncreased = false; } - QQmlEngineDebugService *service = QQmlDebugConnector::service<QQmlEngineDebugService>(); - if (service && rv) { - if (!context->isInternal) - context->asQQmlContextPrivate()->instances.append(rv); - service->objectCreated(engine, rv); + if (rv) { + if (QQmlEngineDebugService *service = + QQmlDebugConnector::service<QQmlEngineDebugService>()) { + if (!context->isInternal) + context->asQQmlContextPrivate()->instances.append(rv); + service->objectCreated(engine, rv); + } } return rv; @@ -917,7 +899,7 @@ void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv, Q_ASSERT(ddata->deferredData); QQmlData::DeferredData *deferredData = ddata->deferredData; QQmlContextData *creationContext = 0; - state->creator.reset(new QQmlObjectCreator(deferredData->context->parent, deferredData->compiledData, creationContext)); + state->creator.reset(new QQmlObjectCreator(deferredData->context->parent, deferredData->compilationUnit, creationContext)); if (!state->creator->populateDeferredProperties(object)) state->errors << state->creator->errors; } @@ -1061,9 +1043,9 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context, QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(d->engine); - p->compiledData = d->cc; - p->compiledData->addref(); - p->creator.reset(new QQmlObjectCreator(contextData, d->cc, d->creationContext, p.data())); + p->compilationUnit = d->compilationUnit; + p->enginePriv = enginePriv; + p->creator.reset(new QQmlObjectCreator(contextData, d->compilationUnit, d->creationContext, p.data())); p->subComponentToCreate = d->start; enginePriv->incubate(incubator, forContextData); @@ -1076,9 +1058,10 @@ namespace QV4 { namespace Heap { struct QmlIncubatorObject : Object { - QmlIncubatorObject(QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous); - QScopedPointer<QQmlComponentIncubator> incubator; - QPointer<QObject> parent; + void init(QQmlIncubator::IncubationMode = QQmlIncubator::Asynchronous); + inline void destroy(); + QQmlComponentIncubator *incubator; + QQmlQPointer<QObject> parent; QV4::Value valuemap; QV4::Value statusChanged; Pointer<Heap::QmlContext> qmlContext; @@ -1196,7 +1179,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent) */ -static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v) +void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v) { QV4::Scope scope(engine); QV4::ScopedObject object(scope); @@ -1285,7 +1268,7 @@ void QQmlComponent::createObject(QQmlV4Function *args) if (!valuemap->isUndefined()) { QV4::Scoped<QV4::QmlContext> qmlContext(scope, v4->qmlContext()); - setInitialProperties(v4, qmlContext, object, valuemap); + QQmlComponentPrivate::setInitialProperties(v4, qmlContext, object, valuemap); } d->completeCreate(); @@ -1406,7 +1389,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) r->d()->qmlContext = v4->qmlContext(); r->d()->parent = parent; - QQmlIncubator *incubator = r->d()->incubator.data(); + QQmlIncubator *incubator = r->d()->incubator; create(*incubator, creationContext()); if (incubator->status() == QQmlIncubator::Null) { @@ -1501,12 +1484,20 @@ QQmlComponentExtension::~QQmlComponentExtension() { } -QV4::Heap::QmlIncubatorObject::QmlIncubatorObject(QQmlIncubator::IncubationMode m) - : valuemap(QV4::Primitive::undefinedValue()) - , statusChanged(QV4::Primitive::undefinedValue()) - , qmlContext(0) +void QV4::Heap::QmlIncubatorObject::init(QQmlIncubator::IncubationMode m) { - incubator.reset(new QQmlComponentIncubator(this, m)); + Object::init(); + valuemap = QV4::Primitive::undefinedValue(); + statusChanged = QV4::Primitive::undefinedValue(); + parent.init(); + qmlContext = nullptr; + incubator = new QQmlComponentIncubator(this, m); +} + +void QV4::Heap::QmlIncubatorObject::destroy() { + delete incubator; + parent.destroy(); + Object::destroy(); } void QV4::QmlIncubatorObject::setInitialState(QObject *o) @@ -1518,7 +1509,7 @@ void QV4::QmlIncubatorObject::setInitialState(QObject *o) QV4::Scope scope(v4); QV4::ScopedObject obj(scope, QV4::QObjectWrapper::wrap(v4, o)); QV4::Scoped<QV4::QmlContext> qmlCtxt(scope, d()->qmlContext); - setInitialProperties(v4, qmlCtxt, obj, d()->valuemap); + QQmlComponentPrivate::setInitialProperties(v4, qmlCtxt, obj, d()->valuemap); } } @@ -1549,7 +1540,7 @@ void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s) QV4::ScopedCallData callData(scope, 1); callData->thisObject = this; callData->args[0] = QV4::Primitive::fromUInt32(s); - f->call(callData); + f->call(scope, callData); if (scope.hasException()) { QQmlError error = scope.engine->catchExceptionAsQmlError(); QQmlEnginePrivate::warning(QQmlEnginePrivate::get(scope.engine->qmlEngine()), error); diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h index aefbf20aff..ca60f01eb5 100644 --- a/src/qml/qml/qqmlcomponent.h +++ b/src/qml/qml/qqmlcomponent.h @@ -55,10 +55,15 @@ class QQmlEngine; class QQmlComponent; class QQmlIncubator; class QQmlV4Function; -class QQmlCompiledData; class QQmlComponentPrivate; class QQmlComponentAttached; +namespace QV4 { +namespace CompiledData { +struct CompilationUnit; +} +} + class Q_QML_EXPORT QQmlComponent : public QObject { Q_OBJECT @@ -122,7 +127,7 @@ protected: Q_INVOKABLE void incubateObject(QQmlV4Function *); private: - QQmlComponent(QQmlEngine *, QQmlCompiledData *, int, QObject *parent); + QQmlComponent(QQmlEngine *, QV4::CompiledData::CompilationUnit *compilationUnit, int, QObject *parent); Q_DISABLE_COPY(QQmlComponent) friend class QQmlTypeData; diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h index 039b267433..3a84e724da 100644 --- a/src/qml/qml/qqmlcomponent_p.h +++ b/src/qml/qml/qqmlcomponent_p.h @@ -71,7 +71,6 @@ QT_BEGIN_NAMESPACE class QQmlComponent; class QQmlEngine; -class QQmlCompiledData; class QQmlComponentAttached; class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public QQmlTypeData::TypeDataCallback @@ -80,13 +79,14 @@ class Q_QML_PRIVATE_EXPORT QQmlComponentPrivate : public QObjectPrivate, public public: QQmlComponentPrivate() - : typeData(0), progress(0.), start(-1), cc(0), engine(0), creationContext(0), depthIncreased(false) {} + : typeData(0), progress(0.), start(-1), engine(0), creationContext(0), depthIncreased(false) {} void loadUrl(const QUrl &newUrl, QQmlComponent::CompilationMode mode = QQmlComponent::PreferSynchronous); QObject *beginCreate(QQmlContextData *); void completeCreate(); void initializeObjectWithInitialProperties(QV4::QmlContext *qmlContext, const QV4::Value &valuemap, QObject *toCreate); + static void setInitialProperties(QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &o, const QV4::Value &v); QQmlTypeData *typeData; virtual void typeDataReady(QQmlTypeData *); @@ -98,7 +98,7 @@ public: qreal progress; int start; - QQmlCompiledData *cc; + QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit; struct ConstructionState { ConstructionState() diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index 65a337f4e5..018841b9b1 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -310,7 +310,7 @@ void QQmlContext::setContextProperty(const QString &name, const QVariant &value) } } - QV4::IdentifierHash<int> &properties = data->propertyNames(); + QV4::IdentifierHash<int> &properties = data->detachedPropertyNames(); int idx = properties.value(name); if (idx == -1) { properties.add(name, data->idValueCount + d->propertyValues.count()); @@ -346,7 +346,7 @@ void QQmlContext::setContextProperty(const QString &name, QObject *value) return; } - QV4::IdentifierHash<int> &properties = data->propertyNames(); + QV4::IdentifierHash<int> &properties = data->detachedPropertyNames(); int idx = properties.value(name); if (idx == -1) { @@ -383,7 +383,7 @@ QVariant QQmlContext::contextProperty(const QString &name) const QQmlPropertyData *property = QQmlPropertyCache::property(data->engine, obj, name, data, local); - if (property) value = obj->metaObject()->property(property->coreIndex).read(obj); + if (property) value = obj->metaObject()->property(property->coreIndex()).read(obj); } if (!value.isValid() && parentContext()) value = parentContext()->contextProperty(name); @@ -516,20 +516,15 @@ QObject *QQmlContextPrivate::context_at(QQmlListProperty<QObject> *prop, int ind QQmlContextData::QQmlContextData() -: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), - isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false), - publicContext(0), activeVMEData(0), - contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0), - expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), - componentAttached(0) + : QQmlContextData(nullptr) { } QQmlContextData::QQmlContextData(QQmlContext *ctxt) : parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false), isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false), - publicContext(ctxt), activeVMEData(0), - contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0), + publicContext(ctxt), activeVMEData(0), componentObjectIndex(-1), + contextObject(0), childContexts(0), nextChild(0), prevChild(0), expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0), componentAttached(0) { @@ -633,9 +628,6 @@ void QQmlContextData::destroy() } contextGuards = 0; - if (imports) - imports->release(); - delete [] idValues; if (isInternal) @@ -765,15 +757,6 @@ void QQmlContextData::setIdProperty(int idx, QObject *obj) idValues[idx].context = this; } -void QQmlContextData::setIdPropertyData(const QHash<int, int> &data) -{ - Q_ASSERT(objectIndexToId.isEmpty()); - objectIndexToId = data; - Q_ASSERT(propertyNameCache.isEmpty()); - idValueCount = data.count(); - idValues = new ContextGuard[idValueCount]; -} - QString QQmlContextData::findObjectId(const QObject *obj) const { const QV4::IdentifierHash<int> &properties = propertyNames(); @@ -809,21 +792,33 @@ QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate() return QQmlContextPrivate::get(asQQmlContext()); } -QV4::IdentifierHash<int> &QQmlContextData::propertyNames() const +void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, int subComponentIndex) +{ + typeCompilationUnit = unit; + componentObjectIndex = subComponentIndex == -1 ? typeCompilationUnit->data->indexOfRootObject : subComponentIndex; + Q_ASSERT(!idValues); + idValueCount = typeCompilationUnit->data->objectAt(componentObjectIndex)->nNamedObjectsInComponent; + idValues = new ContextGuard[idValueCount]; +} + +const QV4::IdentifierHash<int> &QQmlContextData::propertyNames() const { if (propertyNameCache.isEmpty()) { - propertyNameCache = QV4::IdentifierHash<int>(QV8Engine::getV4(engine->handle())); - for (QHash<int, int>::ConstIterator it = objectIndexToId.cbegin(), end = objectIndexToId.cend(); - it != end; ++it) { - const QV4::CompiledData::Object *obj = typeCompilationUnit->data->objectAt(it.key()); - const QString name = typeCompilationUnit->data->stringAt(obj->idIndex); - propertyNameCache.add(name, it.value()); - } - objectIndexToId.clear(); + if (typeCompilationUnit) + propertyNameCache = typeCompilationUnit->namedObjectsPerComponent(componentObjectIndex); + else + propertyNameCache = QV4::IdentifierHash<int>(QV8Engine::getV4(engine)); } return propertyNameCache; } +QV4::IdentifierHash<int> &QQmlContextData::detachedPropertyNames() +{ + propertyNames(); + propertyNameCache.detach(); + return propertyNameCache; +} + QUrl QQmlContextData::url() const { if (typeCompilationUnit) diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h index 48d596418d..62cd3d4877 100644 --- a/src/qml/qml/qqmlcontext_p.h +++ b/src/qml/qml/qqmlcontext_p.h @@ -151,9 +151,15 @@ public: // Compilation unit for contexts that belong to a compiled type. QQmlRefPointer<QV4::CompiledData::CompilationUnit> typeCompilationUnit; - mutable QHash<int, int> objectIndexToId; + // object index in CompiledData::Unit to component that created this context + int componentObjectIndex; + + void initFromTypeCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, int subComponentIndex); + + // flag indicates whether the context owns the cache (after mutation) or not. mutable QV4::IdentifierHash<int> propertyNameCache; - QV4::IdentifierHash<int> &propertyNames() const; + const QV4::IdentifierHash<int> &propertyNames() const; + QV4::IdentifierHash<int> &detachedPropertyNames(); // Context object QObject *contextObject; @@ -168,7 +174,7 @@ public: QString urlString() const; // List of imports that apply to this context - QQmlTypeNameCache *imports; + QQmlRefPointer<QQmlTypeNameCache> imports; // My children QQmlContextData *childContexts; @@ -201,7 +207,6 @@ public: ContextGuard *idValues; int idValueCount; void setIdProperty(int, QObject *); - void setIdPropertyData(const QHash<int, int> &); // Linked contexts. this owns linkedContext. QQmlContextData *linkedContext; diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp index 2d0ebad764..2418003519 100644 --- a/src/qml/qml/qqmlcontextwrapper.cpp +++ b/src/qml/qml/qqmlcontextwrapper.cpp @@ -61,19 +61,23 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlContextWrapper); -Heap::QmlContextWrapper::QmlContextWrapper(QQmlContextData *context, QObject *scopeObject, bool ownsContext) - : readOnly(true) - , ownsContext(ownsContext) - , isNullWrapper(false) - , context(context) - , scopeObject(scopeObject) +void Heap::QmlContextWrapper::init(QQmlContextData *context, QObject *scopeObject, bool ownsContext) { + Object::init(); + readOnly = true; + this->ownsContext = ownsContext; + isNullWrapper = false; + this->context = new QQmlGuardedContextData(context); + this->scopeObject.init(scopeObject); } -Heap::QmlContextWrapper::~QmlContextWrapper() +void Heap::QmlContextWrapper::destroy() { - if (context && ownsContext) - context->destroy(); + if (*context && ownsContext) + (*context)->destroy(); + delete context; + scopeObject.destroy(); + Object::destroy(); } ReturnedValue QmlContextWrapper::qmlScope(ExecutionEngine *v4, QQmlContextData *ctxt, QObject *scope) @@ -119,7 +123,7 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr if (resource->d()->isNullWrapper) return Object::get(m, name, hasProperty); - if (v4->callingQmlContext() != resource->d()->context) + if (v4->callingQmlContext() != *resource->d()->context) return Object::get(m, name, hasProperty); result = Object::get(m, name, &hasProp); diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h index ca7fcf1d75..126ffecf0d 100644 --- a/src/qml/qml/qqmlcontextwrapper_p.h +++ b/src/qml/qml/qqmlcontextwrapper_p.h @@ -64,14 +64,14 @@ namespace QV4 { namespace Heap { struct QmlContextWrapper : Object { - QmlContextWrapper(QQmlContextData *context, QObject *scopeObject, bool ownsContext = false); - ~QmlContextWrapper(); + void init(QQmlContextData *context, QObject *scopeObject, bool ownsContext = false); + void destroy(); bool readOnly; bool ownsContext; bool isNullWrapper; - QQmlGuardedContextData context; - QPointer<QObject> scopeObject; + QQmlGuardedContextData *context; + QQmlQPointer<QObject> scopeObject; }; } @@ -89,7 +89,7 @@ struct Q_QML_EXPORT QmlContextWrapper : Object } inline QObject *getScopeObject() const { return d()->scopeObject; } - inline QQmlContextData *getContext() const { return d()->context; } + inline QQmlContextData *getContext() const { return *d()->context; } void setReadOnly(bool b) { d()->readOnly = b; } diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp index 134002cf33..85c91a592a 100644 --- a/src/qml/qml/qqmlcustomparser.cpp +++ b/src/qml/qml/qqmlcustomparser.cpp @@ -39,7 +39,6 @@ #include "qqmlcustomparser_p.h" -#include "qqmlcompiler_p.h" #include <private/qqmltypecompiler_p.h> #include <QtCore/qdebug.h> @@ -101,11 +100,7 @@ void QQmlCustomParser::clearErrors() */ void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description) { - QQmlError error; - error.setLine(location.line); - error.setColumn(location.column); - error.setDescription(description); - exceptions << error; + exceptions << QQmlCompileError(location, description); } struct StaticQtMetaObject : public QObject @@ -166,11 +161,13 @@ int QQmlCustomParser::evaluateEnum(const QByteArray& script, bool *ok) const */ const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const { + if (!imports.isT1()) + return nullptr; QQmlType *qmltype = 0; - if (!validator->imports().resolveType(name, &qmltype, 0, 0, 0)) - return 0; + if (!imports.asT1()->resolveType(name, &qmltype, 0, 0, 0)) + return nullptr; if (!qmltype) - return 0; + return nullptr; return qmltype->metaObject(); } diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h index d8e25c55fd..5eb409990d 100644 --- a/src/qml/qml/qqmlcustomparser_p.h +++ b/src/qml/qml/qqmlcustomparser_p.h @@ -54,13 +54,13 @@ #include "qqmlmetatype_p.h" #include "qqmlerror.h" #include "qqmlbinding_p.h" +#include <private/qqmltypecompiler_p.h> #include <QtCore/qbytearray.h> #include <QtCore/qxmlstream.h> QT_BEGIN_NAMESPACE -class QQmlCompiledData; class QQmlPropertyValidator; class QQmlEnginePrivate; @@ -82,9 +82,9 @@ public: Flags flags() const { return m_flags; } virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) = 0; - virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) = 0; + virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &) = 0; - QList<QQmlError> errors() const { return exceptions; } + QVector<QQmlCompileError> errors() const { return exceptions; } protected: void error(const QV4::CompiledData::Binding *binding, const QString& description) @@ -98,7 +98,7 @@ protected: const QMetaObject *resolveType(const QString&) const; private: - QList<QQmlError> exceptions; + QVector<QQmlCompileError> exceptions; QQmlEnginePrivate *engine; const QQmlPropertyValidator *validator; Flags m_flags; diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index 7ccab5746d..e271598c2d 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -53,7 +53,7 @@ #include <private/qtqmlglobal_p.h> #include <private/qobject_p.h> - +#include <private/qqmlpropertyindex_p.h> #include <private/qv4value_p.h> #include <private/qv4persistent_p.h> #include <qjsengine.h> @@ -63,7 +63,6 @@ QT_BEGIN_NAMESPACE template <class Key, class T> class QHash; class QQmlEngine; class QQmlGuardImpl; -class QQmlCompiledData; class QQmlAbstractBinding; class QQmlBoundSignal; class QQmlContext; @@ -72,6 +71,13 @@ class QQmlContextData; class QQmlNotifier; class QQmlDataExtended; class QQmlNotifierEndpoint; + +namespace QV4 { +namespace CompiledData { +struct CompilationUnit; +} +} + // This class is structured in such a way, that simply zero'ing it is the // default state for elemental object allocations. This is crucial in the // workings of the QQmlInstruction::CreateSimpleObject instruction. @@ -123,14 +129,16 @@ public: quint32 parentFrozen:1; quint32 dummy:21; - // When bindingBitsSize < 32, we store the binding bit flags inside - // bindingBitsValue. When we need more than 32 bits, we allocated + // When bindingBitsSize < sizeof(ptr), we store the binding bit flags inside + // bindingBitsValue. When we need more than sizeof(ptr) bits, we allocated // sufficient space and use bindingBits to point to it. int bindingBitsSize; + typedef quintptr BindingBitsType; union { - quint32 *bindingBits; - quint32 bindingBitsValue; + BindingBitsType *bindingBits; + BindingBitsType bindingBitsValue; }; + enum { MaxInlineBits = sizeof(BindingBitsType) * 8 }; struct NotifyList { quint64 connectionMask; @@ -168,7 +176,7 @@ public: void clearBindingBit(int); void setBindingBit(QObject *obj, int); - inline bool hasPendingBindingBit(int) const; + inline bool hasPendingBindingBit(int index) const; void setPendingBindingBit(QObject *obj, int); void clearPendingBindingBit(int); @@ -179,10 +187,10 @@ public: struct DeferredData { unsigned int deferredIdx; - QQmlCompiledData *compiledData;//Not always the same as the other compiledData + QV4::CompiledData::CompilationUnit *compilationUnit;//Not always the same as the other compilation unit QQmlContextData *context;//Could be either context or outerContext }; - QQmlCompiledData *compiledData; + QV4::CompiledData::CompilationUnit *compilationUnit; DeferredData *deferredData; QV4::WeakValue jsWrapper; @@ -199,8 +207,7 @@ public: } else if (priv->declarativeData) { return static_cast<QQmlData *>(priv->declarativeData); } else if (create) { - priv->declarativeData = new QQmlData; - return static_cast<QQmlData *>(priv->declarativeData); + return createQQmlData(priv); } else { return 0; } @@ -221,15 +228,36 @@ public: static void markAsDeleted(QObject *); static void setQueuedForDeletion(QObject *); - static inline void flushPendingBinding(QObject *, int coreIndex); + static inline void flushPendingBinding(QObject *, QQmlPropertyIndex propertyIndex); - static QQmlPropertyCache *ensurePropertyCache(QJSEngine *engine, QObject *object); + static QQmlPropertyCache *ensurePropertyCache(QJSEngine *engine, QObject *object) + { + Q_ASSERT(engine); + QQmlData *ddata = QQmlData::get(object, /*create*/true); + if (Q_LIKELY(ddata->propertyCache)) + return ddata->propertyCache; + return createPropertyCache(engine, object); + } private: // For attachedProperties mutable QQmlDataExtended *extendedData; - void flushPendingBindingImpl(int coreIndex); + Q_NEVER_INLINE static QQmlData *createQQmlData(QObjectPrivate *priv); + Q_NEVER_INLINE static QQmlPropertyCache *createPropertyCache(QJSEngine *engine, QObject *object); + + void flushPendingBindingImpl(QQmlPropertyIndex index); + + Q_ALWAYS_INLINE bool hasBitSet(int bit) const + { + if (bindingBitsSize <= bit) + return false; + + if (bindingBitsSize == MaxInlineBits) + return bindingBitsValue & (BindingBitsType(1) << bit); + else + return bindingBits[bit / MaxInlineBits] & (BindingBitsType(1) << (bit % MaxInlineBits)); + } }; bool QQmlData::wasDeleted(QObject *object) @@ -275,27 +303,25 @@ inline bool QQmlData::signalHasEndpoint(int index) const bool QQmlData::hasBindingBit(int coreIndex) const { - int bit = coreIndex * 2; + Q_ASSERT(coreIndex >= 0); + Q_ASSERT(coreIndex <= 0xffff); - return bindingBitsSize > bit && - ((bindingBitsSize == 32) ? (bindingBitsValue & (1 << bit)) : - (bindingBits[bit / 32] & (1 << (bit % 32)))); + return hasBitSet(coreIndex * 2); } bool QQmlData::hasPendingBindingBit(int coreIndex) const { - int bit = coreIndex * 2 + 1; + Q_ASSERT(coreIndex >= 0); + Q_ASSERT(coreIndex <= 0xffff); - return bindingBitsSize > bit && - ((bindingBitsSize == 32) ? (bindingBitsValue & (1 << bit)) : - (bindingBits[bit / 32] & (1 << (bit % 32)))); + return hasBitSet(coreIndex * 2 + 1); } -void QQmlData::flushPendingBinding(QObject *o, int coreIndex) +void QQmlData::flushPendingBinding(QObject *o, QQmlPropertyIndex propertyIndex) { QQmlData *data = QQmlData::get(o, false); - if (data && data->hasPendingBindingBit(coreIndex)) - data->flushPendingBindingImpl(coreIndex); + if (data && data->hasPendingBindingBit(propertyIndex.coreIndex())) + data->flushPendingBindingImpl(propertyIndex); } QT_END_NAMESPACE diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp new file mode 100644 index 0000000000..d10a8c7718 --- /dev/null +++ b/src/qml/qml/qqmldelayedcallqueue.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmldelayedcallqueue_p.h" +#include <private/qv8engine_p.h> +#include <private/qqmlengine_p.h> +#include <private/qqmljavascriptexpression_p.h> +#include <private/qv4value_p.h> +#include <private/qv4qobjectwrapper_p.h> +#include <private/qqmlcontextwrapper_p.h> + +#include <QQmlError> + +QT_BEGIN_NAMESPACE + +// +// struct QQmlDelayedCallQueue::DelayedFunctionCall +// + +void QQmlDelayedCallQueue::DelayedFunctionCall::execute(QV4::ExecutionEngine *engine) const +{ + if (!m_guarded || + (!m_objectGuard.isNull() && + !QQmlData::wasDeleted(m_objectGuard) && + QQmlData::get(m_objectGuard) && + !QQmlData::get(m_objectGuard)->isQueuedForDeletion)) { + + QV4::Scope scope(engine); + + QV4::ArrayObject *array = m_args.as<QV4::ArrayObject>(); + const int argCount = array ? array->getLength() : 0; + QV4::ScopedCallData callData(scope, argCount); + callData->thisObject = QV4::Encode::undefined(); + + for (int i = 0; i < argCount; i++) { + callData->args[i] = array->getIndexed(i); + } + + const QV4::FunctionObject *callback = m_function.as<QV4::FunctionObject>(); + Q_ASSERT(callback); + callback->call(scope, callData); + + if (scope.engine->hasException) { + QQmlError error = scope.engine->catchExceptionAsQmlError(); + error.setDescription(error.description() + QLatin1String(" (exception occurred during delayed function evaluation)")); + QQmlEnginePrivate::warning(QQmlEnginePrivate::get(scope.engine->qmlEngine()), error); + } + } +} + +// +// class QQmlDelayedCallQueue +// + +QQmlDelayedCallQueue::QQmlDelayedCallQueue() + : QObject(0), m_engine(0), m_callbackOutstanding(false) +{ +} + +QQmlDelayedCallQueue::~QQmlDelayedCallQueue() +{ +} + +void QQmlDelayedCallQueue::init(QV4::ExecutionEngine* engine) +{ + m_engine = engine; + + const QMetaObject &metaObject = QQmlDelayedCallQueue::staticMetaObject; + int methodIndex = metaObject.indexOfSlot("ticked()"); + m_tickedMethod = metaObject.method(methodIndex); +} + +QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(QV4::CallContext *ctx) +{ + const QV4::CallData *callData = ctx->d()->callData; + + if (callData->argc == 0) + V4THROW_ERROR("Qt.callLater: no arguments given"); + + const QV4::FunctionObject *func = callData->args[0].as<QV4::FunctionObject>(); + + if (!func) + V4THROW_ERROR("Qt.callLater: first argument not a function or signal"); + + QPair<QObject *, int> functionData = QV4::QObjectMethod::extractQtMethod(func); + + QVector<DelayedFunctionCall>::Iterator iter; + if (functionData.second != -1) { + // This is a QObject function wrapper + iter = m_delayedFunctionCalls.begin(); + while (iter != m_delayedFunctionCalls.end()) { + DelayedFunctionCall& dfc = *iter; + QPair<QObject *, int> storedFunctionData = QV4::QObjectMethod::extractQtMethod(dfc.m_function.as<QV4::FunctionObject>()); + if (storedFunctionData == functionData) { + break; // Already stored! + } + ++iter; + } + } else { + // This is a JavaScript function (dynamic slot on VMEMO) + iter = m_delayedFunctionCalls.begin(); + while (iter != m_delayedFunctionCalls.end()) { + DelayedFunctionCall& dfc = *iter; + if (callData->argument(0) == dfc.m_function.value()) { + break; // Already stored! + } + ++iter; + } + } + + const bool functionAlreadyStored = (iter != m_delayedFunctionCalls.end()); + if (functionAlreadyStored) { + DelayedFunctionCall dfc = *iter; + m_delayedFunctionCalls.erase(iter); + m_delayedFunctionCalls.append(dfc); + } else { + m_delayedFunctionCalls.append(QV4::PersistentValue(m_engine, callData->argument(0))); + } + + DelayedFunctionCall& dfc = m_delayedFunctionCalls.last(); + if (dfc.m_objectGuard.isNull()) { + if (functionData.second != -1) { + // if it's a qobject function wrapper, guard against qobject deletion + dfc.m_objectGuard = QQmlGuard<QObject>(functionData.first); + dfc.m_guarded = true; + } else if (func->scope()->type == QV4::Heap::ExecutionContext::Type_QmlContext) { + QV4::QmlContext::Data *g = static_cast<QV4::QmlContext::Data *>(func->scope()); + Q_ASSERT(g->qml->scopeObject); + dfc.m_objectGuard = QQmlGuard<QObject>(g->qml->scopeObject); + dfc.m_guarded = true; + } + } + storeAnyArguments(dfc, callData, 1, m_engine); + + if (!m_callbackOutstanding) { + m_tickedMethod.invoke(this, Qt::QueuedConnection); + m_callbackOutstanding = true; + } + return QV4::Encode::undefined(); +} + +void QQmlDelayedCallQueue::storeAnyArguments(DelayedFunctionCall &dfc, const QV4::CallData *callData, int offset, QV4::ExecutionEngine *engine) +{ + const int length = callData->argc - offset; + if (length == 0) { + dfc.m_args.clear(); + return; + } + QV4::Scope scope(engine); + QV4::ScopedArrayObject array(scope, engine->newArrayObject(length)); + int i = 0; + for (int j = offset; j < callData->argc; ++i, ++j) { + array->putIndexed(i, callData->args[j]); + } + dfc.m_args.set(engine, array); +} + +void QQmlDelayedCallQueue::executeAllExpired_Later() +{ + // Make a local copy of the list and clear m_delayedFunctionCalls + // This ensures correct behavior in the case of recursive calls to Qt.callLater() + QVector<DelayedFunctionCall> delayedCalls = m_delayedFunctionCalls; + m_delayedFunctionCalls.clear(); + + QVector<DelayedFunctionCall>::Iterator iter = delayedCalls.begin(); + while (iter != delayedCalls.end()) { + DelayedFunctionCall& dfc = *iter; + dfc.execute(m_engine); + ++iter; + } +} + +void QQmlDelayedCallQueue::ticked() +{ + m_callbackOutstanding = false; + executeAllExpired_Later(); +} + +QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlaccessors.cpp b/src/qml/qml/qqmldelayedcallqueue_p.h index 7b0fafdc90..ef899170a2 100644 --- a/src/qml/qml/qqmlaccessors.cpp +++ b/src/qml/qml/qqmldelayedcallqueue_p.h @@ -37,69 +37,68 @@ ** ****************************************************************************/ -#include "qqmlaccessors_p.h" - -#include "qqmldata_p.h" -#include "qqmlnotifier_p.h" +#ifndef QQMLDELAYEDCALLQUEUE_P_H +#define QQMLDELAYEDCALLQUEUE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> +#include <QtCore/qobject.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qmetatype.h> +#include <private/qqmlguard_p.h> +#include <private/qv4context_p.h> QT_BEGIN_NAMESPACE -struct AccessorProperties { - AccessorProperties(); - - QReadWriteLock lock; - QHash<const QMetaObject *, QQmlAccessorProperties::Properties> properties; -}; - -Q_GLOBAL_STATIC(AccessorProperties, accessorProperties) - -static void buildNameMask(QQmlAccessorProperties::Properties &properties) -{ - quint32 mask = 0; - - for (int ii = 0; ii < properties.count; ++ii) { - Q_ASSERT(strlen(properties.properties[ii].name) == properties.properties[ii].nameLength); - Q_ASSERT(properties.properties[ii].nameLength > 0); - - mask |= (1 << qMin(31U, properties.properties[ii].nameLength - 1)); - } - - properties.nameMask = mask; -} - -AccessorProperties::AccessorProperties() -{ -} - -QQmlAccessorProperties::Properties::Properties(Property *properties, int count) -: count(count), properties(properties) +class QV8Engine; +class QQmlDelayedCallQueue : public QObject { - buildNameMask(*this); -} + Q_OBJECT +public: + QQmlDelayedCallQueue(); + ~QQmlDelayedCallQueue(); -QQmlAccessorProperties::Properties -QQmlAccessorProperties::properties(const QMetaObject *mo) -{ - AccessorProperties *This = accessorProperties(); + void init(QV4::ExecutionEngine *); - QReadLocker lock(&This->lock); - return This->properties.value(mo); -} + QV4::ReturnedValue addUniquelyAndExecuteLater(QV4::CallContext *ctx); -void QQmlAccessorProperties::registerProperties(const QMetaObject *mo, int count, - Property *props) -{ - Q_ASSERT(count > 0); +public Q_SLOTS: + void ticked(); - Properties properties(props, count); +private: + struct DelayedFunctionCall + { + DelayedFunctionCall() {} + DelayedFunctionCall(QV4::PersistentValue function) + : m_function(function), m_guarded(false) { } - AccessorProperties *This = accessorProperties(); + void execute(QV4::ExecutionEngine *engine) const; - QWriteLocker lock(&This->lock); + QV4::PersistentValue m_function; + QV4::PersistentValue m_args; + QQmlGuard<QObject> m_objectGuard; + bool m_guarded; + }; - Q_ASSERT(!This->properties.contains(mo) || This->properties.value(mo) == properties); + void storeAnyArguments(DelayedFunctionCall& dfc, const QV4::CallData *callData, int offset, QV4::ExecutionEngine *engine); + void executeAllExpired_Later(); - This->properties.insert(mo, properties); -} + QV4::ExecutionEngine *m_engine; + QVector<DelayedFunctionCall> m_delayedFunctionCalls; + QMetaMethod m_tickedMethod; + bool m_callbackOutstanding; +}; QT_END_NAMESPACE + +#endif // QQMLDELAYEDCALLQUEUE_P_H diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 71795a2539..7877ee7e21 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -42,7 +42,6 @@ #include "qqmlcomponentattached_p.h" #include "qqmlcontext_p.h" -#include "qqmlcompiler_p.h" #include "qqml.h" #include "qqmlcontext.h" #include "qqmlexpression.h" @@ -53,35 +52,33 @@ #include "qqmlscriptstring.h" #include "qqmlglobal_p.h" #include "qqmlcomponent_p.h" -#include "qqmlnetworkaccessmanagerfactory.h" #include "qqmldirparser_p.h" #include "qqmlextensioninterface.h" #include "qqmllist_p.h" #include "qqmltypenamecache_p.h" #include "qqmlnotifier_p.h" -#include <private/qqmldebugconnector_p.h> #include "qqmlincubator.h" #include "qqmlabstracturlinterceptor.h" #include <private/qqmlboundsignal_p.h> - #include <QtCore/qstandardpaths.h> #include <QtCore/qsettings.h> - #include <QtCore/qmetaobject.h> -#include <QNetworkAccessManager> #include <QDebug> #include <QtCore/qcoreapplication.h> #include <QtCore/qdir.h> #include <QtCore/qmutex.h> #include <QtCore/qthread.h> #include <private/qthread_p.h> + +#if QT_CONFIG(qml_network) +#include "qqmlnetworkaccessmanagerfactory.h" +#include <QNetworkAccessManager> #include <QtNetwork/qnetworkconfigmanager.h> +#endif #include <private/qobject_p.h> #include <private/qmetaobject_p.h> - #include <private/qqmllocale_p.h> - #include <private/qqmlbind_p.h> #include <private/qqmlconnections_p.h> #include <private/qqmltimer_p.h> @@ -92,24 +89,26 @@ #include <private/qqmlobjectmodel_p.h> #include <private/qquickworkerscript_p.h> #include <private/qqmlinstantiator_p.h> +#include <private/qqmlloggingcategory_p.h> #ifdef Q_OS_WIN // for %APPDATA% -#include <qt_windows.h> -# if !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) +# include <qt_windows.h> +# ifndef Q_OS_WINRT # include <shlobj.h> # endif -#include <qlibrary.h> -#include <windows.h> - -#ifndef CSIDL_APPDATA -# define CSIDL_APPDATA 0x001a // <username>\Application Data -#endif -#endif +# include <qlibrary.h> +# ifndef CSIDL_APPDATA +# define CSIDL_APPDATA 0x001a // <username>\Application Data +# endif +#endif // Q_OS_WIN Q_DECLARE_METATYPE(QQmlProperty) QT_BEGIN_NAMESPACE +typedef QQmlData::BindingBitsType BindingBitsType; +enum { MaxInlineBits = QQmlData::MaxInlineBits }; + void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor) { QQmlEnginePrivate::registerBaseTypes(uri, versionMajor, versionMinor); @@ -117,6 +116,39 @@ void qmlRegisterBaseTypes(const char *uri, int versionMajor, int versionMinor) QQmlValueTypeFactory::registerValueTypes(uri, versionMajor, versionMinor); } +// Declared in qqml.h +int qmlRegisterUncreatableMetaObject(const QMetaObject &staticMetaObject, + const char *uri, int versionMajor, + int versionMinor, const char *qmlName, + const QString& reason) +{ + QQmlPrivate::RegisterType type = { + 0, + + 0, + 0, + 0, + Q_NULLPTR, + reason, + + uri, versionMajor, versionMinor, qmlName, &staticMetaObject, + + QQmlAttachedPropertiesFunc(), + Q_NULLPTR, + + 0, + 0, + 0, + + Q_NULLPTR, Q_NULLPTR, + + Q_NULLPTR, + 0 + }; + + return QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type); +} + /*! \qmltype QtObject \instantiates QObject @@ -182,12 +214,14 @@ void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int qmlRegisterType<QQmlComponent>(uri,versionMajor,versionMinor,"Component"); qmlRegisterType<QObject>(uri,versionMajor,versionMinor,"QtObject"); qmlRegisterType<QQmlBind>(uri, versionMajor, versionMinor,"Binding"); + qmlRegisterType<QQmlBind,8>(uri, versionMajor, (versionMinor < 8 ? 8 : versionMinor), "Binding"); //Only available in >=2.8 qmlRegisterType<QQmlConnections,1>(uri, versionMajor, (versionMinor < 3 ? 3 : versionMinor), "Connections"); //Only available in >=2.3 qmlRegisterType<QQmlConnections>(uri, versionMajor, versionMinor,"Connections"); qmlRegisterType<QQmlTimer>(uri, versionMajor, versionMinor,"Timer"); qmlRegisterType<QQmlInstantiator>(uri, versionMajor, (versionMinor < 1 ? 1 : versionMinor), "Instantiator"); //Only available in >=2.1 qmlRegisterCustomType<QQmlConnections>(uri, versionMajor, versionMinor,"Connections", new QQmlConnectionsParser); qmlRegisterType<QQmlInstanceModel>(); + qmlRegisterType<QQmlLoggingCategory>(uri, versionMajor, (versionMinor < 8 ? 8 : versionMinor), "LoggingCategory"); //Only available in >=2.8 } @@ -492,6 +526,10 @@ The following functions are also on the Qt object. from right to left. \endlist \row + \li \c application.font + \li This read-only property holds the default application font as + returned by \l QGuiApplication::font(). + \row \li \c application.arguments \li This is a string list of the arguments the executable was invoked with. \row @@ -530,6 +568,7 @@ The following functions are also on the Qt object. \li application.active \li application.state \li application.layoutDirection + \li application.font \endlist */ @@ -600,12 +639,17 @@ the same object as is returned from the Qt.include() call. QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e) : propertyCapture(0), rootContext(0), - profiler(0), outputWarningsToMsgLog(true), +#ifndef QT_NO_QML_DEBUGGER + profiler(0), +#endif + outputWarningsToMsgLog(true), cleanup(0), erroredBindings(0), inProgressCreations(0), workerScriptEngine(0), activeObjectCreator(0), - networkAccessManager(0), networkAccessManagerFactory(0), urlInterceptor(0), - scarceResourcesRefCount(0), importDatabase(e), typeLoader(e), +#if QT_CONFIG(qml_network) + networkAccessManager(0), networkAccessManagerFactory(0), +#endif + urlInterceptor(0), scarceResourcesRefCount(0), importDatabase(e), typeLoader(e), uniqueId(1), incubatorCount(0), incubationController(0) { } @@ -613,7 +657,6 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e) QQmlEnginePrivate::~QQmlEnginePrivate() { typedef QHash<QPair<QQmlType *, int>, QQmlPropertyCache *>::const_iterator TypePropertyCacheIt; - typedef QHash<int, QQmlCompiledData *>::const_iterator CompositeTypesIt; if (inProgressCreations) qWarning() << QQmlEngine::tr("There are still \"%1\" items in the process of being created at engine destruction.").arg(inProgressCreations); @@ -634,7 +677,7 @@ QQmlEnginePrivate::~QQmlEnginePrivate() for (TypePropertyCacheIt iter = typePropertyCache.cbegin(), end = typePropertyCache.cend(); iter != end; ++iter) (*iter)->release(); - for (CompositeTypesIt iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) { + for (auto iter = m_compositeTypes.cbegin(), end = m_compositeTypes.cend(); iter != end; ++iter) { iter.value()->isRegisteredWithEngine = false; // since unregisterInternalCompositeType() will not be called in this @@ -642,12 +685,9 @@ QQmlEnginePrivate::~QQmlEnginePrivate() QMetaType::unregisterType(iter.value()->metaTypeId); QMetaType::unregisterType(iter.value()->listMetaTypeId); } +#ifndef QT_NO_QML_DEBUGGER delete profiler; -} - -void QQmlEnginePrivate::enableProfiler() -{ - profiler = new QQmlProfiler(); +#endif } void QQmlPrivate::qdeclarativeelement_destructor(QObject *o) @@ -674,9 +714,10 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o) QQmlData::QQmlData() : ownedByQml1(false), ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false), hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false), - hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false), bindingBitsSize(0), bindingBits(0), notifyList(0), context(0), outerContext(0), + hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false), + bindingBitsSize(MaxInlineBits), bindingBitsValue(0), notifyList(0), context(0), outerContext(0), bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0), - lineNumber(0), columnNumber(0), jsEngineId(0), compiledData(0), deferredData(0), + lineNumber(0), columnNumber(0), jsEngineId(0), compilationUnit(0), deferredData(0), propertyCache(0), guards(0), extendedData(0) { init(); @@ -834,18 +875,20 @@ void QQmlData::setQueuedForDeletion(QObject *object) } } -void QQmlData::flushPendingBindingImpl(int coreIndex) +void QQmlData::flushPendingBindingImpl(QQmlPropertyIndex index) { - clearPendingBindingBit(coreIndex); + clearPendingBindingBit(index.coreIndex()); // Find the binding QQmlAbstractBinding *b = bindings; - while (b && b->targetPropertyIndex() != coreIndex) + while (b && (b->targetPropertyIndex().coreIndex() != index.coreIndex() || + b->targetPropertyIndex().hasValueTypeIndex())) b = b->nextBinding(); - if (b && b->targetPropertyIndex() == coreIndex) - b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor | - QQmlPropertyPrivate::DontRemoveBinding); + if (b && b->targetPropertyIndex().coreIndex() == index.coreIndex() && + !b->targetPropertyIndex().hasValueTypeIndex()) + b->setEnabled(true, QQmlPropertyData::BypassInterceptor | + QQmlPropertyData::DontRemoveBinding); } bool QQmlEnginePrivate::baseModulesUninitialized = true; @@ -973,8 +1016,19 @@ QQmlEngine::~QQmlEngine() /*! \fn void QQmlEngine::quit() This signal is emitted when the QML loaded by the engine would like to quit. + + \sa exit() */ +/*! \fn void QQmlEngine::exit(int retCode) + This signal is emitted when the QML loaded by the engine would like to exit + from the event loop with the specified return code. + + \since 5.8 + \sa quit() + */ + + /*! \fn void QQmlEngine::warnings(const QList<QQmlError> &warnings) This signal is emitted when \a warnings messages are generated by QML. */ @@ -1065,7 +1119,17 @@ QQmlAbstractUrlInterceptor *QQmlEngine::urlInterceptor() const return d->urlInterceptor; } +void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index) +{ + if (activeObjectCreator) { + activeObjectCreator->finalizeCallbacks()->append(qMakePair(QPointer<QObject>(obj), index)); + } else { + void *args[] = { 0 }; + QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args); + } +} +#if QT_CONFIG(qml_network) /*! Sets the \a factory to use for creating QNetworkAccessManager(s). @@ -1094,16 +1158,6 @@ QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const return d->networkAccessManagerFactory; } -void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index) -{ - if (activeObjectCreator) { - activeObjectCreator->finalizeCallbacks()->append(qMakePair(QPointer<QObject>(obj), index)); - } else { - void *args[] = { 0 }; - QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args); - } -} - QNetworkAccessManager *QQmlEnginePrivate::createNetworkAccessManager(QObject *parent) const { QMutexLocker locker(&networkAccessManagerMutex); @@ -1142,6 +1196,7 @@ QNetworkAccessManager *QQmlEngine::networkAccessManager() const Q_D(const QQmlEngine); return d->getNetworkAccessManager(); } +#endif // qml_network /*! @@ -1404,7 +1459,7 @@ void qmlExecuteDeferred(QObject *object) QQmlComponentPrivate::beginDeferred(ep, object, &state); // Release the reference for the deferral action (we still have one from construction) - data->deferredData->compiledData->release(); + data->deferredData->compilationUnit->release(); delete data->deferredData; data->deferredData = 0; @@ -1635,13 +1690,13 @@ void QQmlData::destroyed(QObject *object) if (bindings && !bindings->ref.deref()) delete bindings; - if (compiledData) { - compiledData->release(); - compiledData = 0; + if (compilationUnit) { + compilationUnit->release(); + compilationUnit = 0; } if (deferredData) { - deferredData->compiledData->release(); + deferredData->compilationUnit->release(); delete deferredData; deferredData = 0; } @@ -1664,7 +1719,7 @@ void QQmlData::destroyed(QObject *object) QString source = expr->expression(); if (source.size() > 100) { source.truncate(96); - source.append(QStringLiteral(" ...")); + source.append(QLatin1String(" ...")); } locationString.append(source); } else { @@ -1684,7 +1739,7 @@ void QQmlData::destroyed(QObject *object) signalHandler = next; } - if (bindingBitsSize > 32) + if (bindingBitsSize > MaxInlineBits) free(bindingBits); if (propertyCache) @@ -1709,6 +1764,8 @@ void QQmlData::destroyed(QObject *object) if (ownMemory) delete this; + else + this->~QQmlData(); } DEFINE_BOOL_CONFIG_OPTION(parentTest, QML_PARENT_TEST); @@ -1732,31 +1789,27 @@ void QQmlData::parentChanged(QObject *object, QObject *parent) static void QQmlData_setBit(QQmlData *data, QObject *obj, int bit) { - if (data->bindingBitsSize == 0 && bit < 32) { - data->bindingBitsSize = 32; - } - - if (data->bindingBitsSize <= bit) { + if (Q_UNLIKELY(data->bindingBitsSize <= bit)) { int props = QQmlMetaObject(obj).propertyCount(); Q_ASSERT(bit < 2 * props); - int arraySize = (2 * props + 31) / 32; + int arraySize = (2 * props + MaxInlineBits - 1) / MaxInlineBits; Q_ASSERT(arraySize > 1); // special handling for 32 here is to make sure we wipe the first byte // when going from bindingBitsValue to bindingBits, and preserve the old // set bits so we can restore them after the allocation - int oldArraySize = data->bindingBitsSize > 32 ? data->bindingBitsSize / 32 : 0; - quint32 oldValue = data->bindingBitsSize == 32 ? data->bindingBitsValue : 0; + int oldArraySize = data->bindingBitsSize > MaxInlineBits ? data->bindingBitsSize / MaxInlineBits : 0; + quintptr oldValue = data->bindingBitsSize == MaxInlineBits ? data->bindingBitsValue : 0; - data->bindingBits = (quint32 *)realloc((data->bindingBitsSize == 32) ? 0 : data->bindingBits, - arraySize * sizeof(quint32)); + data->bindingBits = static_cast<BindingBitsType *>(realloc((data->bindingBitsSize == MaxInlineBits) ? 0 : data->bindingBits, + arraySize * sizeof(BindingBitsType))); memset(data->bindingBits + oldArraySize, 0x00, - sizeof(quint32) * (arraySize - oldArraySize)); + sizeof(BindingBitsType) * (arraySize - oldArraySize)); - data->bindingBitsSize = arraySize * 32; + data->bindingBitsSize = arraySize * MaxInlineBits; // reinstate bindingBitsValue after we dropped it if (oldValue) { @@ -1764,50 +1817,63 @@ static void QQmlData_setBit(QQmlData *data, QObject *obj, int bit) } } - if (data->bindingBitsSize == 32) - data->bindingBitsValue |= (1 << (bit % 32)); + if (data->bindingBitsSize == MaxInlineBits) + data->bindingBitsValue |= BindingBitsType(1) << bit; else - data->bindingBits[bit / 32] |= (1 << (bit % 32)); + data->bindingBits[bit / MaxInlineBits] |= (BindingBitsType(1) << (bit % MaxInlineBits)); } static void QQmlData_clearBit(QQmlData *data, int bit) { if (data->bindingBitsSize > bit) { - if (data->bindingBitsSize == 32) - data->bindingBitsValue &= ~(1 << (bit % 32)); + if (data->bindingBitsSize == MaxInlineBits) + data->bindingBitsValue &= ~(BindingBitsType(1) << (bit % MaxInlineBits)); else - data->bindingBits[bit / 32] &= ~(1 << (bit % 32)); + data->bindingBits[bit / MaxInlineBits] &= ~(BindingBitsType(1) << (bit % MaxInlineBits)); } } void QQmlData::clearBindingBit(int coreIndex) { + Q_ASSERT(coreIndex >= 0); + Q_ASSERT(coreIndex <= 0xffff); QQmlData_clearBit(this, coreIndex * 2); } void QQmlData::setBindingBit(QObject *obj, int coreIndex) { + Q_ASSERT(coreIndex >= 0); + Q_ASSERT(coreIndex <= 0xffff); QQmlData_setBit(this, obj, coreIndex * 2); } void QQmlData::clearPendingBindingBit(int coreIndex) { + Q_ASSERT(coreIndex >= 0); + Q_ASSERT(coreIndex <= 0xffff); QQmlData_clearBit(this, coreIndex * 2 + 1); } void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex) { + Q_ASSERT(coreIndex >= 0); + Q_ASSERT(coreIndex <= 0xffff); QQmlData_setBit(this, obj, coreIndex * 2 + 1); } -QQmlPropertyCache *QQmlData::ensurePropertyCache(QJSEngine *engine, QObject *object) +QQmlData *QQmlData::createQQmlData(QObjectPrivate *priv) +{ + Q_ASSERT(priv); + priv->declarativeData = new QQmlData; + return static_cast<QQmlData *>(priv->declarativeData); +} + +QQmlPropertyCache *QQmlData::createPropertyCache(QJSEngine *engine, QObject *object) { - Q_ASSERT(engine); QQmlData *ddata = QQmlData::get(object, /*create*/true); - if (!ddata->propertyCache){ - ddata->propertyCache = QJSEnginePrivate::get(engine)->cache(object); - if (ddata->propertyCache) ddata->propertyCache->addref(); - } + ddata->propertyCache = QJSEnginePrivate::get(engine)->cache(object); + if (ddata->propertyCache) + ddata->propertyCache->addref(); return ddata->propertyCache; } @@ -1820,6 +1886,14 @@ void QQmlEnginePrivate::sendQuit() } } +void QQmlEnginePrivate::sendExit(int retCode) +{ + Q_Q(QQmlEngine); + if (q->receivers(SIGNAL(exit(int))) == 0) + qWarning("Signal QQmlEngine::exit() emitted, but no receivers connected to handle it."); + emit q->exit(retCode); +} + static void dumpwarning(const QQmlError &error) { QMessageLogger(error.url().toString().toLatin1().constData(), @@ -2219,9 +2293,9 @@ int QQmlEnginePrivate::listType(int t) const QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const { Locker locker(this); - QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t); + auto iter = m_compositeTypes.constFind(t); if (iter != m_compositeTypes.cend()) { - return QQmlMetaObject((*iter)->rootPropertyCache); + return QQmlMetaObject((*iter)->rootPropertyCache()); } else { QQmlType *type = QQmlMetaType::qmlType(t); return QQmlMetaObject(type?type->baseMetaObject():0); @@ -2231,9 +2305,9 @@ QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const { Locker locker(this); - QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t); + auto iter = m_compositeTypes.constFind(t); if (iter != m_compositeTypes.cend()) { - return QQmlMetaObject((*iter)->rootPropertyCache); + return QQmlMetaObject((*iter)->rootPropertyCache()); } else { QQmlType *type = QQmlMetaType::qmlType(t); return QQmlMetaObject(type?type->metaObject():0); @@ -2243,9 +2317,9 @@ QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t) { Locker locker(this); - QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t); + auto iter = m_compositeTypes.constFind(t); if (iter != m_compositeTypes.cend()) { - return (*iter)->rootPropertyCache; + return (*iter)->rootPropertyCache(); } else { QQmlType *type = QQmlMetaType::qmlType(t); locker.unlock(); @@ -2256,9 +2330,9 @@ QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t) QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t) { Locker locker(this); - QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t); + auto iter = m_compositeTypes.constFind(t); if (iter != m_compositeTypes.cend()) { - return (*iter)->rootPropertyCache; + return (*iter)->rootPropertyCache(); } else { QQmlType *type = QQmlMetaType::qmlType(t); locker.unlock(); @@ -2266,9 +2340,9 @@ QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t) } } -void QQmlEnginePrivate::registerInternalCompositeType(QQmlCompiledData *data) +void QQmlEnginePrivate::registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit) { - QByteArray name = data->rootPropertyCache->className(); + QByteArray name = compilationUnit->rootPropertyCache()->className(); QByteArray ptr = name + '*'; QByteArray lst = "QQmlListProperty<" + name + '>'; @@ -2286,21 +2360,21 @@ void QQmlEnginePrivate::registerInternalCompositeType(QQmlCompiledData *data) static_cast<QFlags<QMetaType::TypeFlag> >(QtPrivate::QMetaTypeTypeFlags<QQmlListProperty<QObject> >::Flags), static_cast<QMetaObject*>(0)); - data->metaTypeId = ptr_type; - data->listMetaTypeId = lst_type; - data->isRegisteredWithEngine = true; + compilationUnit->metaTypeId = ptr_type; + compilationUnit->listMetaTypeId = lst_type; + compilationUnit->isRegisteredWithEngine = true; Locker locker(this); m_qmlLists.insert(lst_type, ptr_type); // The QQmlCompiledData is not referenced here, but it is removed from this // hash in the QQmlCompiledData destructor - m_compositeTypes.insert(ptr_type, data); + m_compositeTypes.insert(ptr_type, compilationUnit); } -void QQmlEnginePrivate::unregisterInternalCompositeType(QQmlCompiledData *data) +void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit) { - int ptr_type = data->metaTypeId; - int lst_type = data->listMetaTypeId; + int ptr_type = compilationUnit->metaTypeId; + int lst_type = compilationUnit->listMetaTypeId; Locker locker(this); m_qmlLists.remove(lst_type); @@ -2320,7 +2394,7 @@ bool QQmlEnginePrivate::isScriptLoaded(const QUrl &url) const return typeLoader.isScriptLoaded(url); } -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && !defined(Q_OS_WINRT) +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) // Normalize a file name using Shell API. As opposed to converting it // to a short 8.3 name and back, this also works for drives where 8.3 notation // is disabled (see 8dot3name options of fsutil.exe). @@ -2352,7 +2426,7 @@ static inline QString shellNormalizeFileName(const QString &name) canonicalName[0] = canonicalName.at(0).toUpper(); return QDir::cleanPath(canonicalName); } -#endif // Q_OS_WIN && !Q_OS_WINCE && !Q_OS_WINRT +#endif // Q_OS_WIN && !Q_OS_WINRT bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */) { @@ -2360,7 +2434,7 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */) QFileInfo info(fileName); const QString absolute = info.absoluteFilePath(); -#if defined(Q_OS_MAC) || defined(Q_OS_WINCE) || defined(Q_OS_WINRT) +#if defined(Q_OS_DARWIN) || defined(Q_OS_WINRT) const QString canonical = info.canonicalFilePath(); #elif defined(Q_OS_WIN) // No difference if the path is qrc based diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index bd2a3cfc48..2c0c39d0b4 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -87,8 +87,10 @@ class QQmlExpression; class QQmlContext; class QQmlType; class QUrl; +#if QT_CONFIG(qml_network) class QNetworkAccessManager; class QQmlNetworkAccessManagerFactory; +#endif class QQmlIncubationController; class Q_QML_EXPORT QQmlEngine : public QJSEngine { @@ -115,10 +117,12 @@ public: bool importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors); +#if QT_CONFIG(qml_network) void setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *); QQmlNetworkAccessManagerFactory *networkAccessManagerFactory() const; QNetworkAccessManager *networkAccessManager() const; +#endif void setUrlInterceptor(QQmlAbstractUrlInterceptor* urlInterceptor); QQmlAbstractUrlInterceptor* urlInterceptor() const; @@ -151,6 +155,7 @@ protected: Q_SIGNALS: void quit(); + void exit(int retCode); void warnings(const QList<QQmlError> &warnings); private: diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 003cfa0112..916566b6c7 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -134,8 +134,12 @@ public: QRecyclePool<QQmlJavaScriptExpressionGuard> jsExpressionGuardPool; QQmlContext *rootContext; + +#ifdef QT_NO_QML_DEBUGGER + static const quintptr profiler = 0; +#else QQmlProfiler *profiler; - void enableProfiler(); +#endif bool outputWarningsToMsgLog; @@ -158,12 +162,12 @@ public: void registerFinalizeCallback(QObject *obj, int index); QQmlObjectCreator *activeObjectCreator; - +#if QT_CONFIG(qml_network) QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const; QNetworkAccessManager *getNetworkAccessManager() const; mutable QNetworkAccessManager *networkAccessManager; mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory; - +#endif QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders; QQmlAbstractUrlInterceptor* urlInterceptor; @@ -216,13 +220,14 @@ public: QQmlMetaObject metaObjectForType(int) const; QQmlPropertyCache *propertyCacheForType(int); QQmlPropertyCache *rawPropertyCacheForType(int); - void registerInternalCompositeType(QQmlCompiledData *); - void unregisterInternalCompositeType(QQmlCompiledData *); + void registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit); + void unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit); bool isTypeLoaded(const QUrl &url) const; bool isScriptLoaded(const QUrl &url) const; void sendQuit(); + void sendExit(int retCode = 0); void warning(const QQmlError &); void warning(const QList<QQmlError> &); void warning(QQmlDelayedError *); @@ -260,7 +265,7 @@ private: // the threaded loader. Only access them through their respective accessor methods. QHash<QPair<QQmlType *, int>, QQmlPropertyCache *> typePropertyCache; QHash<int, int> m_qmlLists; - QHash<int, QQmlCompiledData *> m_compositeTypes; + QHash<int, QV4::CompiledData::CompilationUnit *> m_compositeTypes; static bool s_designerMode; // These members is protected by the full QQmlEnginePrivate::mutex mutex diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp index 74ceeabeb4..b309550ca8 100644 --- a/src/qml/qml/qqmlerror.cpp +++ b/src/qml/qml/qqmlerror.cpp @@ -249,9 +249,9 @@ QString QQmlError::toString() const int l(line()); if (u.isEmpty() || (u.isLocalFile() && u.path().isEmpty())) - rv = QLatin1String("<Unknown File>"); + rv += QLatin1String("<Unknown File>"); else - rv = u.toString(); + rv += u.toString(); if (l != -1) { rv += QLatin1Char(':') + QString::number(l); diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp index 50880e70ea..6afbd05e3e 100644 --- a/src/qml/qml/qqmlexpression.cpp +++ b/src/qml/qml/qqmlexpression.cpp @@ -44,7 +44,7 @@ #include "qqmlengine_p.h" #include "qqmlcontext_p.h" #include "qqmlscriptstring_p.h" -#include "qqmlcompiler_p.h" +#include "qqmlbinding_p.h" #include <private/qv8engine_p.h> #include <QtCore/qdebug.h> @@ -245,14 +245,15 @@ void QQmlExpression::setExpression(const QString &expression) } // Must be called with a valid handle scope -QV4::ReturnedValue QQmlExpressionPrivate::v4value(bool *isUndefined) +void QQmlExpressionPrivate::v4value(bool *isUndefined, QV4::Scope &scope) { if (!expressionFunctionValid) { createQmlBinding(context(), scopeObject(), expression, url, line); expressionFunctionValid = true; } - return evaluate(isUndefined); + QV4::ScopedCallData callData(scope); + evaluate(callData, isUndefined, scope); } QVariant QQmlExpressionPrivate::value(bool *isUndefined) @@ -271,9 +272,9 @@ QVariant QQmlExpressionPrivate::value(bool *isUndefined) { QV4::Scope scope(QV8Engine::getV4(ep->v8engine())); - QV4::ScopedValue result(scope, v4value(isUndefined)); + v4value(isUndefined, scope); if (!hasError()) - rv = scope.engine->toVariant(result, -1); + rv = scope.engine->toVariant(scope.result, -1); } ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h index 3d1df55a2d..809a57b169 100644 --- a/src/qml/qml/qqmlexpression_p.h +++ b/src/qml/qml/qqmlexpression_p.h @@ -56,8 +56,6 @@ #include <private/qqmlengine_p.h> #include <private/qfieldlist_p.h> #include <private/qflagpointer_p.h> -#include <private/qdeletewatcher_p.h> -#include <private/qpointervaluepair_p.h> #include <private/qqmljavascriptexpression_p.h> QT_BEGIN_NAMESPACE @@ -77,7 +75,7 @@ public: QVariant value(bool *isUndefined = 0); - QV4::ReturnedValue v4value(bool *isUndefined = 0); + void v4value(bool *isUndefined, QV4::Scope &scope); static inline QQmlExpressionPrivate *get(QQmlExpression *expr); static inline QQmlExpression *get(QQmlExpressionPrivate *expr); diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp index 5fe3cba5c3..4e4db086b0 100644 --- a/src/qml/qml/qqmlfile.cpp +++ b/src/qml/qml/qqmlfile.cpp @@ -67,6 +67,8 @@ static char assets_string[] = "assets"; #endif class QQmlFilePrivate; + +#if QT_CONFIG(qml_network) class QQmlFileNetworkReply : public QObject { Q_OBJECT @@ -97,6 +99,7 @@ private: int m_redirectCount; QNetworkReply *m_reply; }; +#endif class QQmlFilePrivate { @@ -114,10 +117,12 @@ public: Error error; QString errorString; - +#if QT_CONFIG(qml_network) QQmlFileNetworkReply *reply; +#endif }; +#if QT_CONFIG(qml_network) int QQmlFileNetworkReply::finishedIndex = -1; int QQmlFileNetworkReply::downloadProgressIndex = -1; int QQmlFileNetworkReply::networkFinishedIndex = -1; @@ -200,9 +205,13 @@ void QQmlFileNetworkReply::networkDownloadProgress(qint64 a, qint64 b) { emit downloadProgress(a, b); } +#endif // qml_network QQmlFilePrivate::QQmlFilePrivate() -: error(None), reply(0) +: error(None) +#if QT_CONFIG(qml_network) +, reply(0) +#endif { } @@ -218,14 +227,15 @@ QQmlFile::QQmlFile(QQmlEngine *e, const QUrl &url) } QQmlFile::QQmlFile(QQmlEngine *e, const QString &url) -: d(new QQmlFilePrivate) + : QQmlFile(e, QUrl(url)) { - load(e, url); } QQmlFile::~QQmlFile() { +#if QT_CONFIG(qml_network) delete d->reply; +#endif delete d; d = 0; } @@ -263,8 +273,10 @@ QQmlFile::Status QQmlFile::status() const { if (d->url.isEmpty() && d->urlString.isEmpty()) return Null; +#if QT_CONFIG(qml_network) else if (d->reply) return Loading; +#endif else if (d->error != QQmlFilePrivate::None) return Error; else @@ -321,7 +333,11 @@ void QQmlFile::load(QQmlEngine *engine, const QUrl &url) d->error = QQmlFilePrivate::NotFound; } } else { +#if QT_CONFIG(qml_network) d->reply = new QQmlFileNetworkReply(engine, d, url); +#else + d->error = QQmlFilePrivate::NotFound; +#endif } } @@ -348,10 +364,14 @@ void QQmlFile::load(QQmlEngine *engine, const QString &url) d->error = QQmlFilePrivate::NotFound; } } else { +#if QT_CONFIG(qml_network) QUrl qurl(url); d->url = qurl; d->urlString = QString(); d->reply = new QQmlFileNetworkReply(engine, d, qurl); +#else + d->error = QQmlFilePrivate::NotFound; +#endif } } @@ -368,6 +388,7 @@ void QQmlFile::clear(QObject *) clear(); } +#if QT_CONFIG(qml_network) bool QQmlFile::connectFinished(QObject *object, const char *method) { if (!d || !d->reply) { @@ -411,6 +432,7 @@ bool QQmlFile::connectDownloadProgress(QObject *object, int method) return QMetaObject::connect(d->reply, QQmlFileNetworkReply::downloadProgressIndex, object, method); } +#endif /*! Returns true if QQmlFile will open \a url synchronously. diff --git a/src/qml/qml/qqmlfile.h b/src/qml/qml/qqmlfile.h index b0910cc0f4..aec0981a95 100644 --- a/src/qml/qml/qqmlfile.h +++ b/src/qml/qml/qqmlfile.h @@ -80,10 +80,12 @@ public: void clear(); void clear(QObject *); +#if QT_CONFIG(qml_network) bool connectFinished(QObject *, const char *); bool connectFinished(QObject *, int); bool connectDownloadProgress(QObject *, const char *); bool connectDownloadProgress(QObject *, int); +#endif static bool isSynchronous(const QString &url); static bool isSynchronous(const QUrl &url); diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index c1f5e75369..98e2f9eefd 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -191,7 +191,7 @@ void qmlClearEnginePlugins() { StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes(); QMutexLocker lock(&plugins->mutex); - foreach (RegisteredPlugin plugin, plugins->values()) { + for (auto &plugin : qAsConst(*plugins)) { QPluginLoader* loader = plugin.loader; if (loader && !loader->unload()) qWarning("Unloading %s failed: %s", qPrintable(plugin.uri), qPrintable(loader->errorString())); @@ -399,9 +399,7 @@ bool excludeBaseUrl(const QString &importUrl, const QString &fileName, const QSt if (baseUrl.startsWith(importUrl)) { - QString typeUrl(importUrl); - typeUrl.append(fileName); - if (typeUrl == baseUrl) + if (fileName == baseUrl.midRef(importUrl.size())) return false; } @@ -540,10 +538,10 @@ QString QQmlImports::versionString(int vmaj, int vmin, ImportVersion version) { if (version == QQmlImports::FullyVersioned) { // extension with fully encoded version number (eg. MyModule.3.2) - return QString(QLatin1String(".%1.%2")).arg(vmaj).arg(vmin); + return QString::asprintf(".%d.%d", vmaj, vmin); } else if (version == QQmlImports::PartiallyVersioned) { // extension with encoded version major (eg. MyModule.3) - return QString(QLatin1String(".%1")).arg(vmaj); + return QString::asprintf(".%d", vmaj); } // else extension without version number (eg. MyModule) return QString(); } @@ -913,7 +911,7 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res // To avoid traversing all static plugins for all imports, we cut down // the list the first time called to only contain QML plugins: foreach (const QStaticPlugin &plugin, QPluginLoader::staticPlugins()) { - if (qobject_cast<QQmlExtensionPlugin *>(plugin.instance())) + if (plugin.metaData().value(QLatin1String("IID")).toString() == QLatin1String(QQmlExtensionInterface_iid)) plugins.append(plugin); } } @@ -921,7 +919,7 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res foreach (const QStaticPlugin &plugin, plugins) { // Since a module can list more than one plugin, we keep iterating even after we found a match. if (QQmlExtensionPlugin *instance = qobject_cast<QQmlExtensionPlugin *>(plugin.instance())) { - const QJsonArray metaTagsUriList = plugin.metaData().value(QStringLiteral("uri")).toArray(); + const QJsonArray metaTagsUriList = plugin.metaData().value(QLatin1String("uri")).toArray(); if (metaTagsUriList.isEmpty()) { if (errors) { QQmlError error; @@ -1395,15 +1393,9 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix // The uri for this import. For library imports this is the same as uri // specified by the user, but it may be different in the case of file imports. QString importUri = uri; - - QString qmldirPath = importUri; - if (importUri.endsWith(Slash)) - qmldirPath += String_qmldir; - else - qmldirPath += Slash_qmldir; - - QString qmldirUrl = resolveLocalUrl(base, qmldirPath); - + QString qmldirUrl = resolveLocalUrl(base, importUri + (importUri.endsWith(Slash) + ? String_qmldir + : Slash_qmldir)); QString qmldirIdentifier; if (QQmlFile::isLocalFile(qmldirUrl)) { @@ -1701,13 +1693,9 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader, if (!resolvedPath.endsWith(Slash)) resolvedPath += Slash; + resolvedPath += prefix + baseName; foreach (const QString &suffix, suffixes) { - QString pluginFileName = prefix; - - pluginFileName += baseName; - pluginFileName += suffix; - - QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + pluginFileName); + const QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + suffix); if (!absolutePath.isEmpty()) return absolutePath; } @@ -1739,29 +1727,32 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader, const QString &baseName) { #if defined(Q_OS_WIN) - return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, - QStringList() + static const QString prefix; + static const QStringList suffixes = { # ifdef QT_DEBUG - << QLatin1String("d.dll") // try a qmake-style debug build first + QLatin1String("d.dll"), // try a qmake-style debug build first # endif - << QLatin1String(".dll")); + QLatin1String(".dll") + }; #elif defined(Q_OS_DARWIN) - - return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, - QStringList() + static const QString prefix = QLatin1String("lib"); + static const QStringList suffixes = { # ifdef QT_DEBUG - << QLatin1String("_debug.dylib") // try a qmake-style debug build first - << QLatin1String(".dylib") + QLatin1String("_debug.dylib"), // try a qmake-style debug build first + QLatin1String(".dylib"), # else - << QLatin1String(".dylib") - << QLatin1String("_debug.dylib") // try a qmake-style debug build after + QLatin1String(".dylib"), + QLatin1String("_debug.dylib"), // try a qmake-style debug build after # endif - << QLatin1String(".so") - << QLatin1String(".bundle"), - QLatin1String("lib")); + QLatin1String(".so"), + QLatin1String(".bundle") + }; # else // Unix - return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, QStringList() << QLatin1String(".so"), QLatin1String("lib")); + static const QString prefix = QLatin1String("lib"); + static const QStringList suffixes = { QLatin1String(".so") }; #endif + + return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, suffixes, prefix); } /*! @@ -1820,7 +1811,7 @@ void QQmlImportDatabase::addImportPath(const QString& path) } else if (path.startsWith(QLatin1Char(':'))) { // qrc directory, e.g. :/foo // need to convert to a qrc url, e.g. qrc:/foo - cPath = QStringLiteral("qrc") + path; + cPath = QLatin1String("qrc") + path; cPath.replace(Backslash, Slash); } else if (url.isRelative() || (url.scheme().length() == 1 && QFile::exists(path)) ) { // windows path @@ -1960,7 +1951,7 @@ bool QQmlImportDatabase::importStaticPlugin(QObject *instance, const QString &ba #ifndef QT_NO_LIBRARY // Dynamic plugins are differentiated by their filepath. For static plugins we // don't have that information so we use their address as key instead. - QString uniquePluginID = QString().sprintf("%p", instance); + const QString uniquePluginID = QString::asprintf("%p", instance); StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes(); QMutexLocker lock(&plugins->mutex); diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp index f0f160e6f6..0ce769aaea 100644 --- a/src/qml/qml/qqmlincubator.cpp +++ b/src/qml/qml/qqmlincubator.cpp @@ -41,7 +41,6 @@ #include "qqmlcomponent.h" #include "qqmlincubator_p.h" -#include "qqmlcompiler_p.h" #include "qqmlexpression_p.h" #include "qqmlmemoryprofiler_p.h" #include "qqmlobjectcreator_p.h" @@ -132,7 +131,7 @@ QQmlIncubationController *QQmlEngine::incubationController() const QQmlIncubatorPrivate::QQmlIncubatorPrivate(QQmlIncubator *q, QQmlIncubator::IncubationMode m) : q(q), status(QQmlIncubator::Null), mode(m), isAsynchronous(false), progress(Execute), - result(0), compiledData(0), waitingOnMe(0) + result(0), enginePriv(0), waitingOnMe(0) { } @@ -143,20 +142,15 @@ QQmlIncubatorPrivate::~QQmlIncubatorPrivate() void QQmlIncubatorPrivate::clear() { + compilationUnit = nullptr; if (next.isInList()) { next.remove(); - Q_ASSERT(compiledData); - QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(compiledData->engine); - compiledData->release(); - compiledData = 0; enginePriv->incubatorCount--; QQmlIncubationController *controller = enginePriv->incubationController; if (controller) controller->incubatingObjectCountChanged(enginePriv->incubatorCount); - } else if (compiledData) { - compiledData->release(); - compiledData = 0; } + enginePriv = 0; if (!rootContext.isNull()) { rootContext->activeVMEData = 0; rootContext = 0; @@ -278,21 +272,20 @@ void QQmlIncubatorPrivate::forceCompletion(QQmlInstantiationInterrupt &i) void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i) { - if (!compiledData) + if (!compilationUnit) return; - QML_MEMORY_SCOPE_URL(compiledData->url()); + QML_MEMORY_SCOPE_URL(compilationUnit->url()); QExplicitlySharedDataPointer<QQmlIncubatorPrivate> protectThis(this); QRecursionWatcher<QQmlIncubatorPrivate, &QQmlIncubatorPrivate::recursion> watcher(this); - - QQmlEngine *engine = compiledData->engine; - QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(engine); + // get a copy of the engine pointer as it might get reset; + QQmlEnginePrivate *enginePriv = this->enginePriv; if (!vmeGuard.isOK()) { QQmlError error; - error.setUrl(compiledData->url()); + error.setUrl(compilationUnit->url()); error.setDescription(QQmlComponent::tr("Object destroyed during incubation")); errors << error; progress = QQmlIncubatorPrivate::Completed; @@ -563,17 +556,16 @@ void QQmlIncubator::clear() if (s == Null) return; - QQmlEnginePrivate *enginePriv = 0; + QQmlEnginePrivate *enginePriv = d->enginePriv; if (s == Loading) { - Q_ASSERT(d->compiledData); - enginePriv = QQmlEnginePrivate::get(d->compiledData->engine); + Q_ASSERT(d->compilationUnit); if (d->result) d->result->deleteLater(); d->result = 0; } d->clear(); - Q_ASSERT(d->compiledData == 0); + Q_ASSERT(d->compilationUnit.isNull()); Q_ASSERT(d->waitingOnMe.data() == 0); Q_ASSERT(d->waitingFor.isEmpty()); @@ -713,7 +705,7 @@ QQmlIncubator::Status QQmlIncubatorPrivate::calculateStatus() const return QQmlIncubator::Error; else if (result && progress == QQmlIncubatorPrivate::Completed && waitingFor.isEmpty()) return QQmlIncubator::Ready; - else if (compiledData) + else if (compilationUnit) return QQmlIncubator::Loading; else return QQmlIncubator::Null; diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h index a12ff9c5e2..ecf3b6d2ca 100644 --- a/src/qml/qml/qqmlincubator_p.h +++ b/src/qml/qml/qqmlincubator_p.h @@ -59,7 +59,6 @@ QT_BEGIN_NAMESPACE -class QQmlCompiledData; class QQmlIncubator; class QQmlIncubatorPrivate : public QQmlEnginePrivate::Incubator { @@ -85,7 +84,8 @@ public: QPointer<QObject> result; QQmlGuardedContextData rootContext; - QQmlCompiledData *compiledData; + QQmlEnginePrivate *enginePriv; + QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit; QScopedPointer<QQmlObjectCreator> creator; int subComponentToCreate; QQmlVMEGuard vmeGuard; diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index cf0b823612..8020bdb2be 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -106,7 +106,8 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression() m_nextExpression->m_prevExpression = m_prevExpression; } - clearGuards(); + clearActiveGuards(); + clearPermanentGuards(); if (m_scopeObject.isT2()) // notify DeleteWatcher of our deletion. m_scopeObject.asT2()->_s = 0; } @@ -114,12 +115,17 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression() void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v) { activeGuards.setFlagValue(v); - if (!v) clearGuards(); + permanentGuards.setFlagValue(v); + if (!v) { + clearActiveGuards(); + clearPermanentGuards(); + m_permanentDependenciesRegistered = false; + } } void QQmlJavaScriptExpression::resetNotifyOnValueChanged() { - clearGuards(); + setNotifyOnValueChanged(false); } void QQmlJavaScriptExpression::setContext(QQmlContextData *context) @@ -147,16 +153,9 @@ void QQmlJavaScriptExpression::refresh() { } -QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(bool *isUndefined) -{ - QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_context->engine); - QV4::Scope scope(v4); - QV4::ScopedCallData callData(scope); - return evaluate(callData, isUndefined); -} -QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefined) +void QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefined, QV4::Scope &scope) { Q_ASSERT(m_context && m_context->engine); @@ -164,7 +163,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b if (!f || f->isUndefined()) { if (isUndefined) *isUndefined = true; - return QV4::Encode::undefined(); + return; } QQmlEnginePrivate *ep = QQmlEnginePrivate::get(m_context->engine); @@ -184,8 +183,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b capture.guards.copyAndClearPrepend(activeGuards); QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine()); - QV4::Scope scope(v4); - QV4::ScopedValue result(scope, QV4::Primitive::undefinedValue()); + scope.result = QV4::Primitive::undefinedValue(); callData->thisObject = v4->globalObject; if (scopeObject()) { QV4::ScopedValue value(scope, QV4::QObjectWrapper::wrap(v4, scopeObject())); @@ -193,7 +191,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b callData->thisObject = value; } - result = f->as<QV4::FunctionObject>()->call(callData); + f->as<QV4::FunctionObject>()->call(scope, callData); if (scope.hasException()) { if (watcher.wasDeleted()) scope.engine->catchException(); // ignore exception @@ -203,7 +201,7 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b *isUndefined = true; } else { if (isUndefined) - *isUndefined = result->isUndefined(); + *isUndefined = scope.result.isUndefined(); if (!watcher.wasDeleted() && hasDelayedError()) delayedError()->clearError(); @@ -220,11 +218,9 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b g->Delete(); ep->propertyCapture = lastPropertyCapture; - - return result->asReturnedValue(); } -void QQmlPropertyCapture::captureProperty(QQmlNotifier *n) +void QQmlPropertyCapture::captureProperty(QQmlNotifier *n, Duration duration) { if (watcher->wasDeleted()) return; @@ -244,14 +240,17 @@ void QQmlPropertyCapture::captureProperty(QQmlNotifier *n) g->connect(n); } - expression->activeGuards.prepend(g); + if (duration == Permanently) + expression->permanentGuards.prepend(g); + else + expression->activeGuards.prepend(g); } /*! \internal \a n is in the signal index range (see QObjectPrivate::signalIndex()). */ -void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n) +void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, Duration duration) { if (watcher->wasDeleted()) return; @@ -290,15 +289,19 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n) g->connect(o, n, engine); } - expression->activeGuards.prepend(g); + if (duration == Permanently) + expression->permanentGuards.prepend(g); + else + expression->activeGuards.prepend(g); } } -void QQmlPropertyCapture::registerQmlDependencies(QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction) +void QQmlPropertyCapture::registerQmlDependencies(const QV4::CompiledData::Function *compiledFunction, const QV4::Scope &scope) { // Let the caller check and avoid the function call :) Q_ASSERT(compiledFunction->hasQmlDependencies()); + QV4::ExecutionEngine *engine = scope.engine; QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->qmlEngine()); if (!ep) return; @@ -306,33 +309,40 @@ void QQmlPropertyCapture::registerQmlDependencies(QV4::ExecutionEngine *engine, if (!capture || capture->watcher->wasDeleted()) return; - QV4::Scope scope(engine); + if (capture->expression->m_permanentDependenciesRegistered) + return; + + capture->expression->m_permanentDependenciesRegistered = true; + QV4::Scoped<QV4::QmlContext> context(scope, engine->qmlContext()); QQmlContextData *qmlContext = context->qmlContext(); - const quint32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable(); + const QV4::CompiledData::LEUInt32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable(); const int idObjectDependencyCount = compiledFunction->nDependingIdObjects; for (int i = 0; i < idObjectDependencyCount; ++i, ++idObjectDependency) { Q_ASSERT(int(*idObjectDependency) < qmlContext->idValueCount); - capture->captureProperty(&qmlContext->idValues[*idObjectDependency].bindings); + capture->captureProperty(&qmlContext->idValues[*idObjectDependency].bindings, + QQmlPropertyCapture::Permanently); } Q_ASSERT(qmlContext->contextObject); - const quint32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable(); + const QV4::CompiledData::LEUInt32 *contextPropertyDependency = compiledFunction->qmlContextPropertiesDependencyTable(); const int contextPropertyDependencyCount = compiledFunction->nDependingContextProperties; for (int i = 0; i < contextPropertyDependencyCount; ++i) { const int propertyIndex = *contextPropertyDependency++; const int notifyIndex = *contextPropertyDependency++; - capture->captureProperty(qmlContext->contextObject, propertyIndex, notifyIndex); + capture->captureProperty(qmlContext->contextObject, propertyIndex, notifyIndex, + QQmlPropertyCapture::Permanently); } QObject *scopeObject = context->qmlScope(); - const quint32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable(); + const QV4::CompiledData::LEUInt32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable(); const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties; for (int i = 0; i < scopePropertyDependencyCount; ++i) { const int propertyIndex = *scopePropertyDependency++; const int notifyIndex = *scopePropertyDependency++; - capture->captureProperty(scopeObject, propertyIndex, notifyIndex); + capture->captureProperty(scopeObject, propertyIndex, notifyIndex, + QQmlPropertyCapture::Permanently); } } @@ -416,12 +426,19 @@ void QQmlJavaScriptExpression::createQmlBinding(QQmlContextData *ctxt, QObject * } -void QQmlJavaScriptExpression::clearGuards() +void QQmlJavaScriptExpression::clearActiveGuards() { while (QQmlJavaScriptExpressionGuard *g = activeGuards.takeFirst()) g->Delete(); } +void QQmlJavaScriptExpression::clearPermanentGuards() +{ + m_permanentDependenciesRegistered = false; + while (QQmlJavaScriptExpressionGuard *g = permanentGuards.takeFirst()) + g->Delete(); +} + void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *e, void **) { QQmlJavaScriptExpression *expression = diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index 64cb1bb242..5f9cffb56d 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -54,7 +54,6 @@ #include <QtCore/qglobal.h> #include <QtQml/qqmlerror.h> #include <private/qqmlengine_p.h> -#include <private/qpointervaluepair_p.h> QT_BEGIN_NAMESPACE @@ -104,8 +103,7 @@ public: virtual QString expressionIdentifier() = 0; virtual void expressionChanged() = 0; - QV4::ReturnedValue evaluate(bool *isUndefined); - QV4::ReturnedValue evaluate(QV4::CallData *callData, bool *isUndefined); + void evaluate(QV4::CallData *callData, bool *isUndefined, QV4::Scope &scope); inline bool notifyOnValueChanged() const; @@ -138,7 +136,8 @@ public: inline bool hasDelayedError() const; QQmlError error(QQmlEngine *) const; void clearError(); - void clearGuards(); + void clearActiveGuards(); + void clearPermanentGuards(); QQmlDelayedError *delayedError(); static QV4::ReturnedValue evalFunction(QQmlContextData *ctxt, QObject *scope, @@ -147,6 +146,14 @@ public: protected: void createQmlBinding(QQmlContextData *ctxt, QObject *scope, const QString &code, const QString &filename, quint16 line); + void cancelPermanentGuards() const + { + if (m_permanentDependenciesRegistered) { + for (QQmlJavaScriptExpressionGuard *it = permanentGuards.first(); it; it = permanentGuards.next(it)) + it->cancelNotify(); + } + } + private: friend class QQmlContextData; friend class QQmlPropertyCapture; @@ -159,10 +166,12 @@ private: // activeGuards:flag2 - useSharedContext QBiPointer<QObject, DeleteWatcher> m_scopeObject; QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> activeGuards; + QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> permanentGuards; QQmlContextData *m_context; QQmlJavaScriptExpression **m_prevExpression; QQmlJavaScriptExpression *m_nextExpression; + bool m_permanentDependenciesRegistered = false; protected: QV4::PersistentValue m_function; @@ -179,10 +188,14 @@ public: Q_ASSERT(errorString == 0); } - void captureProperty(QQmlNotifier *); - void captureProperty(QObject *, int, int); + enum Duration { + OnlyOnce, + Permanently + }; - static void registerQmlDependencies(QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction); + static void registerQmlDependencies(const QV4::CompiledData::Function *compiledFunction, const QV4::Scope &scope); + void captureProperty(QQmlNotifier *, Duration duration = OnlyOnce); + void captureProperty(QObject *, int, int, Duration duration = OnlyOnce); QQmlEngine *engine; QQmlJavaScriptExpression *expression; diff --git a/src/qml/qml/qqmllist.cpp b/src/qml/qml/qqmllist.cpp index d0b7fb4853..a719956483 100644 --- a/src/qml/qml/qqmllist.cpp +++ b/src/qml/qml/qqmllist.cpp @@ -143,16 +143,16 @@ QQmlListReference::QQmlListReference(QObject *object, const char *property, QQml QQmlEnginePrivate *p = engine?QQmlEnginePrivate::get(engine):0; - int listType = p?p->listType(data->propType):QQmlMetaType::listType(data->propType); + int listType = p?p->listType(data->propType()):QQmlMetaType::listType(data->propType()); if (listType == -1) return; d = new QQmlListReferencePrivate; d->object = object; d->elementType = p?p->rawMetaObjectForType(listType):QQmlMetaType::qmlType(listType)->baseMetaObject(); - d->propertyType = data->propType; + d->propertyType = data->propType(); void *args[] = { &d->property, 0 }; - QMetaObject::metacall(object, QMetaObject::ReadProperty, data->coreIndex, args); + QMetaObject::metacall(object, QMetaObject::ReadProperty, data->coreIndex(), args); } /*! \internal */ diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp index 5c35866274..8aa107dc17 100644 --- a/src/qml/qml/qqmllistwrapper.cpp +++ b/src/qml/qml/qqmllistwrapper.cpp @@ -52,15 +52,19 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlListWrapper); -Heap::QmlListWrapper::QmlListWrapper() +void Heap::QmlListWrapper::init() { + Object::init(); + object.init(); QV4::Scope scope(internalClass->engine); QV4::ScopedObject o(scope, this); o->setArrayType(Heap::ArrayData::Custom); } -Heap::QmlListWrapper::~QmlListWrapper() +void Heap::QmlListWrapper::destroy() { + object.destroy(); + Object::destroy(); } ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, QObject *object, int propId, int propType) @@ -73,7 +77,7 @@ ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, QObject *object, i Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocObject<QmlListWrapper>()); r->d()->object = object; r->d()->propertyType = propType; - void *args[] = { &r->d()->property, 0 }; + void *args[] = { &r->d()->property(), 0 }; QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args); return r.asReturnedValue(); } @@ -84,7 +88,7 @@ ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, const QQmlListProp Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocObject<QmlListWrapper>()); r->d()->object = prop.object; - r->d()->property = prop; + r->d()->property() = prop; r->d()->propertyType = propType; return r.asReturnedValue(); } @@ -94,7 +98,7 @@ QVariant QmlListWrapper::toVariant() const if (!d()->object) return QVariant(); - return QVariant::fromValue(QQmlListReferencePrivate::init(d()->property, d()->propertyType, engine()->qmlEngine())); + return QVariant::fromValue(QQmlListReferencePrivate::init(d()->property(), d()->propertyType, engine()->qmlEngine())); } @@ -105,7 +109,7 @@ ReturnedValue QmlListWrapper::get(const Managed *m, String *name, bool *hasPrope QV4::ExecutionEngine *v4 = w->engine(); if (name->equals(v4->id_length()) && !w->d()->object.isNull()) { - quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0; + quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0; return Primitive::fromUInt32(count).asReturnedValue(); } @@ -124,11 +128,11 @@ ReturnedValue QmlListWrapper::getIndexed(const Managed *m, uint index, bool *has const QmlListWrapper *w = static_cast<const QmlListWrapper *>(m); QV4::ExecutionEngine *v4 = w->engine(); - quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0; - if (index < count && w->d()->property.at) { + quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0; + if (index < count && w->d()->property().at) { if (hasProperty) *hasProperty = true; - return QV4::QObjectWrapper::wrap(v4, w->d()->property.at(&w->d()->property, index)); + return QV4::QObjectWrapper::wrap(v4, w->d()->property().at(&w->d()->property(), index)); } if (hasProperty) @@ -150,12 +154,12 @@ void QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name *index = UINT_MAX; Q_ASSERT(m->as<QmlListWrapper>()); QmlListWrapper *w = static_cast<QmlListWrapper *>(m); - quint32 count = w->d()->property.count ? w->d()->property.count(&w->d()->property) : 0; + quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0; if (it->arrayIndex < count) { *index = it->arrayIndex; ++it->arrayIndex; *attrs = QV4::Attr_Data; - p->value = QV4::QObjectWrapper::wrap(w->engine(), w->d()->property.at(&w->d()->property, *index)); + p->value = QV4::QObjectWrapper::wrap(w->engine(), w->d()->property().at(&w->d()->property(), *index)); return; } return QV4::Object::advanceIterator(m, it, name, index, p, attrs); diff --git a/src/qml/qml/qqmllistwrapper_p.h b/src/qml/qml/qqmllistwrapper_p.h index 26e1e5faaf..d01b332159 100644 --- a/src/qml/qml/qqmllistwrapper_p.h +++ b/src/qml/qml/qqmllistwrapper_p.h @@ -66,11 +66,18 @@ namespace QV4 { namespace Heap { struct QmlListWrapper : Object { - QmlListWrapper(); - ~QmlListWrapper(); - QPointer<QObject> object; - QQmlListProperty<QObject> property; + void init(); + void destroy(); + QQmlQPointer<QObject> object; + + QQmlListProperty<QObject> &property() { + return *reinterpret_cast<QQmlListProperty<QObject>*>(propertyData); + } + int propertyType; + +private: + void *propertyData[sizeof(QQmlListProperty<QObject>)/sizeof(void*)]; }; } diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp index 76752f509c..6f66475aa5 100644 --- a/src/qml/qml/qqmllocale.cpp +++ b/src/qml/qml/qqmllocale.cpp @@ -109,16 +109,16 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::CallContext *ct if (ctx->argc() == 2) { if (ctx->args()[1].isString()) { QString format = ctx->args()[1].stringValue()->toQString(); - formattedDt = r->d()->locale.toString(dt, format); + formattedDt = r->d()->locale->toString(dt, format); } else if (ctx->args()[1].isNumber()) { quint32 intFormat = ctx->args()[1].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - formattedDt = r->d()->locale.toString(dt, format); + formattedDt = r->d()->locale->toString(dt, format); } else { V4THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format"); } } else { - formattedDt = r->d()->locale.toString(dt, enumFormat); + formattedDt = r->d()->locale->toString(dt, enumFormat); } return ctx->d()->engine->newString(formattedDt)->asReturnedValue(); @@ -154,16 +154,16 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleTimeString(QV4::CallContext if (ctx->argc() == 2) { if (ctx->args()[1].isString()) { QString format = ctx->args()[1].stringValue()->toQString(); - formattedTime = r->d()->locale.toString(time, format); + formattedTime = r->d()->locale->toString(time, format); } else if (ctx->args()[1].isNumber()) { quint32 intFormat = ctx->args()[1].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - formattedTime = r->d()->locale.toString(time, format); + formattedTime = r->d()->locale->toString(time, format); } else { V4THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format"); } } else { - formattedTime = r->d()->locale.toString(time, enumFormat); + formattedTime = r->d()->locale->toString(time, enumFormat); } return ctx->d()->engine->newString(formattedTime)->asReturnedValue(); @@ -199,16 +199,16 @@ QV4::ReturnedValue QQmlDateExtension::method_toLocaleDateString(QV4::CallContext if (ctx->argc() == 2) { if (ctx->args()[1].isString()) { QString format = ctx->args()[1].stringValue()->toQString(); - formattedDate = r->d()->locale.toString(date, format); + formattedDate = r->d()->locale->toString(date, format); } else if (ctx->args()[1].isNumber()) { quint32 intFormat = ctx->args()[1].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - formattedDate = r->d()->locale.toString(date, format); + formattedDate = r->d()->locale->toString(date, format); } else { V4THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format"); } } else { - formattedDate = r->d()->locale.toString(date, enumFormat); + formattedDate = r->d()->locale->toString(date, enumFormat); } return ctx->d()->engine->newString(formattedDate)->asReturnedValue(); @@ -237,16 +237,16 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleString(QV4::CallContext * if (ctx->argc() == 3) { if (ctx->args()[2].isString()) { QString format = ctx->args()[2].stringValue()->toQString(); - dt = r->d()->locale.toDateTime(dateString, format); + dt = r->d()->locale->toDateTime(dateString, format); } else if (ctx->args()[2].isNumber()) { quint32 intFormat = ctx->args()[2].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - dt = r->d()->locale.toDateTime(dateString, format); + dt = r->d()->locale->toDateTime(dateString, format); } else { V4THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format"); } } else { - dt = r->d()->locale.toDateTime(dateString, enumFormat); + dt = r->d()->locale->toDateTime(dateString, enumFormat); } return QV4::Encode(engine->newDateObject(dt)); @@ -278,16 +278,16 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallConte if (ctx->argc() == 3) { if (ctx->args()[2].isString()) { QString format = ctx->args()[2].stringValue()->toQString(); - tm = r->d()->locale.toTime(dateString, format); + tm = r->d()->locale->toTime(dateString, format); } else if (ctx->args()[2].isNumber()) { quint32 intFormat = ctx->args()[2].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - tm = r->d()->locale.toTime(dateString, format); + tm = r->d()->locale->toTime(dateString, format); } else { V4THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format"); } } else { - tm = r->d()->locale.toTime(dateString, enumFormat); + tm = r->d()->locale->toTime(dateString, enumFormat); } QDateTime dt; @@ -323,16 +323,16 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleDateString(QV4::CallConte if (ctx->argc() == 3) { if (ctx->args()[2].isString()) { QString format = ctx->args()[2].stringValue()->toQString(); - dt = r->d()->locale.toDate(dateString, format); + dt = r->d()->locale->toDate(dateString, format); } else if (ctx->args()[2].isNumber()) { quint32 intFormat = ctx->args()[2].toNumber(); QLocale::FormatType format = QLocale::FormatType(intFormat); - dt = r->d()->locale.toDate(dateString, format); + dt = r->d()->locale->toDate(dateString, format); } else { V4THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format"); } } else { - dt = r->d()->locale.toDate(dateString, enumFormat); + dt = r->d()->locale->toDate(dateString, enumFormat); } return QV4::Encode(engine->newDateObject(QDateTime(dt))); @@ -393,7 +393,7 @@ QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(QV4::CallContext * prec = ctx->args()[2].toInt32(); } - return ctx->d()->engine->newString(r->d()->locale.toString(number, (char)format, prec))->asReturnedValue(); + return ctx->d()->engine->newString(r->d()->locale->toString(number, (char)format, prec))->asReturnedValue(); } QV4::ReturnedValue QQmlNumberExtension::method_toLocaleCurrencyString(QV4::CallContext *ctx) @@ -423,7 +423,7 @@ QV4::ReturnedValue QQmlNumberExtension::method_toLocaleCurrencyString(QV4::CallC symbol = ctx->args()[1].toQStringNoThrow(); } - return ctx->d()->engine->newString(r->d()->locale.toCurrencyString(number, symbol))->asReturnedValue(); + return ctx->d()->engine->newString(r->d()->locale->toCurrencyString(number, symbol))->asReturnedValue(); } QV4::ReturnedValue QQmlNumberExtension::method_fromLocaleString(QV4::CallContext *ctx) @@ -441,7 +441,7 @@ QV4::ReturnedValue QQmlNumberExtension::method_fromLocaleString(QV4::CallContext V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments"); GET_LOCALE_DATA_RESOURCE(ctx->args()[0]); - locale = r->d()->locale; + locale = *r->d()->locale; numberIdx = 1; } @@ -813,7 +813,7 @@ QV4::ReturnedValue QQmlLocale::wrap(ExecutionEngine *v4, const QLocale &locale) QV4::Scope scope(v4); QV4LocaleDataDeletable *d = localeV4Data(scope.engine); QV4::Scoped<QQmlLocaleData> wrapper(scope, v4->memoryManager->allocObject<QQmlLocaleData>()); - wrapper->d()->locale = locale; + *wrapper->d()->locale = locale; QV4::ScopedObject p(scope, d->prototype.value()); wrapper->setPrototype(p); return wrapper.asReturnedValue(); diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h index 652a3ca0d4..275f58db7d 100644 --- a/src/qml/qml/qqmllocale_p.h +++ b/src/qml/qml/qqmllocale_p.h @@ -143,8 +143,12 @@ namespace QV4 { namespace Heap { struct QQmlLocaleData : Object { - inline QQmlLocaleData() {} - QLocale locale; + inline void init() { locale = new QLocale; } + void destroy() { + delete locale; + Object::destroy(); + } + QLocale *locale; }; } @@ -161,7 +165,7 @@ struct QQmlLocaleData : public QV4::Object ctx->engine()->throwTypeError(); return 0; } - return &thisObject->d()->locale; + return thisObject->d()->locale; } static QV4::ReturnedValue method_currencySymbol(QV4::CallContext *ctx); diff --git a/src/qml/qml/qqmlloggingcategory.cpp b/src/qml/qml/qqmlloggingcategory.cpp new file mode 100644 index 0000000000..fd8fb477c7 --- /dev/null +++ b/src/qml/qml/qqmlloggingcategory.cpp @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlloggingcategory_p.h" + +#include <QtQml/qqmlinfo.h> + +/*! + \qmltype LoggingCategory + \ingroup qml-utility-elements + \inqmlmodule QtQml + \brief Defines a logging category in QML + \since 5.8 + + A logging category can be passed to console.log() and friends as the first argument. + If supplied to to the logger the LoggingCategory's name will be used as Logging Category + otherwise the default logging category will be used. + + \qml + import QtQuick 2.8 + + Item { + LoggingCategory { + id: category + name: "com.qt.category" + } + + Component.onCompleted: { + console.log(category, "message"); + } + } + \endqml + + \note As the creation of objects is expensive, it is encouraged to put the needed + LoggingCategory definitions into a singleton and import this where needed. + + \sa QLoggingCategory +*/ + +/*! + \qmlproperty string QtQml::LoggingCategory::name + + Holds the name of the logging category. + + \note This property needs to be set when declaring the LoggingCategory + and cannot be changed later. + + \sa QLoggingCategory::categoryName() +*/ + +QQmlLoggingCategory::QQmlLoggingCategory(QObject *parent) + : QObject(parent) + , m_initialized(false) +{ +} + +QQmlLoggingCategory::~QQmlLoggingCategory() +{ +} + +QString QQmlLoggingCategory::name() const +{ + return QString::fromUtf8(m_name); +} + +QLoggingCategory *QQmlLoggingCategory::category() const +{ + return m_category.data(); +} + +void QQmlLoggingCategory::classBegin() +{ +} + +void QQmlLoggingCategory::componentComplete() +{ + m_initialized = true; + if (m_name.isNull()) + qmlInfo(this) << QString(QLatin1String("Declaring the name of the LoggingCategory is mandatory and cannot be changed later !")); +} + +void QQmlLoggingCategory::setName(const QString &name) +{ + if (m_initialized) { + qmlInfo(this) << QString(QLatin1String("The name of a LoggingCategory cannot be changed after the Item is created")); + return; + } + + m_name = name.toUtf8(); + QScopedPointer<QLoggingCategory> category(new QLoggingCategory(m_name.constData())); + m_category.swap(category); +} diff --git a/src/qml/qml/ftw/qdeletewatcher_p.h b/src/qml/qml/qqmlloggingcategory_p.h index d4c0c6dfb2..2b7f2f5b53 100644 --- a/src/qml/qml/ftw/qdeletewatcher_p.h +++ b/src/qml/qml/qqmlloggingcategory_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef QDELETEWATCHER_P_H -#define QDELETEWATCHER_P_H +#ifndef QQMLLOGGINGCATEGORY_P_H +#define QQMLLOGGINGCATEGORY_P_H // // W A R N I N G @@ -51,61 +51,39 @@ // We mean it. // -#include <QtCore/qglobal.h> +#include <QtCore/qobject.h> +#include <QtCore/qstring.h> +#include <QtCore/qloggingcategory.h> + +#include <QtQml/qqmlparserstatus.h> QT_BEGIN_NAMESPACE -class QDeleteWatchable +class QQmlLoggingCategory : public QObject, public QQmlParserStatus { -public: - inline QDeleteWatchable(); - inline ~QDeleteWatchable(); -private: - friend class QDeleteWatcher; - bool *_w; -}; + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) -class QDeleteWatcher { -public: - inline QDeleteWatcher(QDeleteWatchable *data); - inline ~QDeleteWatcher(); - inline bool wasDeleted() const; -private: - void *operator new(size_t); - bool *_w; - bool _s; - QDeleteWatchable *m_d; -}; + Q_PROPERTY(QString name READ name WRITE setName) -QDeleteWatchable::QDeleteWatchable() -: _w(0) -{ -} +public: + QQmlLoggingCategory(QObject *parent = 0); + virtual ~QQmlLoggingCategory(); -QDeleteWatchable::~QDeleteWatchable() -{ - if (_w) *_w = true; -} + QString name() const; + void setName(const QString &name); -QDeleteWatcher::QDeleteWatcher(QDeleteWatchable *data) -: _s(false), m_d(data) -{ - if (!m_d->_w) - m_d->_w = &_s; - _w = m_d->_w; -} + QLoggingCategory *category() const; -QDeleteWatcher::~QDeleteWatcher() -{ - if (false == *_w && &_s == m_d->_w) - m_d->_w = 0; -} + void classBegin() override; + void componentComplete() override; -bool QDeleteWatcher::wasDeleted() const -{ - return *_w; -} +private: + QByteArray m_name; + QScopedPointer<QLoggingCategory> m_category; + bool m_initialized; +}; QT_END_NAMESPACE -#endif // QDELETEWATCHER_P_H +#endif // QQMLLOGGINGCATEGORY_H diff --git a/src/qml/qml/qqmlmemoryprofiler.cpp b/src/qml/qml/qqmlmemoryprofiler.cpp deleted file mode 100644 index d9e121bb1b..0000000000 --- a/src/qml/qml/qqmlmemoryprofiler.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlmemoryprofiler_p.h" -#include <QUrl> - -QT_BEGIN_NAMESPACE - -enum LibraryState -{ - Unloaded, - Failed, - Loaded -}; - -static LibraryState state = Unloaded; - -typedef void (qmlmemprofile_stats)(int *allocCount, int *bytesAllocated); -typedef void (qmlmemprofile_clear)(); -typedef void (qmlmemprofile_enable)(); -typedef void (qmlmemprofile_disable)(); -typedef void (qmlmemprofile_push_location)(const char *filename, int lineNumber); -typedef void (qmlmemprofile_pop_location)(); -typedef void (qmlmemprofile_save)(const char *filename); -typedef int (qmlmemprofile_is_enabled)(); - -static qmlmemprofile_stats *memprofile_stats; -static qmlmemprofile_clear *memprofile_clear; -static qmlmemprofile_enable *memprofile_enable; -static qmlmemprofile_disable *memprofile_disable; -static qmlmemprofile_push_location *memprofile_push_location; -static qmlmemprofile_pop_location *memprofile_pop_location; -static qmlmemprofile_save *memprofile_save; -static qmlmemprofile_is_enabled *memprofile_is_enabled; - -#ifndef QT_NO_LIBRARY -extern QFunctionPointer qt_linux_find_symbol_sys(const char *symbol); -#endif - -static bool openLibrary() -{ -#if defined(Q_OS_LINUX) && !defined(QT_NO_LIBRARY) - if (state == Unloaded) { - memprofile_stats = (qmlmemprofile_stats *) qt_linux_find_symbol_sys("qmlmemprofile_stats"); - memprofile_clear = (qmlmemprofile_clear *) qt_linux_find_symbol_sys("qmlmemprofile_clear"); - memprofile_enable = (qmlmemprofile_enable *) qt_linux_find_symbol_sys("qmlmemprofile_enable"); - memprofile_disable = (qmlmemprofile_disable *) qt_linux_find_symbol_sys("qmlmemprofile_disable"); - memprofile_push_location = (qmlmemprofile_push_location *) qt_linux_find_symbol_sys("qmlmemprofile_push_location"); - memprofile_pop_location = (qmlmemprofile_pop_location *) qt_linux_find_symbol_sys("qmlmemprofile_pop_location"); - memprofile_save = (qmlmemprofile_save *) qt_linux_find_symbol_sys("qmlmemprofile_save"); - memprofile_is_enabled = (qmlmemprofile_is_enabled *) qt_linux_find_symbol_sys("qmlmemprofile_is_enabled"); - - if (memprofile_stats && memprofile_clear && memprofile_enable && memprofile_disable && - memprofile_push_location && memprofile_pop_location && memprofile_save && memprofile_is_enabled) - state = Loaded; - else - state = Failed; - } -#endif // Q_OS_LINUX - - return state == Loaded; -} - -QQmlMemoryScope::QQmlMemoryScope(const QUrl &url) : pushed(false) -{ - if (openLibrary() && memprofile_is_enabled()) { - memprofile_push_location(url.path().toUtf8().constData(), 0); - pushed = true; - } -} - -QQmlMemoryScope::QQmlMemoryScope(const char *string) : pushed(false) -{ - if (openLibrary() && memprofile_is_enabled()) { - memprofile_push_location(string, 0); - pushed = true; - } -} - -QQmlMemoryScope::~QQmlMemoryScope() -{ - if (pushed) - memprofile_pop_location(); -} - -bool QQmlMemoryProfiler::isEnabled() -{ - if (openLibrary()) - return memprofile_is_enabled(); - - return false; -} - -void QQmlMemoryProfiler::enable() -{ - if (openLibrary()) - memprofile_enable(); -} - -void QQmlMemoryProfiler::disable() -{ - if (openLibrary()) - memprofile_disable(); -} - -void QQmlMemoryProfiler::clear() -{ - if (openLibrary()) - memprofile_clear(); -} - -void QQmlMemoryProfiler::stats(int *allocCount, int *bytesAllocated) -{ - if (openLibrary()) - memprofile_stats(allocCount, bytesAllocated); -} - -void QQmlMemoryProfiler::save(const char *filename) -{ - if (openLibrary()) - memprofile_save(filename); -} - -QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 7b129e2b57..ce0f4b798a 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -44,7 +44,6 @@ #include <private/qqmlcustomparser_p.h> #include <private/qhashedstring_p.h> #include <private/qqmlimport_p.h> -#include <private/qqmlcompiler_p.h> #include <QtCore/qdebug.h> #include <QtCore/qstringlist.h> @@ -493,8 +492,8 @@ QQmlType *QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const QQmlRefPointer<QQmlTypeData> td(engine->typeLoader.getType(sourceUrl()), QQmlRefPointer<QQmlTypeData>::Adopt); if (td.isNull() || !td->isComplete()) return 0; - QQmlCompiledData *cd = td->compiledData(); - const QMetaObject *mo = cd->rootPropertyCache->firstCppMetaObject(); + QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit(); + const QMetaObject *mo = compilationUnit->rootPropertyCache()->firstCppMetaObject(); return QQmlMetaType::qmlType(mo); } @@ -635,7 +634,7 @@ void QQmlTypePrivate::init() const QMetaObject *mmo = builder.toMetaObject(); mmo->d.superdata = baseMetaObject; if (!metaObjects.isEmpty()) - metaObjects.last().metaObject->d.superdata = mmo; + metaObjects.constLast().metaObject->d.superdata = mmo; QQmlProxyMetaObject::ProxyData data = { mmo, t->d->extraData.cd->extFunc, 0, 0 }; metaObjects << data; } @@ -657,7 +656,7 @@ void QQmlTypePrivate::init() const if (metaObjects.isEmpty()) mo = baseMetaObject; else - mo = metaObjects.first().metaObject; + mo = metaObjects.constFirst().metaObject; for (int ii = 0; !containsRevisionedAttributes && ii < mo->propertyCount(); ++ii) { if (isPropertyRevisioned(mo, ii)) @@ -852,7 +851,7 @@ const QMetaObject *QQmlType::metaObject() const if (d->metaObjects.isEmpty()) return d->baseMetaObject; else - return d->metaObjects.first().metaObject; + return d->metaObjects.constFirst().metaObject; } @@ -1862,7 +1861,7 @@ QQmlType *QQmlMetaType::qmlTypeFromIndex(int idx) if (idx < 0 || idx >= data->types.count()) return 0; - return data->types[idx]; + return data->types.at(idx); } /*! @@ -1914,14 +1913,11 @@ QList<QQmlType*> QQmlMetaType::qmlSingletonTypes() QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - QList<QQmlType*> alltypes = data->nameToType.values(); QList<QQmlType*> retn; - foreach (QQmlType* t, alltypes) { - if (t->isSingleton()) { - retn.append(t); - } + for (const auto type : qAsConst(data->nameToType)) { + if (type->isSingleton()) + retn.append(type); } - return retn; } @@ -1929,9 +1925,9 @@ const QQmlPrivate::CachedQmlUnit *QQmlMetaType::findCachedCompilationUnit(const { QMutexLocker lock(metaTypeDataLock()); QQmlMetaTypeData *data = metaTypeData(); - for (QVector<QQmlPrivate::QmlUnitCacheLookupFunction>::ConstIterator it = data->lookupCachedQmlUnit.constBegin(), end = data->lookupCachedQmlUnit.constEnd(); - it != end; ++it) { - if (const QQmlPrivate::CachedQmlUnit *unit = (*it)(uri)) + + for (const auto lookup : qAsConst(data->lookupCachedQmlUnit)) { + if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri)) return unit; } return 0; @@ -1961,8 +1957,7 @@ QString QQmlMetaType::prettyTypeName(const QObject *object) marker = typeName.indexOf(QLatin1String("_QML_")); if (marker != -1) { - typeName = typeName.left(marker); - typeName += QLatin1Char('*'); + typeName = typeName.left(marker) + QLatin1Char('*'); type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1())); if (type) { typeName = type->qmlTypeName(); diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp index f9fea0279e..1680253d73 100644 --- a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp +++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp @@ -41,6 +41,8 @@ QT_BEGIN_NAMESPACE +#if QT_CONFIG(qml_network) + /*! \class QQmlNetworkAccessManagerFactory \since 5.0 @@ -101,4 +103,6 @@ QQmlNetworkAccessManagerFactory::~QQmlNetworkAccessManagerFactory() implementation of this method is reentrant. */ +#endif // qml_network + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.h b/src/qml/qml/qqmlnetworkaccessmanagerfactory.h index 8e3b94fad3..57dec1da29 100644 --- a/src/qml/qml/qqmlnetworkaccessmanagerfactory.h +++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.h @@ -45,6 +45,7 @@ QT_BEGIN_NAMESPACE +#if QT_CONFIG(qml_network) class QNetworkAccessManager; class Q_QML_EXPORT QQmlNetworkAccessManagerFactory @@ -55,6 +56,8 @@ public: }; +#endif // qml_network + QT_END_NAMESPACE #endif // QQMLNETWORKACCESSMANAGERFACTORY_H diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 19e259207c..2218f277d6 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -69,12 +69,11 @@ struct ActiveOCRestorer }; } -QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlContextData *creationContext, void *activeVMEDataForRootContext) +QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlContextData *creationContext, void *activeVMEDataForRootContext) : phase(Startup) - , compiledData(compiledData) - , resolvedTypes(compiledData->resolvedTypes) - , propertyCaches(compiledData->propertyCaches) - , vmeMetaObjectData(compiledData->metaObjects) + , compilationUnit(compilationUnit) + , resolvedTypes(compilationUnit->resolvedTypes) + , propertyCaches(&compilationUnit->propertyCaches) , sharedState(new QQmlObjectCreatorSharedState) , topLevelCreator(true) , activeVMEDataForRootContext(activeVMEDataForRootContext) @@ -82,24 +81,26 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile init(parentContext); sharedState->componentAttached = 0; - sharedState->allCreatedBindings.allocate(compiledData->totalBindingsCount); - sharedState->allParserStatusCallbacks.allocate(compiledData->totalParserStatusCount); - sharedState->allCreatedObjects.allocate(compiledData->totalObjectCount); + sharedState->allCreatedBindings.allocate(compilationUnit->totalBindingsCount); + sharedState->allParserStatusCallbacks.allocate(compilationUnit->totalParserStatusCount); + sharedState->allCreatedObjects.allocate(compilationUnit->totalObjectCount); sharedState->allJavaScriptObjects = 0; sharedState->creationContext = creationContext; sharedState->rootContext = 0; - QQmlProfiler *profiler = QQmlEnginePrivate::get(engine)->profiler; - Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler, - sharedState->profiler.init(profiler, compiledData->totalParserStatusCount)); + if (auto profiler = QQmlEnginePrivate::get(engine)->profiler) { + Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler, + sharedState->profiler.init(profiler, compilationUnit->totalParserStatusCount)); + } else { + Q_UNUSED(profiler); + } } -QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlObjectCreatorSharedState *inheritedSharedState) +QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState) : phase(Startup) - , compiledData(compiledData) - , resolvedTypes(compiledData->resolvedTypes) - , propertyCaches(compiledData->propertyCaches) - , vmeMetaObjectData(compiledData->metaObjects) + , compilationUnit(compilationUnit) + , resolvedTypes(compilationUnit->resolvedTypes) + , propertyCaches(&compilationUnit->propertyCaches) , sharedState(inheritedSharedState) , topLevelCreator(false) , activeVMEDataForRootContext(0) @@ -113,10 +114,10 @@ void QQmlObjectCreator::init(QQmlContextData *providedParentContext) engine = parentContext->engine; v4 = QV8Engine::getV4(engine); - if (!compiledData->isInitialized()) - compiledData->initialize(engine); + if (compilationUnit && !compilationUnit->engine) + compilationUnit->linkToEngine(v4); - qmlUnit = compiledData->compilationUnit->data; + qmlUnit = compilationUnit->data; context = 0; _qobject = 0; _scopeObject = 0; @@ -160,19 +161,16 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI int objectToCreate; if (subComponentIndex == -1) { - objectIndexToId = compiledData->objectIndexToIdForRoot; objectToCreate = qmlUnit->indexOfRootObject; } else { - objectIndexToId = compiledData->objectIndexToIdPerComponent[subComponentIndex]; const QV4::CompiledData::Object *compObj = qmlUnit->objectAt(subComponentIndex); objectToCreate = compObj->bindingTable()->value.objectIndex; } context = new QQmlContextData; context->isInternal = true; - context->imports = compiledData->importCache; - context->imports->addref(); - context->typeCompilationUnit = compiledData->compilationUnit; + context->imports = compilationUnit->importCache; + context->initFromTypeCompilationUnit(compilationUnit, subComponentIndex); context->setParent(parentContext); if (!sharedState->rootContext) { @@ -185,16 +183,14 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI Q_ASSERT(sharedState->allJavaScriptObjects || topLevelCreator); if (topLevelCreator) - sharedState->allJavaScriptObjects = scope.alloc(compiledData->totalObjectCount); + sharedState->allJavaScriptObjects = scope.alloc(compilationUnit->totalObjectCount); - context->setIdPropertyData(objectIndexToId); - - if (subComponentIndex == -1 && compiledData->scripts.count()) { - QV4::ScopedObject scripts(scope, v4->newArrayObject(compiledData->scripts.count())); + if (subComponentIndex == -1 && compilationUnit->dependentScripts.count()) { + QV4::ScopedObject scripts(scope, v4->newArrayObject(compilationUnit->dependentScripts.count())); context->importedScripts.set(v4, scripts); QV4::ScopedValue v(scope); - for (int i = 0; i < compiledData->scripts.count(); ++i) { - QQmlScriptData *s = compiledData->scripts.at(i); + for (int i = 0; i < compilationUnit->dependentScripts.count(); ++i) { + QQmlScriptData *s = compilationUnit->dependentScripts.at(i); scripts->putIndexed(i, (v = s->scriptValueForContext(context))); } } else if (sharedState->creationContext) { @@ -205,10 +201,10 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI if (instance) { QQmlData *ddata = QQmlData::get(instance); Q_ASSERT(ddata); - if (ddata->compiledData) - ddata->compiledData->release(); - ddata->compiledData = compiledData; - ddata->compiledData->addref(); + if (ddata->compilationUnit) + ddata->compilationUnit->release(); + ddata->compilationUnit = compilationUnit; + ddata->compilationUnit->addref(); } if (topLevelCreator) @@ -242,7 +238,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) Q_ASSERT(topLevelCreator); Q_ASSERT(!sharedState->allJavaScriptObjects); - sharedState->allJavaScriptObjects = valueScope.alloc(compiledData->totalObjectCount); + sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount); QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc(1)); @@ -261,11 +257,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) qSwap(_bindingTarget, bindingTarget); qSwap(_vmeMetaObject, vmeMetaObject); - QBitArray bindingSkipList = compiledData->deferredBindingsPerObject.value(_compiledObjectIndex); - for (int i = 0; i < bindingSkipList.count(); ++i) - bindingSkipList.setBit(i, !bindingSkipList.testBit(i)); - - setupBindings(bindingSkipList); + setupBindings(/*applyDeferredBindings=*/true); qSwap(_vmeMetaObject, vmeMetaObject); qSwap(_bindingTarget, bindingTarget); @@ -285,14 +277,10 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance) void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) { - QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor | - QQmlPropertyPrivate::RemoveBindingOnAliasWrite; - int propertyWriteStatus = -1; - void *argv[] = { 0, 0, &propertyWriteStatus, &propertyWriteFlags }; - + QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor | QQmlPropertyData::RemoveBindingOnAliasWrite; QV4::Scope scope(v4); - int propertyType = property->propType; + int propertyType = property->propType(); if (property->isEnum()) { if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum) { @@ -313,39 +301,35 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const double n = binding->valueAsNumber(); if (double(int(n)) == n) { if (property->isVarProperty()) { - _vmeMetaObject->setVMEProperty(property->coreIndex, QV4::Primitive::fromInt32(int(n))); + _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Primitive::fromInt32(int(n))); } else { int i = int(n); QVariant value(i); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } } else { if (property->isVarProperty()) { - _vmeMetaObject->setVMEProperty(property->coreIndex, QV4::Primitive::fromDouble(n)); + _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Primitive::fromDouble(n)); } else { QVariant value(n); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } } } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) { if (property->isVarProperty()) { - _vmeMetaObject->setVMEProperty(property->coreIndex, QV4::Primitive::fromBoolean(binding->valueAsBoolean())); + _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Primitive::fromBoolean(binding->valueAsBoolean())); } else { QVariant value(binding->valueAsBoolean()); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } } else { QString stringValue = binding->valueAsString(qmlUnit); if (property->isVarProperty()) { QV4::ScopedString s(scope, v4->newString(stringValue)); - _vmeMetaObject->setVMEProperty(property->coreIndex, s); + _vmeMetaObject->setVMEProperty(property->coreIndex(), s); } else { QVariant value = QQmlStringConverters::variantFromString(stringValue); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } } } @@ -353,22 +337,19 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const case QVariant::String: { Q_ASSERT(binding->evaluatesToString()); QString value = binding->valueAsString(qmlUnit); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::StringList: { Q_ASSERT(binding->evaluatesToString()); QStringList value(binding->valueAsString(qmlUnit)); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::ByteArray: { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String); QByteArray value(binding->valueAsString(qmlUnit).toUtf8()); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Url: { @@ -376,20 +357,18 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QString string = binding->valueAsString(qmlUnit); // Encoded dir-separators defeat QUrl processing - decode them first string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive); - QUrl value = string.isEmpty() ? QUrl() : compiledData->url().resolved(QUrl(string)); + QUrl value = string.isEmpty() ? QUrl() : compilationUnit->url().resolved(QUrl(string)); // Apply URL interceptor if (engine->urlInterceptor()) value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::UInt: { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number); double d = binding->valueAsNumber(); uint value = uint(d); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); break; } break; @@ -397,23 +376,20 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number); double d = binding->valueAsNumber(); int value = int(d); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); break; } break; case QMetaType::Float: { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number); float value = float(binding->valueAsNumber()); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Double: { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number); double value = binding->valueAsNumber(); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Color: { @@ -421,9 +397,8 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const uint colorValue = QQmlStringConverters::rgbaFromString(binding->valueAsString(qmlUnit), &ok); Q_ASSERT(ok); struct { void *data[4]; } buffer; - if (QQml_valueTypeProvider()->storeValueType(property->propType, &colorValue, &buffer, sizeof(buffer))) { - argv[0] = reinterpret_cast<void *>(&buffer); - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + if (QQml_valueTypeProvider()->storeValueType(property->propType(), &colorValue, &buffer, sizeof(buffer))) { + property->writeProperty(_qobject, &buffer, propertyWriteFlags); } } break; @@ -432,16 +407,14 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const bool ok = false; QDate value = QQmlStringConverters::dateFromString(binding->valueAsString(qmlUnit), &ok); Q_ASSERT(ok); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Time: { bool ok = false; QTime value = QQmlStringConverters::timeFromString(binding->valueAsString(qmlUnit), &ok); Q_ASSERT(ok); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::DateTime: { @@ -454,8 +427,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const value = QDateTime(QDate::fromJulianDay(date), QTime::fromMSecsSinceStartOfDay(msecsSinceStartOfDay)); } Q_ASSERT(ok); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } break; #endif // QT_NO_DATESTRING @@ -463,55 +435,48 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const bool ok = false; QPoint value = QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok).toPoint(); Q_ASSERT(ok); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::PointF: { bool ok = false; QPointF value = QQmlStringConverters::pointFFromString(binding->valueAsString(qmlUnit), &ok); Q_ASSERT(ok); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Size: { bool ok = false; QSize value = QQmlStringConverters::sizeFFromString(binding->valueAsString(qmlUnit), &ok).toSize(); Q_ASSERT(ok); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::SizeF: { bool ok = false; QSizeF value = QQmlStringConverters::sizeFFromString(binding->valueAsString(qmlUnit), &ok); Q_ASSERT(ok); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Rect: { bool ok = false; QRect value = QQmlStringConverters::rectFFromString(binding->valueAsString(qmlUnit), &ok).toRect(); Q_ASSERT(ok); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::RectF: { bool ok = false; QRectF value = QQmlStringConverters::rectFFromString(binding->valueAsString(qmlUnit), &ok); Q_ASSERT(ok); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Bool: { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean); bool value = binding->valueAsBoolean(); - argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Vector2D: { @@ -522,8 +487,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const bool ok = QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(qmlUnit), &vec, sizeof(vec)); Q_ASSERT(ok); Q_UNUSED(ok); - argv[0] = reinterpret_cast<void *>(&vec); - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &vec, propertyWriteFlags); } break; case QVariant::Vector3D: { @@ -535,8 +499,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const bool ok = QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(qmlUnit), &vec, sizeof(vec)); Q_ASSERT(ok); Q_UNUSED(ok); - argv[0] = reinterpret_cast<void *>(&vec); - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &vec, propertyWriteFlags); } break; case QVariant::Vector4D: { @@ -549,8 +512,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const bool ok = QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(qmlUnit), &vec, sizeof(vec)); Q_ASSERT(ok); Q_UNUSED(ok); - argv[0] = reinterpret_cast<void *>(&vec); - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &vec, propertyWriteFlags); } break; case QVariant::Quaternion: { @@ -563,8 +525,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const bool ok = QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(qmlUnit), &vec, sizeof(vec)); Q_ASSERT(ok); Q_UNUSED(ok); - argv[0] = reinterpret_cast<void *>(&vec); - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &vec, propertyWriteFlags); } break; case QVariant::RegExp: @@ -572,45 +533,40 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const break; default: { // generate single literal value assignment to a list property if required - if (property->propType == qMetaTypeId<QList<qreal> >()) { + if (property->propType() == qMetaTypeId<QList<qreal> >()) { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number); QList<qreal> value; value.append(binding->valueAsNumber()); - argv[0] = reinterpret_cast<void *>(&value); - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); break; - } else if (property->propType == qMetaTypeId<QList<int> >()) { + } else if (property->propType() == qMetaTypeId<QList<int> >()) { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Number); double n = binding->valueAsNumber(); QList<int> value; value.append(int(n)); - argv[0] = reinterpret_cast<void *>(&value); - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); break; - } else if (property->propType == qMetaTypeId<QList<bool> >()) { + } else if (property->propType() == qMetaTypeId<QList<bool> >()) { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Boolean); QList<bool> value; value.append(binding->valueAsBoolean()); - argv[0] = reinterpret_cast<void *>(&value); - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); break; - } else if (property->propType == qMetaTypeId<QList<QUrl> >()) { + } else if (property->propType() == qMetaTypeId<QList<QUrl> >()) { Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String); QString urlString = binding->valueAsString(qmlUnit); - QUrl u = urlString.isEmpty() ? QUrl() : compiledData->url().resolved(QUrl(urlString)); + QUrl u = urlString.isEmpty() ? QUrl() : compilationUnit->url().resolved(QUrl(urlString)); QList<QUrl> value; value.append(u); - argv[0] = reinterpret_cast<void *>(&value); - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); break; - } else if (property->propType == qMetaTypeId<QList<QString> >()) { + } else if (property->propType() == qMetaTypeId<QList<QString> >()) { Q_ASSERT(binding->evaluatesToString()); QList<QString> value; value.append(binding->valueAsString(qmlUnit)); - argv[0] = reinterpret_cast<void *>(&value); - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); break; - } else if (property->propType == qMetaTypeId<QJSValue>()) { + } else if (property->propType() == qMetaTypeId<QJSValue>()) { QJSValue value; if (binding->type == QV4::CompiledData::Binding::Type_Boolean) { value = QJSValue(binding->valueAsBoolean()); @@ -623,25 +579,23 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const } else { value = QJSValue(binding->valueAsString(qmlUnit)); } - argv[0] = reinterpret_cast<void *>(&value); - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, &value, propertyWriteFlags); break; } // otherwise, try a custom type assignment QString stringValue = binding->valueAsString(qmlUnit); - QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType); + QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType()); Q_ASSERT(converter); QVariant value = (*converter)(stringValue); - QMetaProperty metaProperty = _qobject->metaObject()->property(property->coreIndex); - if (value.isNull() || ((int)metaProperty.type() != property->propType && metaProperty.userType() != property->propType)) { + QMetaProperty metaProperty = _qobject->metaObject()->property(property->coreIndex()); + if (value.isNull() || ((int)metaProperty.type() != property->propType() && metaProperty.userType() != property->propType())) { recordError(binding->location, tr("Cannot assign value %1 to property %2").arg(stringValue).arg(QString::fromUtf8(metaProperty.name()))); break; } - argv[0] = value.data(); - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, value.data(), propertyWriteFlags); } break; } @@ -658,22 +612,22 @@ static QQmlType *qmlTypeForObject(QObject *object) return type; } -void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) +void QQmlObjectCreator::setupBindings(bool applyDeferredBindings) { QQmlListProperty<void> savedList; qSwap(_currentList, savedList); - const QV4::CompiledData::BindingPropertyData &propertyData = compiledData->compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex); + const QV4::CompiledData::BindingPropertyData &propertyData = compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex); - if (_compiledObject->idIndex) { + if (_compiledObject->idNameIndex) { const QQmlPropertyData *idProperty = propertyData.last(); Q_ASSERT(!idProperty || !idProperty->isValid() || idProperty->name(_qobject) == QLatin1String("id")); - if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType == QMetaType::QString) { + if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType() == QMetaType::QString) { QV4::CompiledData::Binding idBinding; idBinding.propertyNameIndex = 0; // Not used idBinding.flags = 0; idBinding.type = QV4::CompiledData::Binding::Type_String; - idBinding.stringIndex = _compiledObject->idIndex; + idBinding.stringIndex = _compiledObject->idNameIndex; idBinding.location = _compiledObject->location; // ### setPropertyValue(idProperty, &idBinding); } @@ -681,23 +635,23 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) // ### this is best done through type-compile-time binding skip lists. if (_valueTypeProperty) { - QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(_bindingTarget, _valueTypeProperty->coreIndex); + QQmlAbstractBinding *binding = QQmlPropertyPrivate::binding(_bindingTarget, QQmlPropertyIndex(_valueTypeProperty->coreIndex())); if (binding && !binding->isValueTypeProxy()) { - QQmlPropertyPrivate::removeBinding(_bindingTarget, _valueTypeProperty->coreIndex); + QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(_valueTypeProperty->coreIndex())); } else if (binding) { QQmlValueTypeProxyBinding *proxy = static_cast<QQmlValueTypeProxyBinding *>(binding); if (qmlTypeForObject(_bindingTarget)) { quint32 bindingSkipList = 0; - QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultProperty != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty(); + QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultPropertyOrAlias != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty(); const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable(); for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) { QQmlPropertyData *property = binding->propertyNameIndex != 0 ? _propertyCache->property(stringAt(binding->propertyNameIndex), _qobject, context) : defaultProperty; if (property) - bindingSkipList |= (1 << property->coreIndex); + bindingSkipList |= (1 << property->coreIndex()); } proxy->removeBindings(bindingSkipList); @@ -709,16 +663,24 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable(); for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) { - if (static_cast<int>(i) < bindingsToSkip.size() && bindingsToSkip.testBit(i)) + if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding) continue; + if (binding->flags & QV4::CompiledData::Binding::IsDeferredBinding) { + if (!applyDeferredBindings) + continue; + } else { + if (applyDeferredBindings) + continue; + } + const QQmlPropertyData *property = propertyData.at(i); if (property && property->isQList()) { - if (property->coreIndex != currentListPropertyIndex) { + if (property->coreIndex() != currentListPropertyIndex) { void *argv[1] = { (void*)&_currentList }; - QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex, argv); - currentListPropertyIndex = property->coreIndex; + QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex(), argv); + currentListPropertyIndex = property->coreIndex(); } } else if (_currentList.object) { _currentList = QQmlListProperty<void>(); @@ -736,7 +698,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con { if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { Q_ASSERT(stringAt(qmlUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty()); - QQmlCompiledData::TypeReference *tr = resolvedTypes.value(binding->propertyNameIndex); + QV4::CompiledData::ResolvedTypeReference *tr = resolvedTypes.value(binding->propertyNameIndex); Q_ASSERT(tr); QQmlType *attachedType = tr->type; if (!attachedType) { @@ -754,7 +716,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con } // ### resolve this at compile time - if (property && property->propType == qMetaTypeId<QQmlScriptString>()) { + if (property && property->propType() == qMetaTypeId<QQmlScriptString>()) { QQmlScriptString ss(binding->valueAsScriptString(qmlUnit), context->asQQmlContext(), _scopeObject); ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid; ss.d.data()->lineNumber = binding->location.line; @@ -763,11 +725,11 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con ss.d.data()->isNumberLiteral = binding->type == QV4::CompiledData::Binding::Type_Number; ss.d.data()->numberValue = binding->valueAsNumber(); - QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor | - QQmlPropertyPrivate::RemoveBindingOnAliasWrite; + QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor | + QQmlPropertyData::RemoveBindingOnAliasWrite; int propertyWriteStatus = -1; void *argv[] = { &ss, 0, &propertyWriteStatus, &propertyWriteFlags }; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv); return true; } @@ -790,20 +752,20 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con const QQmlPropertyData *valueTypeProperty = 0; QObject *bindingTarget = _bindingTarget; - if (QQmlValueTypeFactory::isValueType(property->propType)) { - valueType = QQmlValueTypeFactory::valueType(property->propType); + if (QQmlValueTypeFactory::isValueType(property->propType())) { + valueType = QQmlValueTypeFactory::valueType(property->propType()); if (!valueType) { recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex))); return false; } - valueType->read(_qobject, property->coreIndex); + valueType->read(_qobject, property->coreIndex()); groupObject = valueType; valueTypeProperty = property; } else { void *argv[1] = { &groupObject }; - QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex, argv); + QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property->coreIndex(), argv); if (!groupObject) { recordError(binding->location, tr("Cannot set properties on %1 as it is null").arg(stringAt(binding->propertyNameIndex))); return false; @@ -816,48 +778,49 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con return false; if (valueType) - valueType->write(_qobject, property->coreIndex, QQmlPropertyPrivate::BypassInterceptor); + valueType->write(_qobject, property->coreIndex(), QQmlPropertyData::BypassInterceptor); return true; } } - if (_ddata->hasBindingBit(property->coreIndex) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) + if (_ddata->hasBindingBit(property->coreIndex()) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment) && !_valueTypeProperty) - QQmlPropertyPrivate::removeBinding(_bindingTarget, property->coreIndex); + QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(property->coreIndex())); if (binding->type == QV4::CompiledData::Binding::Type_Script) { - QV4::Function *runtimeFunction = compiledData->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; + QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]; QV4::Scope scope(v4); QV4::ScopedContext qmlContext(scope, currentQmlContext()); QV4::ScopedFunctionObject function(scope, QV4::FunctionObject::createScriptFunction(qmlContext, runtimeFunction, /*createProto*/ false)); if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression) { - int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex); + int signalIndex = _propertyCache->methodIndexToSignalIndex(property->coreIndex()); QQmlBoundSignal *bs = new QQmlBoundSignal(_bindingTarget, signalIndex, _scopeObject, engine); QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(_bindingTarget, signalIndex, context, _scopeObject, function); bs->takeExpression(expr); } else { - QQmlBinding *qmlBinding = new QQmlBinding(function, _scopeObject, context); - // When writing bindings to grouped properties implemented as value types, // such as point.x: { someExpression; }, then the binding is installed on // the point property (_qobjectForBindings) and after evaluating the expression, // the result is written to a value type virtual property, that contains the sub-index // of the "x" property. - QQmlPropertyData targetCorePropertyData = *property; - if (_valueTypeProperty) - targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine); + QQmlBinding *qmlBinding; + if (_valueTypeProperty) { + qmlBinding = QQmlBinding::create(_valueTypeProperty, function, _scopeObject, context); + qmlBinding->setTarget(_bindingTarget, *_valueTypeProperty, property); + } else { + qmlBinding = QQmlBinding::create(property, function, _scopeObject, context); + qmlBinding->setTarget(_bindingTarget, *property, nullptr); + } sharedState->allCreatedBindings.push(QQmlAbstractBinding::Ptr(qmlBinding)); - qmlBinding->setTarget(_bindingTarget, targetCorePropertyData); - - if (targetCorePropertyData.isAlias()) { + if (property->isAlias()) { QQmlPropertyPrivate::setBinding(qmlBinding, QQmlPropertyPrivate::DontEnable); } else { qmlBinding->addToObject(); @@ -865,7 +828,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con if (!_valueTypeProperty) { QQmlData *targetDeclarativeData = QQmlData::get(_bindingTarget); Q_ASSERT(targetDeclarativeData); - targetDeclarativeData->setPendingBindingBit(_bindingTarget, property->coreIndex); + targetDeclarativeData->setPendingBindingBit(_bindingTarget, property->coreIndex()); } } } @@ -878,15 +841,16 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con QQmlType *type = qmlTypeForObject(createdSubObject); Q_ASSERT(type); - QQmlPropertyData targetCorePropertyData = *property; - if (_valueTypeProperty) - targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine); - int valueSourceCast = type->propertyValueSourceCast(); if (valueSourceCast != -1) { QQmlPropertyValueSource *vs = reinterpret_cast<QQmlPropertyValueSource *>(reinterpret_cast<char *>(createdSubObject) + valueSourceCast); QObject *target = createdSubObject->parent(); - vs->setTarget(QQmlPropertyPrivate::restore(target, targetCorePropertyData, context)); + QQmlProperty prop; + if (_valueTypeProperty) + prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, property, context); + else + prop = QQmlPropertyPrivate::restore(target, *property, nullptr, context); + vs->setTarget(prop); return true; } int valueInterceptorCast = type->propertyValueInterceptorCast(); @@ -894,25 +858,36 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con QQmlPropertyValueInterceptor *vi = reinterpret_cast<QQmlPropertyValueInterceptor *>(reinterpret_cast<char *>(createdSubObject) + valueInterceptorCast); QObject *target = createdSubObject->parent(); - if (targetCorePropertyData.isAlias()) { - int propIndex; - QQmlPropertyPrivate::findAliasTarget(target, targetCorePropertyData.coreIndex, &target, &propIndex); + QQmlPropertyIndex propertyIndex; + if (property->isAlias()) { + QQmlPropertyIndex originalIndex(property->coreIndex(), _valueTypeProperty ? _valueTypeProperty->coreIndex() : -1); + QQmlPropertyIndex propIndex; + QQmlPropertyPrivate::findAliasTarget(target, originalIndex, &target, &propIndex); QQmlData *data = QQmlData::get(target); if (!data || !data->propertyCache) { qWarning() << "can't resolve property alias for 'on' assignment"; return false; } - targetCorePropertyData = *data->propertyCache->property(propIndex); - } - QQmlProperty prop = - QQmlPropertyPrivate::restore(target, targetCorePropertyData, context); + // we can't have aliasses on subproperties of value types, so: + QQmlPropertyData targetPropertyData = *data->propertyCache->property(propIndex.coreIndex()); + auto prop = QQmlPropertyPrivate::restore(target, targetPropertyData, nullptr, context); + vi->setTarget(prop); + propertyIndex = QQmlPropertyPrivate::propertyIndex(prop); + } else { + QQmlProperty prop; + if (_valueTypeProperty) + prop = QQmlPropertyPrivate::restore(target, *_valueTypeProperty, property, context); + else + prop = QQmlPropertyPrivate::restore(target, *property, nullptr, context); + vi->setTarget(prop); + propertyIndex = QQmlPropertyPrivate::propertyIndex(prop); + } - vi->setTarget(prop); QQmlInterceptorMetaObject *mo = QQmlInterceptorMetaObject::get(target); if (!mo) mo = new QQmlInterceptorMetaObject(target, QQmlData::get(target)->propertyCache); - mo->registerInterceptor(prop.index(), QQmlPropertyPrivate::valueTypeCoreIndex(prop), vi); + mo->registerInterceptor(propertyIndex, vi); return true; } return false; @@ -930,7 +905,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con return false; } - QMetaMethod signalMethod = _qobject->metaObject()->method(property->coreIndex); + QMetaMethod signalMethod = _qobject->metaObject()->method(property->coreIndex()); if (!QMetaObject::checkConnectArgs(signalMethod, method)) { recordError(binding->valueLocation, tr("Cannot connect mismatched signal/slot %1 %vs. %2") @@ -939,33 +914,33 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con return false; } - QQmlPropertyPrivate::connect(_qobject, property->coreIndex, createdSubObject, method.methodIndex()); + QQmlPropertyPrivate::connect(_qobject, property->coreIndex(), createdSubObject, method.methodIndex()); return true; } - QQmlPropertyPrivate::WriteFlags propertyWriteFlags = QQmlPropertyPrivate::BypassInterceptor | - QQmlPropertyPrivate::RemoveBindingOnAliasWrite; + QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor | + QQmlPropertyData::RemoveBindingOnAliasWrite; int propertyWriteStatus = -1; void *argv[] = { 0, 0, &propertyWriteStatus, &propertyWriteFlags }; - if (const char *iid = QQmlMetaType::interfaceIId(property->propType)) { + if (const char *iid = QQmlMetaType::interfaceIId(property->propType())) { void *ptr = createdSubObject->qt_metacast(iid); if (ptr) { argv[0] = &ptr; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv); } else { recordError(binding->location, tr("Cannot assign object to interface property")); return false; } - } else if (property->propType == QMetaType::QVariant) { + } else if (property->propType() == QMetaType::QVariant) { if (property->isVarProperty()) { QV4::Scope scope(v4); QV4::ScopedValue wrappedObject(scope, QV4::QObjectWrapper::wrap(QV8Engine::getV4(engine), createdSubObject)); - _vmeMetaObject->setVMEProperty(property->coreIndex, wrappedObject); + _vmeMetaObject->setVMEProperty(property->coreIndex(), wrappedObject); } else { QVariant value = QVariant::fromValue(createdSubObject); argv[0] = &value; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv); } } else if (property->isQList()) { Q_ASSERT(_currentList.object); @@ -973,7 +948,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con void *itemToAdd = createdSubObject; const char *iid = 0; - int listItemType = QQmlEnginePrivate::get(engine)->listType(property->propType); + int listItemType = QQmlEnginePrivate::get(engine)->listType(property->propType()); if (listItemType != -1) iid = QQmlMetaType::interfaceIId(listItemType); if (iid) @@ -989,7 +964,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con } else { // pointer compatibility was tested in QQmlPropertyValidator at type compile time argv[0] = &createdSubObject; - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex(), argv); } return true; } @@ -1009,9 +984,9 @@ void QQmlObjectCreator::setupFunctions() QV4::ScopedValue function(scope); QV4::ScopedContext qmlContext(scope, currentQmlContext()); - const quint32 *functionIdx = _compiledObject->functionOffsetTable(); + const QV4::CompiledData::LEUInt32 *functionIdx = _compiledObject->functionOffsetTable(); for (quint32 i = 0; i < _compiledObject->nFunctions; ++i, ++functionIdx) { - QV4::Function *runtimeFunction = compiledData->compilationUnit->runtimeFunctions[*functionIdx]; + QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[*functionIdx]; const QString name = runtimeFunction->name()->toQString(); QQmlPropertyData *property = _propertyCache->property(name, _qobject, context); @@ -1019,25 +994,24 @@ void QQmlObjectCreator::setupFunctions() continue; function = QV4::FunctionObject::createScriptFunction(qmlContext, runtimeFunction); - _vmeMetaObject->setVmeMethod(property->coreIndex, function); + _vmeMetaObject->setVmeMethod(property->coreIndex(), function); } } void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location, const QString &description) { QQmlError error; - error.setUrl(compiledData->url()); + error.setUrl(compilationUnit->url()); error.setLine(location.line); error.setColumn(location.column); error.setDescription(description); errors << error; } -void QQmlObjectCreator::registerObjectWithContextById(int objectIndex, QObject *instance) const +void QQmlObjectCreator::registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const { - QHash<int, int>::ConstIterator idEntry = objectIndexToId.find(objectIndex); - if (idEntry != objectIndexToId.constEnd()) - context->setIdProperty(idEntry.value(), instance); + if (object->id >= 0) + context->setIdProperty(object->id, instance); } QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext() @@ -1050,7 +1024,9 @@ QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext() QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject) { - QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler); + const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); + QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler, obj); + ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine)); bool isComponent = false; @@ -1060,29 +1036,36 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo QQmlParserStatus *parserStatus = 0; bool installPropertyCache = true; - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); - if (compiledData->isComponent(index)) { + if (obj->flags & QV4::CompiledData::Object::IsComponent) { isComponent = true; - QQmlComponent *component = new QQmlComponent(engine, compiledData, index, parent); + QQmlComponent *component = new QQmlComponent(engine, compilationUnit, index, parent); Q_QML_OC_PROFILE(sharedState->profiler, profiler.update( - compiledData, obj, QStringLiteral("<component>"), context->url())); + compilationUnit, obj, QStringLiteral("<component>"), context->url())); QQmlComponentPrivate::get(component)->creationContext = context; instance = component; ddata = QQmlData::get(instance, /*create*/true); } else { - QQmlCompiledData::TypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); + QV4::CompiledData::ResolvedTypeReference *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); installPropertyCache = !typeRef->isFullyDynamicType; QQmlType *type = typeRef->type; if (type) { Q_QML_OC_PROFILE(sharedState->profiler, profiler.update( - compiledData, obj, type->qmlTypeName(), context->url())); - instance = type->create(); + compilationUnit, obj, type->qmlTypeName(), context->url())); + + void *ddataMemory = 0; + type->create(&instance, &ddataMemory, sizeof(QQmlData)); if (!instance) { recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex))); return 0; } + { + QQmlData *ddata = new (ddataMemory) QQmlData; + ddata->ownMemory = false; + QObjectPrivate::get(instance)->declarativeData = ddata; + } + const int parserStatusCast = type->parserStatusCast(); if (parserStatusCast != -1) parserStatus = reinterpret_cast<QQmlParserStatus*>(reinterpret_cast<char *>(instance) + parserStatusCast); @@ -1097,17 +1080,17 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo sharedState->allCreatedObjects.push(instance); } else { - Q_ASSERT(typeRef->component); + Q_ASSERT(typeRef->compilationUnit); Q_QML_OC_PROFILE(sharedState->profiler, profiler.update( - compiledData, obj, typeRef->component->fileName(), + compilationUnit, obj, typeRef->compilationUnit->fileName(), context->url())); - if (typeRef->component->compilationUnit->data->isSingleton()) + if (typeRef->compilationUnit->data->isSingleton()) { recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex))); return 0; } - QQmlObjectCreator subCreator(context, typeRef->component, sharedState.data()); + QQmlObjectCreator subCreator(context, typeRef->compilationUnit, sharedState.data()); instance = subCreator.create(); if (!instance) { errors += subCreator.errors; @@ -1153,32 +1136,30 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo if (isContextObject) context->contextObject = instance; - QBitArray bindingsToSkip; - if (customParser) { - QHash<int, QBitArray>::ConstIterator customParserBindings = compiledData->customParserBindings.constFind(index); - if (customParserBindings != compiledData->customParserBindings.constEnd()) { - customParser->engine = QQmlEnginePrivate::get(engine); - customParser->imports = compiledData->importCache; - - QList<const QV4::CompiledData::Binding *> bindings; - const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); - for (int i = 0; i < customParserBindings->count(); ++i) - if (customParserBindings->testBit(i)) - bindings << obj->bindingTable() + i; - customParser->applyBindings(instance, compiledData, bindings); - - customParser->engine = 0; - customParser->imports = (QQmlTypeNameCache*)0; - bindingsToSkip = *customParserBindings; + if (customParser && obj->flags & QV4::CompiledData::Object::HasCustomParserBindings) { + customParser->engine = QQmlEnginePrivate::get(engine); + customParser->imports = compilationUnit->importCache; + + QList<const QV4::CompiledData::Binding *> bindings; + const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index); + const QV4::CompiledData::Binding *binding = obj->bindingTable(); + for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) { + if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding) { + bindings << binding; + } } + customParser->applyBindings(instance, compilationUnit, bindings); + + customParser->engine = 0; + customParser->imports = (QQmlTypeNameCache*)0; } if (isComponent) { - registerObjectWithContextById(index, instance); + registerObjectWithContextById(obj, instance); return instance; } - QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(index); + QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches->at(index); Q_ASSERT(!cache.isNull()); if (installPropertyCache) { if (ddata->propertyCache) @@ -1199,7 +1180,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo qSwap(_qmlContext, qmlContext); - bool result = populateInstance(index, instance, /*binding target*/instance, /*value type property*/0, bindingsToSkip); + bool result = populateInstance(index, instance, /*binding target*/instance, /*value type property*/0); qSwap(_qmlContext, qmlContext); qSwap(_scopeObject, scopeObject); @@ -1223,9 +1204,9 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru continue; QQmlData *data = QQmlData::get(b->targetObject()); Q_ASSERT(data); - data->clearPendingBindingBit(b->targetPropertyIndex()); - b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor | - QQmlPropertyPrivate::DontRemoveBinding); + data->clearPendingBindingBit(b->targetPropertyIndex().coreIndex()); + b->setEnabled(true, QQmlPropertyData::BypassInterceptor | + QQmlPropertyData::DontRemoveBinding); if (watcher.hasRecursed() || interrupt.shouldInterrupt()) return 0; @@ -1294,7 +1275,7 @@ void QQmlObjectCreator::clear() phase = Done; } -bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty, const QBitArray &bindingsToSkip) +bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty) { QQmlData *declarativeData = QQmlData::get(instance, /*create*/true); @@ -1309,14 +1290,13 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * QV4::Scope valueScope(v4); QV4::ScopedValue scopeObjectProtector(valueScope); - QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches.at(_compiledObjectIndex); + QQmlRefPointer<QQmlPropertyCache> cache = propertyCaches->at(_compiledObjectIndex); QQmlVMEMetaObject *vmeMetaObject = 0; - const QByteArray data = vmeMetaObjectData.value(_compiledObjectIndex); - if (!data.isEmpty()) { + if (propertyCaches->needsVMEMetaObject(_compiledObjectIndex)) { Q_ASSERT(!cache.isNull()); // install on _object - vmeMetaObject = new QQmlVMEMetaObject(_qobject, cache, reinterpret_cast<const QQmlVMEMetaData*>(data.constData())); + vmeMetaObject = new QQmlVMEMetaObject(_qobject, cache, compilationUnit, _compiledObjectIndex); if (_ddata->propertyCache) _ddata->propertyCache->release(); _ddata->propertyCache = cache; @@ -1326,33 +1306,23 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * vmeMetaObject = QQmlVMEMetaObject::get(_qobject); } - registerObjectWithContextById(_compiledObjectIndex, _qobject); + registerObjectWithContextById(_compiledObject, _qobject); qSwap(_propertyCache, cache); qSwap(_vmeMetaObject, vmeMetaObject); - QBitArray bindingSkipList = bindingsToSkip; - { - QHash<int, QBitArray>::ConstIterator deferredBindings = compiledData->deferredBindingsPerObject.constFind(_compiledObjectIndex); - if (deferredBindings != compiledData->deferredBindingsPerObject.constEnd()) { - if (bindingSkipList.isEmpty()) - bindingSkipList.resize(deferredBindings->count()); - - for (int i = 0; i < deferredBindings->count(); ++i) - if (deferredBindings->testBit(i)) - bindingSkipList.setBit(i); - QQmlData::DeferredData *deferData = new QQmlData::DeferredData; - deferData->deferredIdx = _compiledObjectIndex; - deferData->compiledData = compiledData; - deferData->compiledData->addref(); - deferData->context = context; - _ddata->deferredData = deferData; - } + if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings) { + QQmlData::DeferredData *deferData = new QQmlData::DeferredData; + deferData->deferredIdx = _compiledObjectIndex; + deferData->compilationUnit = compilationUnit; + deferData->compilationUnit->addref(); + deferData->context = context; + _ddata->deferredData = deferData; } if (_compiledObject->nFunctions > 0) setupFunctions(); - setupBindings(bindingSkipList); + setupBindings(); qSwap(_vmeMetaObject, vmeMetaObject); qSwap(_bindingTarget, bindingTarget); diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 3d743954c9..e3312f9df5 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -53,7 +53,6 @@ #include <private/qqmlimport_p.h> #include <private/qqmltypenamecache_p.h> #include <private/qv4compileddata_p.h> -#include <private/qqmlcompiler_p.h> #include <private/qqmltypecompiler_p.h> #include <private/qfinitestack_p.h> #include <private/qrecursionwatcher_p.h> @@ -66,7 +65,6 @@ QT_BEGIN_NAMESPACE class QQmlAbstractBinding; struct QQmlTypeCompiler; class QQmlInstantiationInterrupt; -struct QQmlVmeProfiler; struct QQmlObjectCreatorSharedState : public QSharedData { @@ -86,7 +84,7 @@ class QQmlObjectCreator { Q_DECLARE_TR_FUNCTIONS(QQmlObjectCreator) public: - QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlContextData *creationContext, void *activeVMEDataForRootContext = 0); + QQmlObjectCreator(QQmlContextData *parentContext, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlContextData *creationContext, void *activeVMEDataForRootContext = 0); ~QQmlObjectCreator(); QObject *create(int subComponentIndex = -1, QObject *parent = 0, QQmlInstantiationInterrupt *interrupt = 0); @@ -104,17 +102,16 @@ public: QFiniteStack<QPointer<QObject> > &allCreatedObjects() const { return sharedState->allCreatedObjects; } private: - QQmlObjectCreator(QQmlContextData *contextData, QQmlCompiledData *compiledData, QQmlObjectCreatorSharedState *inheritedSharedState); + QQmlObjectCreator(QQmlContextData *contextData, QV4::CompiledData::CompilationUnit *compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState); void init(QQmlContextData *parentContext); QObject *createInstance(int index, QObject *parent = 0, bool isContextObject = false); bool populateInstance(int index, QObject *instance, - QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty, - const QBitArray &bindingsToSkip = QBitArray()); + QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty); - void setupBindings(const QBitArray &bindingsToSkip); + void setupBindings(bool applyDeferredBindings = false); bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding); void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding); void setupFunctions(); @@ -122,7 +119,7 @@ private: QString stringAt(int idx) const { return qmlUnit->stringAt(idx); } void recordError(const QV4::CompiledData::Location &location, const QString &description); - void registerObjectWithContextById(int objectIndex, QObject *instance) const; + void registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const; QV4::Heap::QmlContext *currentQmlContext(); @@ -137,14 +134,12 @@ private: QQmlEngine *engine; QV4::ExecutionEngine *v4; - QQmlCompiledData *compiledData; + QV4::CompiledData::CompilationUnit *compilationUnit; const QV4::CompiledData::Unit *qmlUnit; QQmlGuardedContextData parentContext; QQmlContextData *context; - const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes; - const QVector<QQmlPropertyCache *> &propertyCaches; - const QVector<QByteArray> &vmeMetaObjectData; - QHash<int, int> objectIndexToId; + const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypes; + const QQmlPropertyCacheVector *propertyCaches; QExplicitlySharedDataPointer<QQmlObjectCreatorSharedState> sharedState; bool topLevelCreator; void *activeVMEDataForRootContext; diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp index 0fd9e63bde..49f02476a2 100644 --- a/src/qml/qml/qqmlopenmetaobject.cpp +++ b/src/qml/qml/qqmlopenmetaobject.cpp @@ -278,7 +278,7 @@ int QQmlOpenMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void * propertyRead(propId); *reinterpret_cast<QVariant *>(a[0]) = d->getData(propId); } else if (c == QMetaObject::WriteProperty) { - if (propId >= d->data.count() || d->data[propId].first != *reinterpret_cast<QVariant *>(a[0])) { + if (propId >= d->data.count() || d->data.at(propId).first != *reinterpret_cast<QVariant *>(a[0])) { propertyWrite(propId); QPair<QVariant, bool> &prop = d->getDataRef(propId); prop.first = propertyWriteValue(propId, *reinterpret_cast<QVariant *>(a[0])); diff --git a/src/qml/qml/qqmlplatform.cpp b/src/qml/qml/qqmlplatform.cpp index 37d8d4748a..a47a0ab4a4 100644 --- a/src/qml/qml/qqmlplatform.cpp +++ b/src/qml/qml/qqmlplatform.cpp @@ -67,8 +67,6 @@ QString QQmlPlatform::os() return QStringLiteral("tvos"); #elif defined(Q_OS_MAC) return QStringLiteral("osx"); -#elif defined(Q_OS_WINCE) - return QStringLiteral("wince"); #elif defined(Q_OS_WINPHONE) return QStringLiteral("winphone"); #elif defined(Q_OS_WINRT) diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 0ef0a5b16e..c62fef7c3d 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -42,6 +42,7 @@ #include "qqml.h" #include "qqmlbinding_p.h" +#include "qqmlboundsignal_p.h" #include "qqmlcontext.h" #include "qqmlcontext_p.h" #include "qqmlboundsignal_p.h" @@ -50,7 +51,6 @@ #include "qqmldata_p.h" #include "qqmlstringconverters_p.h" #include "qqmllist_p.h" -#include "qqmlcompiler_p.h" #include "qqmlvmemetaobject_p.h" #include "qqmlexpression_p.h" #include "qqmlvaluetypeproxybinding_p.h" @@ -291,9 +291,9 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) if (property->isFunction()) return; // Not an object property - if (ii == (path.count() - 2) && QQmlValueTypeFactory::isValueType(property->propType)) { + if (ii == (path.count() - 2) && QQmlValueTypeFactory::isValueType(property->propType())) { // We're now at a value type property - const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property->propType); + const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property->propType()); if (!valueTypeMetaObject) return; // Not a value type int idx = valueTypeMetaObject->indexOfProperty(path.last().toUtf8().constData()); @@ -301,24 +301,21 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) QMetaProperty vtProp = valueTypeMetaObject->property(idx); - Q_ASSERT(QQmlPropertyData::flagsForProperty(vtProp) <= QQmlPropertyData::ValueTypeFlagMask); Q_ASSERT(vtProp.userType() <= 0x0000FFFF); Q_ASSERT(idx <= 0x0000FFFF); object = currentObject; core = *property; - core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual); - core.valueTypeFlags = QQmlPropertyData::flagsForProperty(vtProp); - core.valueTypePropType = vtProp.userType(); - core.valueTypeCoreIndex = idx; + valueTypeData.setFlags(QQmlPropertyData::flagsForProperty(vtProp)); + valueTypeData.setPropType(vtProp.userType()); + valueTypeData.setCoreIndex(idx); return; } else { if (!property->isQObject()) return; // Not an object property - void *args[] = { ¤tObject, 0 }; - QMetaObject::metacall(currentObject, QMetaObject::ReadProperty, property->coreIndex, args); + property->readProperty(currentObject, ¤tObject); if (!currentObject) return; // No value } @@ -358,9 +355,9 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) while (d && d->isFunction()) d = ddata->propertyCache->overrideData(d); - if (d && d->notifyIndex != -1) { + if (d && d->notifyIndex() != -1) { object = currentObject; - core = *ddata->propertyCache->signal(d->notifyIndex); + core = *ddata->propertyCache->signal(d->notifyIndex()); return; } } @@ -397,7 +394,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) int QQmlPropertyPrivate::signalIndex() const { Q_ASSERT(type() == QQmlProperty::SignalProperty); - QMetaMethod m = object->metaObject()->method(core.coreIndex); + QMetaMethod m = object->metaObject()->method(core.coreIndex()); return QMetaObjectPrivate::signalIndex(m); } @@ -473,11 +470,11 @@ const char *QQmlProperty::propertyTypeName() const if (!d) return 0; if (d->isValueType()) { - const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(d->core.propType); + const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(d->core.propType()); Q_ASSERT(valueTypeMetaObject); - return valueTypeMetaObject->property(d->core.valueTypeCoreIndex).typeName(); + return valueTypeMetaObject->property(d->valueTypeData.coreIndex()).typeName(); } else if (d->object && type() & Property && d->core.isValid()) { - return d->object->metaObject()->property(d->core.coreIndex).typeName(); + return d->object->metaObject()->property(d->core.coreIndex()).typeName(); } else { return 0; } @@ -494,11 +491,8 @@ bool QQmlProperty::operator==(const QQmlProperty &other) const // category is intentially omitted here as it is generated // from the other members return d->object == other.d->object && - d->core.coreIndex == other.d->core.coreIndex && - d->core.isValueTypeVirtual() == other.d->core.isValueTypeVirtual() && - (!d->core.isValueTypeVirtual() || - (d->core.valueTypeCoreIndex == other.d->core.valueTypeCoreIndex && - d->core.valueTypePropType == other.d->core.valueTypePropType)); + d->core.coreIndex() == other.d->core.coreIndex() && + d->valueTypeData.coreIndex() == other.d->valueTypeData.coreIndex(); } /*! @@ -512,16 +506,16 @@ int QQmlProperty::propertyType() const bool QQmlPropertyPrivate::isValueType() const { - return core.isValueTypeVirtual(); + return valueTypeData.isValid(); } int QQmlPropertyPrivate::propertyType() const { uint type = this->type(); if (isValueType()) { - return core.valueTypePropType; + return valueTypeData.propType(); } else if (type & QQmlProperty::Property) { - return core.propType; + return core.propType(); } else { return QVariant::Invalid; } @@ -610,7 +604,7 @@ bool QQmlProperty::isDesignable() const if (!d) return false; if (type() & Property && d->core.isValid() && d->object) - return d->object->metaObject()->property(d->core.coreIndex).isDesignable(); + return d->object->metaObject()->property(d->core.coreIndex()).isDesignable(); else return false; } @@ -650,15 +644,11 @@ QString QQmlProperty::name() const // ### if (!d->object) { } else if (d->isValueType()) { - QString rv = d->core.name(d->object) + QLatin1Char('.'); - - const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(d->core.propType); + const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(d->core.propType()); Q_ASSERT(valueTypeMetaObject); - const char *vtName = valueTypeMetaObject->property(d->core.valueTypeCoreIndex).name(); - rv += QString::fromUtf8(vtName); - - d->nameCache = rv; + const char *vtName = valueTypeMetaObject->property(d->valueTypeData.coreIndex()).name(); + d->nameCache = d->core.name(d->object) + QLatin1Char('.') + QString::fromUtf8(vtName); } else if (type() & SignalProperty) { QString name = QLatin1String("on") + d->core.name(d->object); name[2] = name.at(2).toUpper(); @@ -681,7 +671,7 @@ QMetaProperty QQmlProperty::property() const if (!d) return QMetaProperty(); if (type() & Property && d->core.isValid() && d->object) - return d->object->metaObject()->property(d->core.coreIndex); + return d->object->metaObject()->property(d->core.coreIndex()); else return QMetaProperty(); } @@ -695,7 +685,7 @@ QMetaMethod QQmlProperty::method() const if (!d) return QMetaMethod(); if (type() & SignalProperty && d->object) - return d->object->metaObject()->method(d->core.coreIndex); + return d->object->metaObject()->method(d->core.coreIndex()); else return QMetaMethod(); } @@ -710,7 +700,8 @@ QQmlPropertyPrivate::binding(const QQmlProperty &that) if (!that.d || !that.isProperty() || !that.d->object) return 0; - return binding(that.d->object, that.d->core.encodedIndex()); + QQmlPropertyIndex thatIndex(that.d->core.coreIndex(), that.d->valueTypeData.coreIndex()); + return binding(that.d->object, thatIndex); } /*! @@ -742,10 +733,10 @@ QQmlPropertyPrivate::setBinding(const QQmlProperty &that, QQmlAbstractBinding *n setBinding(newBinding); } -static void removeOldBinding(QObject *object, int index, QQmlPropertyPrivate::BindingFlags flags = QQmlPropertyPrivate::None) +static void removeOldBinding(QObject *object, QQmlPropertyIndex index, QQmlPropertyPrivate::BindingFlags flags = QQmlPropertyPrivate::None) { - int coreIndex; - int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex); + int coreIndex = index.coreIndex(); + int valueTypeIndex = index.valueTypeIndex(); QQmlData *data = QQmlData::get(object, false); @@ -755,7 +746,8 @@ static void removeOldBinding(QObject *object, int index, QQmlPropertyPrivate::Bi QQmlAbstractBinding::Ptr oldBinding; oldBinding = data->bindings; - while (oldBinding && oldBinding->targetPropertyIndex() != coreIndex) + while (oldBinding && (oldBinding->targetPropertyIndex().coreIndex() != coreIndex || + oldBinding->targetPropertyIndex().hasValueTypeIndex())) oldBinding = oldBinding->nextBinding(); if (!oldBinding) @@ -777,12 +769,12 @@ void QQmlPropertyPrivate::removeBinding(QQmlAbstractBinding *b) removeBinding(b->targetObject(), b->targetPropertyIndex()); } -void QQmlPropertyPrivate::removeBinding(QObject *o, int index) +void QQmlPropertyPrivate::removeBinding(QObject *o, QQmlPropertyIndex index) { Q_ASSERT(o); QObject *target; - int targetIndex; + QQmlPropertyIndex targetIndex; findAliasTarget(o, index, &target, &targetIndex); removeOldBinding(target, targetIndex); } @@ -792,11 +784,11 @@ void QQmlPropertyPrivate::removeBinding(const QQmlProperty &that) if (!that.d || !that.isProperty() || !that.d->object) return; - removeBinding(that.d->object, that.d->core.encodedIndex()); + removeBinding(that.d->object, that.d->encodedIndex()); } QQmlAbstractBinding * -QQmlPropertyPrivate::binding(QObject *object, int index) +QQmlPropertyPrivate::binding(QObject *object, QQmlPropertyIndex index) { QQmlData *data = QQmlData::get(object); if (!data) @@ -804,19 +796,19 @@ QQmlPropertyPrivate::binding(QObject *object, int index) findAliasTarget(object, index, &object, &index); - int coreIndex; - int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex); + const int coreIndex = index.coreIndex(); + const int valueTypeIndex = index.valueTypeIndex(); if (!data->hasBindingBit(coreIndex)) return 0; QQmlAbstractBinding *binding = data->bindings; - while (binding && binding->targetPropertyIndex() != coreIndex) + while (binding && (binding->targetPropertyIndex().coreIndex() != coreIndex || + binding->targetPropertyIndex().hasValueTypeIndex())) binding = binding->nextBinding(); if (binding && valueTypeIndex != -1) { if (binding->isValueTypeProxy()) { - int index = QQmlPropertyData::encodeValueTypePropertyIndex(coreIndex, valueTypeIndex); binding = static_cast<QQmlValueTypeProxyBinding *>(binding)->binding(index); } } @@ -824,13 +816,14 @@ QQmlPropertyPrivate::binding(QObject *object, int index) return binding; } -void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex, - QObject **targetObject, int *targetBindingIndex) +void QQmlPropertyPrivate::findAliasTarget(QObject *object, QQmlPropertyIndex bindingIndex, + QObject **targetObject, + QQmlPropertyIndex *targetBindingIndex) { QQmlData *data = QQmlData::get(object, false); if (data) { - int coreIndex; - int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(bindingIndex, &coreIndex); + int coreIndex = bindingIndex.coreIndex(); + int valueTypeIndex = bindingIndex.valueTypeIndex(); QQmlPropertyData *propertyData = data->propertyCache?data->propertyCache->property(coreIndex):0; @@ -842,11 +835,12 @@ void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex, // This will either be a value type sub-reference or an alias to a value-type sub-reference not both Q_ASSERT(valueTypeIndex == -1 || aValueTypeIndex == -1); - int aBindingIndex = aCoreIndex; - if (aValueTypeIndex != -1) - aBindingIndex = QQmlPropertyData::encodeValueTypePropertyIndex(aBindingIndex, aValueTypeIndex); - else if (valueTypeIndex != -1) - aBindingIndex = QQmlPropertyData::encodeValueTypePropertyIndex(aBindingIndex, valueTypeIndex); + QQmlPropertyIndex aBindingIndex(aCoreIndex); + if (aValueTypeIndex != -1) { + aBindingIndex = QQmlPropertyIndex(aCoreIndex, aValueTypeIndex); + } else if (valueTypeIndex != -1) { + aBindingIndex = QQmlPropertyIndex(aCoreIndex, valueTypeIndex); + } findAliasTarget(aObject, aBindingIndex, targetObject, targetBindingIndex); return; @@ -859,16 +853,15 @@ void QQmlPropertyPrivate::findAliasTarget(QObject *object, int bindingIndex, } -void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags flags, WriteFlags writeFlags) +void QQmlPropertyPrivate::setBinding(QQmlAbstractBinding *binding, BindingFlags flags, QQmlPropertyData::WriteFlags writeFlags) { Q_ASSERT(binding); QObject *object = binding->targetObject(); - int index = binding->targetPropertyIndex(); + const QQmlPropertyIndex index = binding->targetPropertyIndex(); #ifndef QT_NO_DEBUG - int coreIndex; - QQmlPropertyData::decodeValueTypePropertyIndex(index, &coreIndex); + int coreIndex = index.coreIndex(); QQmlData *data = QQmlData::get(object, true); if (data->propertyCache) { QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex); @@ -1027,42 +1020,40 @@ QVariant QQmlPropertyPrivate::readValueProperty() { if (isValueType()) { - QQmlValueType *valueType = QQmlValueTypeFactory::valueType(core.propType); + QQmlValueType *valueType = QQmlValueTypeFactory::valueType(core.propType()); Q_ASSERT(valueType); - valueType->read(object, core.coreIndex); - return valueType->metaObject()->property(core.valueTypeCoreIndex).read(valueType); + valueType->read(object, core.coreIndex()); + return valueType->metaObject()->property(valueTypeData.coreIndex()).read(valueType); } else if (core.isQList()) { QQmlListProperty<QObject> prop; - void *args[] = { &prop, 0 }; - QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args); - return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType, engine)); + core.readProperty(object, &prop); + return QVariant::fromValue(QQmlListReferencePrivate::init(prop, core.propType(), engine)); } else if (core.isQObject()) { QObject *rv = 0; - void *args[] = { &rv, 0 }; - QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args); + core.readProperty(object, &rv); return QVariant::fromValue(rv); } else { - if (!core.propType) // Unregistered type - return object->metaObject()->property(core.coreIndex).read(object); + 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) { + if (core.propType() == QMetaType::QVariant) { args[0] = &value; } else { - value = QVariant(core.propType, (void*)0); + 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]); + core.readPropertyWithArgs(object, args); + if (core.propType() != QMetaType::QVariant && args[0] != value.data()) + return QVariant((QVariant::Type)core.propType(), args[0]); return value; } @@ -1148,40 +1139,30 @@ bool QQmlPropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, return status; } -bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, WriteFlags flags) +bool QQmlPropertyPrivate::writeValueProperty(const QVariant &value, QQmlPropertyData::WriteFlags flags) { - return writeValueProperty(object, core, value, effectiveContext(), flags); + return writeValueProperty(object, core, valueTypeData, value, effectiveContext(), flags); } bool QQmlPropertyPrivate::writeValueProperty(QObject *object, const QQmlPropertyData &core, + const QQmlPropertyData &valueTypeData, const QVariant &value, - QQmlContextData *context, WriteFlags flags) + QQmlContextData *context,QQmlPropertyData::WriteFlags flags) { // Remove any existing bindings on this property - if (!(flags & DontRemoveBinding) && object) - removeBinding(object, core.encodedIndex()); + if (!(flags & QQmlPropertyData::DontRemoveBinding) && object) + removeBinding(object, encodedIndex(core, valueTypeData)); bool rv = false; - if (core.isValueTypeVirtual()) { - - QQmlValueType *writeBack = QQmlValueTypeFactory::valueType(core.propType); - writeBack->read(object, core.coreIndex); - - QQmlPropertyData data = core; - data.setFlags(QQmlPropertyData::Flag(core.valueTypeFlags)); - data.coreIndex = core.valueTypeCoreIndex; - data.propType = core.valueTypePropType; - - rv = write(writeBack, data, value, context, flags); - - writeBack->write(object, core.coreIndex, flags); - + if (valueTypeData.isValid()) { + QQmlValueType *writeBack = QQmlValueTypeFactory::valueType(core.propType()); + writeBack->read(object, core.coreIndex()); + rv = write(writeBack, valueTypeData, value, context, flags); + writeBack->write(object, core.coreIndex(), flags); } else { - rv = write(object, core, value, context, flags); - } return rv; @@ -1190,145 +1171,151 @@ QQmlPropertyPrivate::writeValueProperty(QObject *object, bool QQmlPropertyPrivate::write(QObject *object, const QQmlPropertyData &property, const QVariant &value, QQmlContextData *context, - WriteFlags flags) + QQmlPropertyData::WriteFlags flags) { - int coreIdx = property.coreIndex; - int status = -1; //for dbus + const int propertyType = property.propType(); + const int variantType = value.userType(); if (property.isEnum()) { - QMetaProperty prop = object->metaObject()->property(property.coreIndex); + QMetaProperty prop = object->metaObject()->property(property.coreIndex()); QVariant v = value; // Enum values come through the script engine as doubles - if (value.userType() == QVariant::Double) { + if (variantType == QVariant::Double) { double integral; double fractional = std::modf(value.toDouble(), &integral); if (qFuzzyIsNull(fractional)) v.convert(QVariant::Int); } - return writeEnumProperty(prop, coreIdx, object, v, flags); + return writeEnumProperty(prop, property.coreIndex(), object, v, flags); } - int propertyType = property.propType; - int variantType = value.userType(); - QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(context); + const bool isUrl = propertyType == QVariant::Url; // handled separately + + // The cases below are in approximate order of likelyhood: + if (propertyType == variantType && !isUrl && propertyType != qMetaTypeId<QList<QUrl>>() && !property.isQList()) { + return property.writeProperty(object, const_cast<void *>(value.constData()), flags); + } else if (property.isQObject()) { + QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, variantType); + if (valMo.isNull()) + return false; + QObject *o = *static_cast<QObject *const *>(value.constData()); + QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType); - if (propertyType == QVariant::Url) { + if (o) + valMo = o; + if (QQmlMetaObject::canConvert(valMo, propMo)) { + return property.writeProperty(object, &o, flags); + } 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. + return property.writeProperty(object, &o, flags); + } else { + return false; + } + } else if (value.canConvert(propertyType) && !isUrl && variantType != QVariant::String && propertyType != qMetaTypeId<QList<QUrl>>() && !property.isQList()) { + // common cases: + switch (propertyType) { + case QMetaType::Bool: { + bool b = value.toBool(); + return property.writeProperty(object, &b, flags); + } + case QMetaType::Int: { + int i = value.toInt(); + return property.writeProperty(object, &i, flags); + } + case QMetaType::Double: { + double d = value.toDouble(); + return property.writeProperty(object, &d, flags); + } + case QMetaType::Float: { + float f = value.toFloat(); + return property.writeProperty(object, &f, flags); + } + case QMetaType::QString: { + QString s = value.toString(); + return property.writeProperty(object, &s, flags); + } + default: { // "fallback": + QVariant v = value; + v.convert(propertyType); + return property.writeProperty(object, const_cast<void *>(v.constData()), flags); + } + } + } else if (propertyType == qMetaTypeId<QVariant>()) { + return property.writeProperty(object, const_cast<QVariant *>(&value), flags); + } else if (isUrl) { QUrl u; - bool found = false; if (variantType == QVariant::Url) { u = value.toUrl(); - found = true; } else if (variantType == QVariant::ByteArray) { QString input(QString::fromUtf8(value.toByteArray())); // Encoded dir-separators defeat QUrl processing - decode them first input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive); u = QUrl(input); - found = true; } else if (variantType == QVariant::String) { QString input(value.toString()); // Encoded dir-separators defeat QUrl processing - decode them first input.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive); u = QUrl(input); - found = true; - } - - if (!found) - return false; - - if (context && u.isRelative() && !u.isEmpty()) - u = context->resolvedUrl(u); - int status = -1; - void *argv[] = { &u, 0, &status, &flags }; - QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv); - - } else if (propertyType == qMetaTypeId<QList<QUrl> >()) { - QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl> >(); - int status = -1; - void *argv[] = { &urlSeq, 0, &status, &flags }; - QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, argv); - } else if (variantType == propertyType) { - - void *a[] = { const_cast<void *>(value.constData()), 0, &status, &flags }; - QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); - - } else if (qMetaTypeId<QVariant>() == propertyType) { - - void *a[] = { const_cast<QVariant *>(&value), 0, &status, &flags }; - QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); - - } else if (property.isQObject()) { - - QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, value.userType()); - - if (valMo.isNull()) - return false; - - QObject *o = *(QObject *const *)value.constData(); - QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType); - - if (o) valMo = o; - - if (QQmlMetaObject::canConvert(valMo, propMo)) { - void *args[] = { &o, 0, &status, &flags }; - 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); } else { return false; } + if (context && u.isRelative() && !u.isEmpty()) + u = context->resolvedUrl(u); + return property.writeProperty(object, &u, flags); + } else if (propertyType == qMetaTypeId<QList<QUrl>>()) { + QList<QUrl> urlSeq = resolvedUrlSequence(value, context).value<QList<QUrl>>(); + return property.writeProperty(object, &urlSeq, flags); } else if (property.isQList()) { - QQmlMetaObject listType; if (enginePriv) { - listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType)); + listType = enginePriv->rawMetaObjectForType(enginePriv->listType(property.propType())); } else { - QQmlType *type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType)); - if (!type) return false; + QQmlType *type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType())); + if (!type) + return false; listType = type->baseMetaObject(); } - if (listType.isNull()) return false; + if (listType.isNull()) + return false; QQmlListProperty<void> prop; - void *args[] = { &prop, 0 }; - QMetaObject::metacall(object, QMetaObject::ReadProperty, coreIdx, args); + property.readProperty(object, &prop); - if (!prop.clear) return false; + if (!prop.clear) + return false; prop.clear(&prop); - if (value.userType() == qMetaTypeId<QQmlListReference>()) { + if (variantType == qMetaTypeId<QQmlListReference>()) { QQmlListReference qdlr = value.value<QQmlListReference>(); for (int ii = 0; ii < qdlr.count(); ++ii) { QObject *o = qdlr.at(ii); if (o && !QQmlMetaObject::canConvert(o, listType)) - o = 0; - prop.append(&prop, (void *)o); + o = nullptr; + prop.append(&prop, o); } - } else if (value.userType() == qMetaTypeId<QList<QObject *> >()) { + } else if (variantType == qMetaTypeId<QList<QObject *> >()) { const QList<QObject *> &list = qvariant_cast<QList<QObject *> >(value); for (int ii = 0; ii < list.count(); ++ii) { QObject *o = list.at(ii); if (o && !QQmlMetaObject::canConvert(o, listType)) - o = 0; - prop.append(&prop, (void *)o); + o = nullptr; + prop.append(&prop, o); } } else { QObject *o = enginePriv?enginePriv->toQObject(value):QQmlMetaType::toQObject(value); if (o && !QQmlMetaObject::canConvert(o, listType)) - o = 0; - prop.append(&prop, (void *)o); + o = nullptr; + prop.append(&prop, o); } - } else { Q_ASSERT(variantType != propertyType); @@ -1347,7 +1334,8 @@ bool QQmlPropertyPrivate::write(QObject *object, // successful conversion. Q_ASSERT(v.userType() == propertyType); ok = true; - } else if ((uint)propertyType >= QVariant::UserType && variantType == QVariant::String) { + } else if (static_cast<uint>(propertyType) >= QVariant::UserType && + variantType == QVariant::String) { QQmlMetaType::StringConverter con = QQmlMetaType::customStringConverter(propertyType); if (con) { v = con(value.toString()); @@ -1390,8 +1378,7 @@ bool QQmlPropertyPrivate::write(QObject *object, } if (ok) { - void *a[] = { const_cast<void *>(v.constData()), 0, &status, &flags}; - QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); + return property.writeProperty(object, const_cast<void *>(v.constData()), flags); } else { return false; } @@ -1407,10 +1394,9 @@ QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engi return metaType.metaObject(); if (engine) return engine->rawMetaObjectForType(userType); - QQmlType *type = QQmlMetaType::qmlType(userType); - if (type) + if (QQmlType *type = QQmlMetaType::qmlType(userType)) return QQmlMetaObject(type->baseMetaObject()); - return QQmlMetaObject((QObject*)0); + return QQmlMetaObject(); } /*! @@ -1484,7 +1470,7 @@ bool QQmlProperty::reset() const { if (isResettable()) { void *args[] = { 0 }; - QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args); + QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex(), args); return true; } else { return false; @@ -1492,7 +1478,7 @@ bool QQmlProperty::reset() const } bool QQmlPropertyPrivate::write(const QQmlProperty &that, - const QVariant &value, WriteFlags flags) + const QVariant &value, QQmlPropertyData::WriteFlags flags) { if (!that.d) return false; @@ -1509,7 +1495,7 @@ bool QQmlPropertyPrivate::write(const QQmlProperty &that, bool QQmlProperty::hasNotifySignal() const { if (type() & Property && d->object) { - return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal(); + return d->object->metaObject()->property(d->core.coreIndex()).hasNotifySignal(); } return false; } @@ -1539,7 +1525,7 @@ bool QQmlProperty::connectNotifySignal(QObject *dest, int method) const if (!(type() & Property) || !d->object) return false; - QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex); + QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex()); if (prop.hasNotifySignal()) { return QQmlPropertyPrivate::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection); } else { @@ -1560,7 +1546,7 @@ bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const if (!(type() & Property) || !d->object) return false; - QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex); + QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex()); if (prop.hasNotifySignal()) { QByteArray signal('2' + prop.notifySignal().methodSignature()); return QObject::connect(d->object, signal.constData(), dest, slot); @@ -1574,61 +1560,28 @@ bool QQmlProperty::connectNotifySignal(QObject *dest, const char *slot) const */ int QQmlProperty::index() const { - return d ? d->core.coreIndex : -1; -} - -int QQmlPropertyPrivate::valueTypeCoreIndex(const QQmlProperty &that) -{ - return that.d ? that.d->core.getValueTypeCoreIndex() : -1; -} - -/*! - Returns the "property index" for use in bindings. The top 16 bits are the value type - offset, and 0 otherwise. The bottom 16 bits are the regular property index. -*/ -int QQmlPropertyPrivate::bindingIndex(const QQmlProperty &that) -{ - if (!that.d) - return -1; - return bindingIndex(that.d->core); -} - -int QQmlPropertyPrivate::bindingIndex(const QQmlPropertyData &that) -{ - int rv = that.coreIndex; - if (rv != -1 && that.isValueTypeVirtual()) - rv = rv | (that.valueTypeCoreIndex << 16); - return rv; + return d ? d->core.coreIndex() : -1; } -QQmlPropertyData -QQmlPropertyPrivate::saveValueType(const QQmlPropertyData &base, - const QMetaObject *subObject, int subIndex, - QQmlEngine *) +QQmlPropertyIndex QQmlPropertyPrivate::propertyIndex(const QQmlProperty &that) { - QMetaProperty subProp = subObject->property(subIndex); - - QQmlPropertyData core = base; - core.setFlags(core.getFlags() | QQmlPropertyData::IsValueTypeVirtual); - core.valueTypeFlags = QQmlPropertyData::flagsForProperty(subProp); - core.valueTypeCoreIndex = subIndex; - core.valueTypePropType = subProp.userType(); - - return core; + return that.d ? that.d->encodedIndex() : QQmlPropertyIndex(); } QQmlProperty QQmlPropertyPrivate::restore(QObject *object, const QQmlPropertyData &data, - QQmlContextData *ctxt) + const QQmlPropertyData *valueTypeData, QQmlContextData *ctxt) { QQmlProperty prop; prop.d = new QQmlPropertyPrivate; prop.d->object = object; prop.d->context = ctxt; - prop.d->engine = ctxt?ctxt->engine:0; + prop.d->engine = ctxt ? ctxt->engine : nullptr; prop.d->core = data; + if (valueTypeData) + prop.d->valueTypeData = *valueTypeData; return prop; } diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h index 58fea9c239..2565ec0ce6 100644 --- a/src/qml/qml/qqmlproperty_p.h +++ b/src/qml/qml/qqmlproperty_p.h @@ -68,24 +68,23 @@ class QQmlJavaScriptExpression; class Q_QML_PRIVATE_EXPORT QQmlPropertyPrivate : public QQmlRefCount { public: - enum WriteFlag { - BypassInterceptor = 0x01, - DontRemoveBinding = 0x02, - RemoveBindingOnAliasWrite = 0x04 - }; - Q_DECLARE_FLAGS(WriteFlags, WriteFlag) - QQmlContextData *context; QPointer<QQmlEngine> engine; QPointer<QObject> object; QQmlPropertyData core; + QQmlPropertyData valueTypeData; bool isNameCached:1; QString nameCache; QQmlPropertyPrivate(); + QQmlPropertyIndex encodedIndex() const + { return encodedIndex(core, valueTypeData); } + static QQmlPropertyIndex encodedIndex(const QQmlPropertyData &core, const QQmlPropertyData &valueTypeData) + { return QQmlPropertyIndex(core.coreIndex(), valueTypeData.coreIndex()); } + inline QQmlContextData *effectiveContext() const; void initProperty(QObject *obj, const QString &name); @@ -97,18 +96,18 @@ public: QQmlProperty::PropertyTypeCategory propertyTypeCategory() const; QVariant readValueProperty(); - bool writeValueProperty(const QVariant &, WriteFlags); + bool writeValueProperty(const QVariant &, QQmlPropertyData::WriteFlags); static QQmlMetaObject rawMetaObjectForType(QQmlEnginePrivate *, int); static bool writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags); static bool writeValueProperty(QObject *, - const QQmlPropertyData &, + const QQmlPropertyData &, const QQmlPropertyData &valueTypeData, const QVariant &, QQmlContextData *, - WriteFlags flags = 0); + QQmlPropertyData::WriteFlags flags = 0); static bool write(QObject *, const QQmlPropertyData &, const QVariant &, - QQmlContextData *, WriteFlags flags = 0); - static void findAliasTarget(QObject *, int, QObject **, int *); + QQmlContextData *, QQmlPropertyData::WriteFlags flags = 0); + static void findAliasTarget(QObject *, QQmlPropertyIndex, QObject **, QQmlPropertyIndex *); enum BindingFlag { None = 0, @@ -116,19 +115,15 @@ public: }; Q_DECLARE_FLAGS(BindingFlags, BindingFlag) - static void setBinding(QQmlAbstractBinding *binding, BindingFlags flags = None, WriteFlags writeFlags = DontRemoveBinding); + static void setBinding(QQmlAbstractBinding *binding, BindingFlags flags = None, QQmlPropertyData::WriteFlags writeFlags = QQmlPropertyData::DontRemoveBinding); static void removeBinding(const QQmlProperty &that); - static void removeBinding(QObject *o, int index); + static void removeBinding(QObject *o, QQmlPropertyIndex index); static void removeBinding(QQmlAbstractBinding *b); - static QQmlAbstractBinding *binding(QObject *, int index); + static QQmlAbstractBinding *binding(QObject *, QQmlPropertyIndex index); - static QQmlPropertyData saveValueType(const QQmlPropertyData &, - const QMetaObject *, int, - QQmlEngine *); - static QQmlProperty restore(QObject *, - const QQmlPropertyData &, - QQmlContextData *); + static QQmlProperty restore(QObject *, const QQmlPropertyData &, const QQmlPropertyData *, + QQmlContextData *); int signalIndex() const; @@ -144,10 +139,8 @@ public: QQmlBoundSignalExpression *); static void takeSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *); - static bool write(const QQmlProperty &that, const QVariant &, WriteFlags); - static int valueTypeCoreIndex(const QQmlProperty &that); - static int bindingIndex(const QQmlProperty &that); - static int bindingIndex(const QQmlPropertyData &that); + static bool write(const QQmlProperty &that, const QVariant &, QQmlPropertyData::WriteFlags); + static QQmlPropertyIndex propertyIndex(const QQmlProperty &that); static QMetaMethod findSignalByName(const QMetaObject *mo, const QByteArray &); static bool connect(const QObject *sender, int signal_index, const QObject *receiver, int method_index, @@ -157,7 +150,6 @@ public: static QVariant resolvedUrlSequence(const QVariant &value, QQmlContextData *context); }; -Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::WriteFlags) Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyPrivate::BindingFlags) QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 9c535b8ce8..2610a807b5 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -45,12 +45,12 @@ #include <private/qv8engine_p.h> #include <private/qmetaobject_p.h> -#include <private/qqmlaccessors_p.h> #include <private/qmetaobjectbuilder_p.h> #include <private/qv4value_p.h> #include <QtCore/qdebug.h> +#include <QtCore/QCryptographicHash> #include <ctype.h> // for toupper #include <limits.h> @@ -85,51 +85,45 @@ static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p) { QQmlPropertyData::Flags flags; - if (p.isConstant()) - flags |= QQmlPropertyData::IsConstant; - if (p.isWritable()) - flags |= QQmlPropertyData::IsWritable; - if (p.isResettable()) - flags |= QQmlPropertyData::IsResettable; - if (p.isFinal()) - flags |= QQmlPropertyData::IsFinal; + flags.isConstant = p.isConstant(); + flags.isWritable = p.isWritable(); + flags.isResettable = p.isResettable(); + flags.isFinal = p.isFinal(); + if (p.isEnumType()) - flags |= QQmlPropertyData::IsEnumType; + flags.type = QQmlPropertyData::Flags::EnumType; return flags; } // Flags that do depend on the property's QMetaProperty::userType() and thus are slow to // load -static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *engine) +static void flagsForPropertyType(int propType, QQmlEngine *engine, QQmlPropertyData::Flags &flags) { Q_ASSERT(propType != -1); - QQmlPropertyData::Flags flags; - if (propType == QMetaType::QObjectStar) { - flags |= QQmlPropertyData::IsQObjectDerived; + flags.type = QQmlPropertyData::Flags::QObjectDerivedType; } else if (propType == QMetaType::QVariant) { - flags |= QQmlPropertyData::IsQVariant; - } else if (propType < (int)QVariant::UserType) { + flags.type = QQmlPropertyData::Flags::QVariantType; + } else if (propType < static_cast<int>(QVariant::UserType)) { + // nothing to do } else if (propType == qMetaTypeId<QQmlBinding *>()) { - flags |= QQmlPropertyData::IsQmlBinding; + flags.type = QQmlPropertyData::Flags::QmlBindingType; } else if (propType == qMetaTypeId<QJSValue>()) { - flags |= QQmlPropertyData::IsQJSValue; + flags.type = QQmlPropertyData::Flags::QJSValueType; } else if (propType == qMetaTypeId<QQmlV4Handle>()) { - flags |= QQmlPropertyData::IsV4Handle; + flags.type = QQmlPropertyData::Flags::V4HandleType; } else { QQmlMetaType::TypeCategory cat = engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType) : QQmlMetaType::typeCategory(propType); if (cat == QQmlMetaType::Object || QMetaType::typeFlags(propType) & QMetaType::PointerToQObject) - flags |= QQmlPropertyData::IsQObjectDerived; + flags.type = QQmlPropertyData::Flags::QObjectDerivedType; else if (cat == QQmlMetaType::List) - flags |= QQmlPropertyData::IsQList; + flags.type = QQmlPropertyData::Flags::QListType; } - - return flags; } static int metaObjectSignalCount(const QMetaObject *metaObject) @@ -143,95 +137,107 @@ static int metaObjectSignalCount(const QMetaObject *metaObject) QQmlPropertyData::Flags QQmlPropertyData::flagsForProperty(const QMetaProperty &p, QQmlEngine *engine) { - return fastFlagsForProperty(p) | flagsForPropertyType(p.userType(), engine); + auto flags = fastFlagsForProperty(p); + flagsForPropertyType(p.userType(), engine, flags); + return flags; } void QQmlPropertyData::lazyLoad(const QMetaProperty &p) { - coreIndex = p.propertyIndex(); - notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal()); + setCoreIndex(p.propertyIndex()); + setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal())); Q_ASSERT(p.revision() <= Q_INT16_MAX); - revision = p.revision(); + setRevision(p.revision()); - flags = fastFlagsForProperty(p); + setFlags(fastFlagsForProperty(p)); - int type = p.type(); + int type = static_cast<int>(p.type()); if (type == QMetaType::QObjectStar) { - propType = type; - flags |= QQmlPropertyData::IsQObjectDerived; + setPropType(type); + _flags.type = Flags::QObjectDerivedType; } else if (type == QMetaType::QVariant) { - propType = type; - flags |= QQmlPropertyData::IsQVariant; + setPropType(type); + _flags.type = Flags::QVariantType; } else if (type == QVariant::UserType || type == -1) { - propTypeName = p.typeName(); - flags |= QQmlPropertyData::NotFullyResolved; + _flags.notFullyResolved = true; } else { - propType = type; + setPropType(type); } } void QQmlPropertyData::load(const QMetaProperty &p, QQmlEngine *engine) { - propType = p.userType(); - coreIndex = p.propertyIndex(); - notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal()); - flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine); + setPropType(p.userType()); + setCoreIndex(p.propertyIndex()); + setNotifyIndex(QMetaObjectPrivate::signalIndex(p.notifySignal())); + setFlags(fastFlagsForProperty(p)); + flagsForPropertyType(propType(), engine, _flags); Q_ASSERT(p.revision() <= Q_INT16_MAX); - revision = p.revision(); + setRevision(p.revision()); } void QQmlPropertyData::load(const QMetaMethod &m) { - coreIndex = m.methodIndex(); - arguments = 0; - flags |= IsFunction; + setCoreIndex(m.methodIndex()); + setArguments(nullptr); + + setPropType(m.returnType()); + + _flags.type = Flags::FunctionType; if (m.methodType() == QMetaMethod::Signal) - flags |= IsSignal; - propType = m.returnType(); + _flags.isSignal = true; + else if (m.methodType() == QMetaMethod::Constructor) { + _flags.isConstructor = true; + setPropType(QMetaType::QObjectStar); + } if (m.parameterCount()) { - flags |= HasArguments; + _flags.hasArguments = true; if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) { - flags |= IsV4Function; + _flags.isV4Function = true; } } if (m.attributes() & QMetaMethod::Cloned) - flags |= IsCloned; + _flags.isCloned = true; Q_ASSERT(m.revision() <= Q_INT16_MAX); - revision = m.revision(); + setRevision(m.revision()); } void QQmlPropertyData::lazyLoad(const QMetaMethod &m) { - coreIndex = m.methodIndex(); - arguments = 0; - flags |= IsFunction; + setCoreIndex(m.methodIndex()); + setPropType(QMetaType::Void); + setArguments(nullptr); + _flags.type = Flags::FunctionType; if (m.methodType() == QMetaMethod::Signal) - flags |= IsSignal; - propType = QMetaType::Void; + _flags.isSignal = true; + else if (m.methodType() == QMetaMethod::Constructor) { + _flags.isConstructor = true; + setPropType(QMetaType::QObjectStar); + } const char *returnType = m.typeName(); if (!returnType) returnType = "\0"; if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) { - propTypeName = returnType; - flags |= NotFullyResolved; + _flags.notFullyResolved = true; } - if (m.parameterCount()) { - flags |= HasArguments; - if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) { - flags |= IsV4Function; + const int paramCount = m.parameterCount(); + if (paramCount) { + _flags.hasArguments = true; + if ((paramCount == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) { + _flags.isV4Function = true; } } if (m.attributes() & QMetaMethod::Cloned) - flags |= IsCloned; + _flags.isCloned = true; Q_ASSERT(m.revision() <= Q_INT16_MAX); - revision = m.revision(); + setRevision(m.revision()); } /*! @@ -249,11 +255,8 @@ QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e) Creates a new QQmlPropertyCache of \a metaObject. */ QQmlPropertyCache::QQmlPropertyCache(QV4::ExecutionEngine *e, const QMetaObject *metaObject) - : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0), - signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false), - _metaObject(0), argumentsCache(0), _jsFactoryMethodIndex(-1) + : QQmlPropertyCache(e) { - Q_ASSERT(engine); Q_ASSERT(metaObject); update(metaObject); @@ -333,14 +336,14 @@ QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(int propertyCount, int meth \a notifyIndex MUST be in the signal index range (see QObjectPrivate::signalIndex()). This is different from QMetaMethod::methodIndex(). */ -void QQmlPropertyCache::appendProperty(const QString &name, - quint32 flags, int coreIndex, int propType, int notifyIndex) +void QQmlPropertyCache::appendProperty(const QString &name, QQmlPropertyData::Flags flags, + int coreIndex, int propType, int notifyIndex) { QQmlPropertyData data; - data.propType = propType; - data.coreIndex = coreIndex; - data.notifyIndex = notifyIndex; - data.flags = flags; + data.setPropType(propType); + data.setCoreIndex(coreIndex); + data.setNotifyIndex(notifyIndex); + data.setFlags(flags); QQmlPropertyData *old = findNamedProperty(name); if (old) @@ -352,24 +355,25 @@ void QQmlPropertyCache::appendProperty(const QString &name, setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0)); } -void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int coreIndex, - const int *types, const QList<QByteArray> &names) +void QQmlPropertyCache::appendSignal(const QString &name, QQmlPropertyData::Flags flags, + int coreIndex, const int *types, + const QList<QByteArray> &names) { QQmlPropertyData data; - data.propType = QVariant::Invalid; - data.coreIndex = coreIndex; - data.flags = flags; - data.arguments = 0; + data.setPropType(QVariant::Invalid); + data.setCoreIndex(coreIndex); + data.setFlags(flags); + data.setArguments(nullptr); QQmlPropertyData handler = data; - handler.flags |= QQmlPropertyData::IsSignalHandler; + handler._flags.isSignalHandler = true; if (types) { int argumentCount = *types; QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names); ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int)); args->argumentsValid = true; - data.arguments = args; + data.setArguments(args); } QQmlPropertyData *old = findNamedProperty(name); @@ -383,28 +387,28 @@ void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int cor signalHandlerIndexCache.append(handler); QString handlerName = QLatin1String("on") + name; - handlerName[2] = handlerName[2].toUpper(); + handlerName[2] = handlerName.at(2).toUpper(); setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0)); setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != 0)); } -void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int coreIndex, - const QList<QByteArray> &names) +void QQmlPropertyCache::appendMethod(const QString &name, QQmlPropertyData::Flags flags, + int coreIndex, const QList<QByteArray> &names) { int argumentCount = names.count(); QQmlPropertyData data; - data.propType = QMetaType::QVariant; - data.coreIndex = coreIndex; + data.setPropType(QMetaType::QVariant); + data.setCoreIndex(coreIndex); QQmlPropertyCacheMethodArguments *args = createArgumentsObject(argumentCount, names); for (int ii = 0; ii < argumentCount; ++ii) args->arguments[ii + 1] = QMetaType::QVariant; args->argumentsValid = true; - data.arguments = args; + data.setArguments(args); - data.flags = flags; + data.setFlags(flags); QQmlPropertyData *old = findNamedProperty(name); if (old) @@ -416,12 +420,6 @@ void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int cor setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0)); } -// 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() { @@ -437,51 +435,36 @@ const QMetaObject *QQmlPropertyCache::createMetaObject() 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(), 0, 0); } -QQmlPropertyCache *QQmlPropertyCache::parent() const -{ - return _parent; -} - void QQmlPropertyCache::setParent(QQmlPropertyCache *newParent) { + if (_parent == newParent) + return; + if (_parent) + _parent->release(); _parent = newParent; -} - -// 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; + _parent->addref(); } QQmlPropertyCache * QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject, - QQmlPropertyData::Flag propertyFlags, - QQmlPropertyData::Flag methodFlags, - QQmlPropertyData::Flag signalFlags) + QQmlPropertyData::Flags propertyFlags, + QQmlPropertyData::Flags methodFlags, + QQmlPropertyData::Flags signalFlags) { return copyAndAppend(metaObject, -1, propertyFlags, methodFlags, signalFlags); } QQmlPropertyCache * QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject, - int revision, - QQmlPropertyData::Flag propertyFlags, - QQmlPropertyData::Flag methodFlags, - QQmlPropertyData::Flag signalFlags) + int revision, + QQmlPropertyData::Flags propertyFlags, + QQmlPropertyData::Flags methodFlags, + QQmlPropertyData::Flags signalFlags) { Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4); @@ -498,10 +481,10 @@ QQmlPropertyCache::copyAndAppend(const QMetaObject *metaObject, } void QQmlPropertyCache::append(const QMetaObject *metaObject, - int revision, - QQmlPropertyData::Flag propertyFlags, - QQmlPropertyData::Flag methodFlags, - QQmlPropertyData::Flag signalFlags) + int revision, + QQmlPropertyData::Flags propertyFlags, + QQmlPropertyData::Flags methodFlags, + QQmlPropertyData::Flags signalFlags) { Q_UNUSED(revision); @@ -516,40 +499,21 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, int signalCount = metaObjectSignalCount(metaObject); int classInfoCount = QMetaObjectPrivate::get(metaObject)->classInfoCount; - QQmlAccessorProperties::Properties accessorProperties; - if (classInfoCount) { int classInfoOffset = metaObject->classInfoOffset(); - bool hasFastProperty = false; for (int ii = 0; ii < classInfoCount; ++ii) { int idx = ii + classInfoOffset; - - const char * const classInfoName = metaObject->classInfo(idx).name(); - if (0 == qstrcmp(classInfoName, "qt_HasQmlAccessors")) { - hasFastProperty = true; - } else if (0 == qstrcmp(classInfoName, "DefaultProperty")) { - _defaultPropertyName = QString::fromUtf8(metaObject->classInfo(idx).value()); - } else if (0 == qstrcmp(classInfoName, "qt_QmlJSWrapperFactoryMethod")) { - const char * const factoryMethod = metaObject->classInfo(idx).value(); + QMetaClassInfo mci = metaObject->classInfo(idx); + const char *name = mci.name(); + if (0 == qstrcmp(name, "DefaultProperty")) { + _defaultPropertyName = QString::fromUtf8(mci.value()); + } else if (0 == qstrcmp(name, "qt_QmlJSWrapperFactoryMethod")) { + const char * const factoryMethod = mci.value(); _jsFactoryMethodIndex = metaObject->indexOfSlot(factoryMethod); if (_jsFactoryMethodIndex != -1) _jsFactoryMethodIndex -= metaObject->methodOffset(); } } - - if (hasFastProperty) { - accessorProperties = QQmlAccessorProperties::properties(metaObject); - if (accessorProperties.count == 0) - qFatal("QQmlPropertyCache: %s has FastProperty class info, but has not " - "installed property accessors", metaObject->className()); - } else { -#ifndef QT_NO_DEBUG - accessorProperties = QQmlAccessorProperties::properties(metaObject); - if (accessorProperties.count != 0) - qFatal("QQmlPropertyCache: %s has fast property accessors, but is missing " - "FastProperty class info", metaObject->className()); -#endif - } } //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML @@ -588,23 +552,21 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, QQmlPropertyData *data = &methodIndexCache[ii - methodIndexCacheStart]; QQmlPropertyData *sigdata = 0; - data->lazyLoad(m); - - if (data->isSignal()) - data->flags |= signalFlags; + if (m.methodType() == QMetaMethod::Signal) + data->setFlags(signalFlags); else - data->flags |= methodFlags; + data->setFlags(methodFlags); - if (!dynamicMetaObject) - data->flags |= QQmlPropertyData::IsDirect; + data->lazyLoad(m); + data->_flags.isDirect = !dynamicMetaObject; Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX); - data->metaObjectOffset = allowedRevisionCache.count() - 1; + data->setMetaObjectOffset(allowedRevisionCache.count() - 1); if (data->isSignal()) { sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart]; *sigdata = *data; - sigdata->flags |= QQmlPropertyData::IsSignalHandler; + sigdata->_flags.isSignalHandler = true; } QQmlPropertyData *old = 0; @@ -616,7 +578,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, setNamedProperty(methodName, ii, data, (old != 0)); if (data->isSignal()) { - QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1)); + QHashedString on(QLatin1String("on") % methodName.at(0).toUpper() % methodName.midRef(1)); setNamedProperty(on, ii, sigdata, (old != 0)); ++signalHandlerIndex; } @@ -645,8 +607,8 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, if (old) { // We only overload methods in the same class, exactly like C++ - if (old->isFunction() && old->coreIndex >= methodOffset) - data->flags |= QQmlPropertyData::IsOverload; + if (old->isFunction() && old->coreIndex() >= methodOffset) + data->_flags.isOverload = true; data->markAsOverrideOf(old); } @@ -673,14 +635,13 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart]; + data->setFlags(propertyFlags); data->lazyLoad(p); - data->flags |= propertyFlags; - if (!dynamicMetaObject) - data->flags |= QQmlPropertyData::IsDirect; + data->_flags.isDirect = !dynamicMetaObject; Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX); - data->metaObjectOffset = allowedRevisionCache.count() - 1; + data->setMetaObjectOffset(allowedRevisionCache.count() - 1); QQmlPropertyData *old = 0; @@ -696,29 +657,40 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, setNamedProperty(propName, ii, data, (old != 0)); } - QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str); - - // Fast properties may not be overrides or revisioned - Q_ASSERT(accessorProperty == 0 || (old == 0 && data->revision == 0)); + bool isGadget = true; + for (const QMetaObject *it = metaObject; it != nullptr; it = it->superClass()) { + if (it == &QObject::staticMetaObject) + isGadget = false; + } - if (accessorProperty) { - data->flags |= QQmlPropertyData::HasAccessors; - data->accessors = accessorProperty->accessors; - } else if (old) { + if (isGadget) // always dispatch over a 'normal' meta-call so the QQmlValueType can intercept + data->_flags.isDirect = false; + else + data->trySetStaticMetaCallFunction(metaObject->d.static_metacall, ii - propOffset); + if (old) data->markAsOverrideOf(old); - } } } void QQmlPropertyCache::resolve(QQmlPropertyData *data) const { Q_ASSERT(data->notFullyResolved()); - - data->propType = QMetaType::type(data->propTypeName); + data->_flags.notFullyResolved = false; + + const QMetaObject *mo = firstCppMetaObject(); + if (data->isFunction()) { + auto metaMethod = mo->method(data->coreIndex()); + const char *retTy = metaMethod.typeName(); + if (!retTy) + retTy = "\0"; + data->setPropType(QMetaType::type(retTy)); + } else { + auto metaProperty = mo->property(data->coreIndex()); + data->setPropType(QMetaType::type(metaProperty.typeName())); + } if (!data->isFunction()) { - if (data->propType == QMetaType::UnknownType) { - const QMetaObject *mo = _metaObject; + if (data->propType() == QMetaType::UnknownType) { QQmlPropertyCache *p = _parent; while (p && (!mo || _ownMetaObject)) { mo = p->_metaObject; @@ -726,22 +698,20 @@ void QQmlPropertyCache::resolve(QQmlPropertyData *data) const } int propOffset = mo->propertyOffset(); - if (mo && data->coreIndex < propOffset + mo->propertyCount()) { - while (data->coreIndex < propOffset) { + if (mo && data->coreIndex() < propOffset + mo->propertyCount()) { + while (data->coreIndex() < propOffset) { mo = mo->superClass(); propOffset = mo->propertyOffset(); } int registerResult = -1; void *argv[] = { ®isterResult }; - mo->static_metacall(QMetaObject::RegisterPropertyMetaType, data->coreIndex - propOffset, argv); - data->propType = registerResult == -1 ? QMetaType::UnknownType : registerResult; + mo->static_metacall(QMetaObject::RegisterPropertyMetaType, data->coreIndex() - propOffset, argv); + data->setPropType(registerResult == -1 ? QMetaType::UnknownType : registerResult); } } - data->flags |= flagsForPropertyType(data->propType, engine->qmlEngine()); + flagsForPropertyType(data->propType(), engine->qmlEngine(), data->_flags); } - - data->flags &= ~QQmlPropertyData::NotFullyResolved; } void QQmlPropertyCache::updateRecur(const QMetaObject *metaObject) @@ -808,48 +778,6 @@ void QQmlPropertyCache::invalidate(const QMetaObject *metaObject) } } -/*! \internal - \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()). - This is different from QMetaMethod::methodIndex(). -*/ -QQmlPropertyData * -QQmlPropertyCache::signal(int index) const -{ - if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count())) - return 0; - - if (index < signalHandlerIndexCacheStart) - return _parent->signal(index); - - QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart)); - Q_ASSERT(rv->isSignal() || rv->coreIndex == -1); - return ensureResolved(rv); -} - -int QQmlPropertyCache::methodIndexToSignalIndex(int index) const -{ - if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count())) - return index; - - if (index < methodIndexCacheStart) - return _parent->methodIndexToSignalIndex(index); - - return index - methodIndexCacheStart + signalHandlerIndexCacheStart; -} - -QQmlPropertyData * -QQmlPropertyCache::method(int index) const -{ - if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count())) - return 0; - - if (index < methodIndexCacheStart) - return _parent->method(index); - - QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart)); - return ensureResolved(rv); -} - QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, QObject *object, QQmlContextData *context) const { QQmlData *data = (object ? QQmlData::get(object) : 0); @@ -866,11 +794,11 @@ inline bool contextHasNoExtensions(QQmlContextData *context) return (!context->parent || !context->parent->imports); } -inline int maximumIndexForProperty(QQmlPropertyData *prop, const QQmlVMEMetaObject *vmemo) +inline int maximumIndexForProperty(QQmlPropertyData *prop, const int methodCount, const int signalCount, const int propertyCount) { - return (prop->isFunction() ? vmemo->methodCount() - : prop->isSignalHandler() ? vmemo->signalCount() - : vmemo->propertyCount()); + return prop->isFunction() ? methodCount + : prop->isSignalHandler() ? signalCount + : propertyCount; } } @@ -897,11 +825,15 @@ QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, } if (vmemo) { + const int methodCount = vmemo->methodCount(); + const int signalCount = vmemo->signalCount(); + const int propertyCount = vmemo->propertyCount(); + // Ensure that the property we resolve to is accessible from this meta-object do { const StringCache::mapped_type &property(it.value()); - if (property.first < maximumIndexForProperty(property.second, vmemo)) { + if (property.first < maximumIndexForProperty(property.second, methodCount, signalCount, propertyCount)) { // This property is available in the specified context if (property.second->isFunction() || property.second->isSignalHandler()) { // Prefer the earlier resolution @@ -933,33 +865,25 @@ QString QQmlPropertyData::name(QObject *object) const QString QQmlPropertyData::name(const QMetaObject *metaObject) const { - if (!metaObject || coreIndex == -1) + if (!metaObject || coreIndex() == -1) return QString(); - if (flags & IsFunction) { - QMetaMethod m = metaObject->method(coreIndex); + if (isFunction()) { + QMetaMethod m = metaObject->method(coreIndex()); return QString::fromUtf8(m.name().constData()); } else { - QMetaProperty p = metaObject->property(coreIndex); + QMetaProperty p = metaObject->property(coreIndex()); return QString::fromUtf8(p.name()); } } void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor) { - overrideIndexIsProperty = !predecessor->isFunction(); - overrideIndex = predecessor->coreIndex; + setOverrideIndexIsProperty(!predecessor->isFunction()); + setOverrideIndex(predecessor->coreIndex()); - predecessor->flags |= QQmlPropertyData::IsOverridden; -} - -QStringList QQmlPropertyCache::propertyNames() const -{ - QStringList keys; - for (StringCache::ConstIterator iter = stringCache.begin(), cend = stringCache.end(); iter != cend; ++iter) - keys.append(iter.key()); - return keys; + predecessor->_flags.isOverridden = true; } struct StaticQtMetaObject : public QObject @@ -1010,7 +934,6 @@ QString QQmlPropertyCache::signalParameterStringForJS(QV4::ExecutionEngine *engi { bool unnamedParameter = false; const QSet<QString> &illegalNames = engine->v8Engine->illegalNames(); - QString error; QString parameters; for (int i = 0; i < parameterNameList.count(); ++i) { @@ -1173,9 +1096,21 @@ QQmlPropertyCache::property(QJSEngine *engine, QObject *obj, return qQmlPropertyCacheProperty<const QString &>(engine, obj, name, context, local); } +// these two functions are copied from qmetaobject.cpp static inline const QMetaObjectPrivate *priv(const uint* data) { return reinterpret_cast<const QMetaObjectPrivate*>(data); } +static inline const QByteArray stringData(const QMetaObject *mo, int index) +{ + Q_ASSERT(priv(mo->d.data)->revision >= 7); + const QByteArrayDataPtr data = { const_cast<QByteArrayData*>(&mo->d.stringdata[index]) }; + Q_ASSERT(data.ptr->ref.isStatic()); + Q_ASSERT(data.ptr->alloc == 0); + Q_ASSERT(data.ptr->capacityReserved == 0); + Q_ASSERT(data.ptr->size >= 0); + return data; +} + bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo) { return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject; @@ -1193,7 +1128,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) { struct Sort { static bool lt(const QPair<QString, QQmlPropertyData *> &lhs, const QPair<QString, QQmlPropertyData *> &rhs) { - return lhs.second->coreIndex < rhs.second->coreIndex; + return lhs.second->coreIndex() < rhs.second->coreIndex(); } }; struct Insert { static void in(QQmlPropertyCache *This, @@ -1204,7 +1139,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) return; if (data->isFunction()) { - if (data->coreIndex < This->methodIndexCacheStart) + if (data->coreIndex() < This->methodIndexCacheStart) return; QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data); @@ -1214,7 +1149,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) data = This->overrideData(data); if (data && !data->isFunction()) Insert::in(This, properties, methods, iter, data); } else { - if (data->coreIndex < This->propertyIndexCacheStart) + if (data->coreIndex() < This->propertyIndexCacheStart) return; QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data); @@ -1245,11 +1180,11 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) QQmlPropertyData *data = properties.at(ii).second; int notifierId = -1; - if (data->notifyIndex != -1) - notifierId = data->notifyIndex - signalHandlerIndexCacheStart; + if (data->notifyIndex() != -1) + notifierId = data->notifyIndex() - signalHandlerIndexCacheStart; QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(), - QMetaType::typeName(data->propType), + QMetaType::typeName(data->propType()), notifierId); property.setReadable(true); @@ -1261,14 +1196,16 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) QQmlPropertyData *data = methods.at(ii).second; QByteArray returnType; - if (data->propType != 0) - returnType = QMetaType::typeName(data->propType); + if (data->propType() != 0) + returnType = QMetaType::typeName(data->propType()); - QByteArray signature = methods.at(ii).first.toUtf8() + '('; + QByteArray signature; + // '+=' reserves extra capacity. Follow-up appending will be probably free. + signature += methods.at(ii).first.toUtf8() + '('; QQmlPropertyCacheMethodArguments *arguments = 0; if (data->hasArguments()) { - arguments = (QQmlPropertyCacheMethodArguments *)data->arguments; + arguments = (QQmlPropertyCacheMethodArguments *)data->arguments(); Q_ASSERT(arguments->argumentsValid); for (int ii = 0; ii < arguments->arguments[0]; ++ii) { if (ii != 0) signature.append(','); @@ -1295,13 +1232,227 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) if (!_defaultPropertyName.isEmpty()) { QQmlPropertyData *dp = property(_defaultPropertyName, 0, 0); - if (dp && dp->coreIndex >= propertyIndexCacheStart) { + if (dp && dp->coreIndex() >= propertyIndexCacheStart) { Q_ASSERT(!dp->isFunction()); builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8()); } } } +namespace { +template <typename StringVisitor, typename TypeInfoVisitor> +int visitMethods(const QMetaObject &mo, int methodOffset, int methodCount, + StringVisitor visitString, TypeInfoVisitor visitTypeInfo) +{ + const int intsPerMethod = 5; + + int fieldsForParameterData = 0; + + bool hasRevisionedMethods = false; + + for (int i = 0; i < methodCount; ++i) { + const int handle = methodOffset + i * intsPerMethod; + + const uint flags = mo.d.data[handle + 4]; + if (flags & MethodRevisioned) + hasRevisionedMethods = true; + + visitString(mo.d.data[handle + 0]); // name + visitString(mo.d.data[handle + 3]); // tag + + const int argc = mo.d.data[handle + 1]; + const int paramIndex = mo.d.data[handle + 2]; + + fieldsForParameterData += argc * 2; // type and name + fieldsForParameterData += 1; // + return type + + // return type + args + for (int i = 0; i < 1 + argc; ++i) { + // type name (maybe) + visitTypeInfo(mo.d.data[paramIndex + i]); + + // parameter name + if (i > 0) + visitString(mo.d.data[paramIndex + argc + i]); + } + } + + int fieldsForRevisions = 0; + if (hasRevisionedMethods) + fieldsForRevisions = methodCount; + + return methodCount * intsPerMethod + fieldsForRevisions + fieldsForParameterData; +} + +template <typename StringVisitor, typename TypeInfoVisitor> +int visitProperties(const QMetaObject &mo, StringVisitor visitString, TypeInfoVisitor visitTypeInfo) +{ + const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); + const int intsPerProperty = 3; + + bool hasRevisionedProperties = false; + bool hasNotifySignals = false; + + for (int i = 0; i < priv->propertyCount; ++i) { + const int handle = priv->propertyData + i * intsPerProperty; + + const auto flags = mo.d.data[handle + 2]; + if (flags & Revisioned) { + hasRevisionedProperties = true; + } + if (flags & Notify) + hasNotifySignals = true; + + visitString(mo.d.data[handle]); // name + visitTypeInfo(mo.d.data[handle + 1]); + } + + int fieldsForPropertyRevisions = 0; + if (hasRevisionedProperties) + fieldsForPropertyRevisions = priv->propertyCount; + + int fieldsForNotifySignals = 0; + if (hasNotifySignals) + fieldsForNotifySignals = priv->propertyCount; + + return priv->propertyCount * intsPerProperty + fieldsForPropertyRevisions + + fieldsForNotifySignals; +} + +template <typename StringVisitor> +int visitClassInfo(const QMetaObject &mo, StringVisitor visitString) +{ + const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); + const int intsPerClassInfo = 2; + + for (int i = 0; i < priv->classInfoCount; ++i) { + const int handle = priv->classInfoData + i * intsPerClassInfo; + + visitString(mo.d.data[handle]); // key + visitString(mo.d.data[handle + 1]); // value + } + + return priv->classInfoCount * intsPerClassInfo; +} + +template <typename StringVisitor> +int visitEnumerations(const QMetaObject &mo, StringVisitor visitString) +{ + const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); + const int intsPerEnumerator = 4; + + int fieldCount = priv->enumeratorCount * intsPerEnumerator; + + for (int i = 0; i < priv->enumeratorCount; ++i) { + const uint *enumeratorData = mo.d.data + priv->enumeratorData + i * intsPerEnumerator; + + const uint keyCount = enumeratorData[2]; + fieldCount += keyCount * 2; + + visitString(enumeratorData[0]); // name + + const uint keyOffset = enumeratorData[3]; + + for (uint j = 0; j < keyCount; ++j) { + visitString(mo.d.data[keyOffset + 2 * j]); + } + } + + return fieldCount; +} + +template <typename StringVisitor> +int countMetaObjectFields(const QMetaObject &mo, StringVisitor stringVisitor) +{ + const QMetaObjectPrivate *const priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); + + const auto typeInfoVisitor = [&stringVisitor](uint typeInfo) { + if (typeInfo & IsUnresolvedType) + stringVisitor(typeInfo & TypeNameIndexMask); + }; + + int fieldCount = MetaObjectPrivateFieldCount; + + fieldCount += visitMethods(mo, priv->methodData, priv->methodCount, stringVisitor, + typeInfoVisitor); + fieldCount += visitMethods(mo, priv->constructorData, priv->constructorCount, stringVisitor, + typeInfoVisitor); + + fieldCount += visitProperties(mo, stringVisitor, typeInfoVisitor); + fieldCount += visitClassInfo(mo, stringVisitor); + fieldCount += visitEnumerations(mo, stringVisitor); + + return fieldCount; +} + +} // anonymous namespace + +bool QQmlPropertyCache::determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, + int *stringCount) +{ + const QMetaObjectPrivate *priv = reinterpret_cast<const QMetaObjectPrivate*>(mo.d.data); + if (priv->revision != 7) { + return false; + } + + uint highestStringIndex = 0; + const auto stringIndexVisitor = [&highestStringIndex](uint index) { + highestStringIndex = qMax(highestStringIndex, index); + }; + + *fieldCount = countMetaObjectFields(mo, stringIndexVisitor); + *stringCount = highestStringIndex + 1; + + return true; +} + +bool QQmlPropertyCache::addToHash(QCryptographicHash &hash, const QMetaObject &mo) +{ + int fieldCount = 0; + int stringCount = 0; + if (!determineMetaObjectSizes(mo, &fieldCount, &stringCount)) { + return false; + } + + hash.addData(reinterpret_cast<const char *>(mo.d.data), fieldCount * sizeof(uint)); + for (int i = 0; i < stringCount; ++i) { + hash.addData(stringData(&mo, i)); + } + + return true; +} + +QByteArray QQmlPropertyCache::checksum(bool *ok) +{ + if (!_checksum.isEmpty()) { + *ok = true; + return _checksum; + } + + // Generate a checksum on the meta-object data only on C++ types. + if (!_metaObject || _ownMetaObject) { + *ok = false; + return _checksum; + } + + QCryptographicHash hash(QCryptographicHash::Md5); + + if (_parent) { + hash.addData(_parent->checksum(ok)); + if (!*ok) + return QByteArray(); + } + + if (!addToHash(hash, *createMetaObject())) { + *ok = false; + return QByteArray(); + } + + _checksum = hash.result(); + *ok = !_checksum.isEmpty(); + return _checksum; +} + /*! \internal \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()). This is different from QMetaMethod::methodIndex(). @@ -1310,7 +1461,7 @@ QList<QByteArray> QQmlPropertyCache::signalParameterNames(int index) const { QQmlPropertyData *signalData = signal(index); if (signalData && signalData->hasArguments()) { - QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments; + QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments(); if (args && args->names) return *args->names; const QMetaMethod &method = QMetaObjectPrivate::signal(firstCppMetaObject(), index); @@ -1412,9 +1563,9 @@ QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const int QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const { - Q_ASSERT(!_m.isNull() && data.coreIndex >= 0); + Q_ASSERT(!_m.isNull() && data.coreIndex() >= 0); - int type = data.propType; + int type = data.propType(); const char *propTypeName = 0; @@ -1424,16 +1575,16 @@ int QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *u if (_m.isT1()) { QQmlPropertyCache *c = _m.asT1(); - Q_ASSERT(data.coreIndex < c->methodIndexCacheStart + c->methodIndexCache.count()); + Q_ASSERT(data.coreIndex() < c->methodIndexCacheStart + c->methodIndexCache.count()); - while (data.coreIndex < c->methodIndexCacheStart) + while (data.coreIndex() < c->methodIndexCacheStart) c = c->_parent; const QMetaObject *metaObject = c->createMetaObject(); Q_ASSERT(metaObject); - m = metaObject->method(data.coreIndex); + m = metaObject->method(data.coreIndex()); } else { - m = _m.asT2()->method(data.coreIndex); + m = _m.asT2()->method(data.coreIndex()); } type = m.returnType(); @@ -1457,7 +1608,8 @@ int QQmlMetaObject::methodReturnType(const QQmlPropertyData &data, QByteArray *u return type; } -int *QQmlMetaObject::methodParameterTypes(int index, QVarLengthArray<int, 9> &dummy, QByteArray *unknownTypeError) const +int *QQmlMetaObject::methodParameterTypes(int index, ArgTypeStorage *argStorage, + QByteArray *unknownTypeError) const { Q_ASSERT(!_m.isNull() && index >= 0); @@ -1472,19 +1624,19 @@ int *QQmlMetaObject::methodParameterTypes(int index, QVarLengthArray<int, 9> &du QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart)); - if (rv->arguments && static_cast<A *>(rv->arguments)->argumentsValid) - return static_cast<A *>(rv->arguments)->arguments; + if (rv->arguments() && static_cast<A *>(rv->arguments())->argumentsValid) + return static_cast<A *>(rv->arguments())->arguments; const QMetaObject *metaObject = c->createMetaObject(); Q_ASSERT(metaObject); QMetaMethod m = metaObject->method(index); int argc = m.parameterCount(); - if (!rv->arguments) { + if (!rv->arguments()) { A *args = c->createArgumentsObject(argc, m.parameterNames()); - rv->arguments = args; + rv->setArguments(args); } - A *args = static_cast<A *>(rv->arguments); + A *args = static_cast<A *>(rv->arguments()); QList<QByteArray> argTypeNames; // Only loaded if needed @@ -1508,43 +1660,57 @@ int *QQmlMetaObject::methodParameterTypes(int index, QVarLengthArray<int, 9> &du args->arguments[ii + 1] = type; } args->argumentsValid = true; - return static_cast<A *>(rv->arguments)->arguments; + return static_cast<A *>(rv->arguments())->arguments; } else { QMetaMethod m = _m.asT2()->method(index); - int argc = m.parameterCount(); - dummy.resize(argc + 1); - dummy[0] = argc; - QList<QByteArray> argTypeNames; // Only loaded if needed + return methodParameterTypes(m, argStorage, unknownTypeError); - for (int ii = 0; ii < argc; ++ii) { - int type = m.parameterType(ii); - QMetaType::TypeFlags flags = QMetaType::typeFlags(type); - if (flags & QMetaType::IsEnumeration) - type = QVariant::Int; - else if (type == QMetaType::UnknownType || - (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) && - type != qMetaTypeId<QJSValue>())) { - //the UserType clause is to catch registered QFlags) - if (argTypeNames.isEmpty()) - argTypeNames = m.parameterTypes(); - type = EnumType(_m.asT2(), argTypeNames.at(ii), type); - } - if (type == QMetaType::UnknownType) { - if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii); - return 0; - } - dummy[ii + 1] = type; - } + } +} - return dummy.data(); +int *QQmlMetaObject::methodParameterTypes(const QMetaMethod &m, ArgTypeStorage *argStorage, + QByteArray *unknownTypeError) const +{ + Q_ASSERT(argStorage); + + int argc = m.parameterCount(); + argStorage->resize(argc + 1); + argStorage->operator[](0) = argc; + QList<QByteArray> argTypeNames; // Only loaded if needed + + for (int ii = 0; ii < argc; ++ii) { + int type = m.parameterType(ii); + QMetaType::TypeFlags flags = QMetaType::typeFlags(type); + if (flags & QMetaType::IsEnumeration) + type = QVariant::Int; + else if (type == QMetaType::UnknownType || + (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) && + type != qMetaTypeId<QJSValue>())) { + //the UserType clause is to catch registered QFlags) + if (argTypeNames.isEmpty()) + argTypeNames = m.parameterTypes(); + type = EnumType(_m.asT2(), argTypeNames.at(ii), type); + } + if (type == QMetaType::UnknownType) { + if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii); + return 0; + } + argStorage->operator[](ii + 1) = type; } + + return argStorage->data(); } void QQmlObjectOrGadget::metacall(QMetaObject::Call type, int index, void **argv) const { - if (ptr.isT1()) + if (ptr.isNull()) { + const QMetaObject *metaObject = _m.asT2(); + metaObject->d.static_metacall(0, type, index, argv); + } + else if (ptr.isT1()) { QMetaObject::metacall(ptr.asT1(), type, index, argv); + } else { const QMetaObject *metaObject = _m.asT1()->metaObject(); QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(type, &metaObject, &index); @@ -1552,4 +1718,11 @@ void QQmlObjectOrGadget::metacall(QMetaObject::Call type, int index, void **argv } } +int *QQmlStaticMetaObject::constructorParameterTypes(int index, ArgTypeStorage *dummy, + QByteArray *unknownTypeError) const +{ + QMetaMethod m = _m.asT2()->constructor(index); + return methodParameterTypes(m, dummy, unknownTypeError); +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 830b8398b5..6281b9c05e 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -55,6 +55,7 @@ #include <private/qflagpointer_p.h> #include "qqmlcleanup_p.h" #include "qqmlnotifier_p.h" +#include <private/qqmlpropertyindex_p.h> #include <private/qhashedstring_p.h> #include <QtCore/qvarlengtharray.h> @@ -62,17 +63,20 @@ #include <private/qv4value_p.h> +#include <limits> + QT_BEGIN_NAMESPACE +class QCryptographicHash; class QMetaProperty; class QQmlEngine; class QJSEngine; class QQmlPropertyData; -class QQmlAccessors; class QMetaObjectBuilder; class QQmlPropertyCacheMethodArguments; class QQmlVMEMetaObject; -class QQmlPropertyCacheCreator; +template <typename T> class QQmlPropertyCacheCreator; +template <typename T> class QQmlPropertyCacheAliasCreator; // We have this somewhat awful split between RawData and Data so that RawData can be // used in unions. In normal code, you should always use Data which initializes RawData @@ -82,149 +86,203 @@ class QQmlPropertyRawData public: typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction; - enum Flag { - NoFlags = 0x00000000, - ValueTypeFlagMask = 0x0000FFFF, // Flags in valueTypeFlags must fit in this mask + struct Flags { + enum Types { + OtherType = 0, + FunctionType = 1, // Is an invokable + QObjectDerivedType = 2, // Property type is a QObject* derived type + EnumType = 3, // Property type is an enum + QListType = 4, // Property type is a QML list + QmlBindingType = 5, // Property type is a QQmlBinding* + QJSValueType = 6, // Property type is a QScriptValue + V4HandleType = 7, // Property type is a QQmlV4Handle + VarPropertyType = 8, // Property type is a "var" property of VMEMO + QVariantType = 9 // Property is a QVariant + }; + + // The _otherBits (which "pad" the Flags struct to align it nicely) are used + // to store the relative property index. It will only get used when said index fits. See + // trySetStaticMetaCallFunction for details. + // (Note: this padding is done here, because certain compilers have surprising behavior + // when an enum is declared in-between two bit fields.) + enum { BitsLeftInFlags = 10 }; + unsigned _otherBits : BitsLeftInFlags; // align to 32 bits // Can apply to all properties, except IsFunction - IsConstant = 0x00000001, // Has CONST flag - IsWritable = 0x00000002, // Has WRITE function - IsResettable = 0x00000004, // Has RESET function - IsAlias = 0x00000008, // Is a QML alias to another property - IsFinal = 0x00000010, // Has FINAL flag - IsOverridden = 0x00000020, // Is overridden by a extension property - IsDirect = 0x00000040, // Exists on a C++ QMetaObject - HasAccessors = 0x00000080, // Has property accessors - - // These are mutualy exclusive - IsFunction = 0x00000100, // Is an invokable - IsQObjectDerived = 0x00000200, // Property type is a QObject* derived type - IsEnumType = 0x00000400, // Property type is an enum - IsQList = 0x00000800, // Property type is a QML list - IsQmlBinding = 0x00001000, // Property type is a QQmlBinding* - IsQJSValue = 0x00002000, // Property type is a QScriptValue - IsV4Handle = 0x00004000, // Property type is a QQmlV4Handle - IsVarProperty = 0x00008000, // Property type is a "var" property of VMEMO - IsValueTypeVirtual = 0x00010000, // Property is a value type "virtual" property - IsQVariant = 0x00020000, // Property is a QVariant + unsigned isConstant : 1; // Has CONST flag + unsigned isWritable : 1; // Has WRITE function + unsigned isResettable : 1; // Has RESET function + unsigned isAlias : 1; // Is a QML alias to another property + unsigned isFinal : 1; // Has FINAL flag + unsigned isOverridden : 1; // Is overridden by a extension property + unsigned isDirect : 1; // Exists on a C++ QMetaObject + + unsigned type : 4; // stores an entry of Types // Apply only to IsFunctions - IsVMEFunction = 0x00040000, // Function was added by QML - HasArguments = 0x00080000, // Function takes arguments - IsSignal = 0x00100000, // Function is a signal - IsVMESignal = 0x00200000, // Signal was added by QML - IsV4Function = 0x00400000, // Function takes QQmlV4Function* args - IsSignalHandler = 0x00800000, // Function is a signal handler - IsOverload = 0x01000000, // Function is an overload of another function - IsCloned = 0x02000000, // The function was marked as cloned + unsigned isVMEFunction : 1; // Function was added by QML + unsigned hasArguments : 1; // Function takes arguments + unsigned isSignal : 1; // Function is a signal + unsigned isVMESignal : 1; // Signal was added by QML + unsigned isV4Function : 1; // Function takes QQmlV4Function* args + unsigned isSignalHandler : 1; // Function is a signal handler + unsigned isOverload : 1; // Function is an overload of another function + unsigned isCloned : 1; // The function was marked as cloned + unsigned isConstructor : 1; // The function was marked is a constructor // Internal QQmlPropertyCache flags - NotFullyResolved = 0x04000000, // True if the type data is to be lazily resolved + unsigned notFullyResolved : 1; // True if the type data is to be lazily resolved + unsigned overrideIndexIsProperty: 1; - // Flags that are set based on the propType field - PropTypeFlagMask = IsQObjectDerived | IsEnumType | IsQList | IsQmlBinding | IsQJSValue | - IsV4Handle | IsQVariant, + inline Flags(); + inline bool operator==(const Flags &other) const; + inline void copyPropertyTypeFlags(Flags from); }; - Q_DECLARE_FLAGS(Flags, Flag) - - Flags getFlags() const { return Flag(flags); } - void setFlags(Flags f) { flags = f; } - - bool isValid() const { return coreIndex != -1; } - - bool isConstant() const { return flags & IsConstant; } - bool isWritable() const { return flags & IsWritable; } - bool isResettable() const { return flags & IsResettable; } - bool isAlias() const { return flags & IsAlias; } - bool isFinal() const { return flags & IsFinal; } - bool isOverridden() const { return flags & IsOverridden; } - bool isDirect() const { return flags & IsDirect; } - bool hasAccessors() const { return flags & HasAccessors; } - bool isFunction() const { return flags & IsFunction; } - bool isQObject() const { return flags & IsQObjectDerived; } - bool isEnum() const { return flags & IsEnumType; } - bool isQList() const { return flags & IsQList; } - bool isQmlBinding() const { return flags & IsQmlBinding; } - bool isQJSValue() const { return flags & IsQJSValue; } - bool isV4Handle() const { return flags & IsV4Handle; } - bool isVarProperty() const { return flags & IsVarProperty; } - bool isValueTypeVirtual() const { return flags & IsValueTypeVirtual; } - bool isQVariant() const { return flags & IsQVariant; } - bool isVMEFunction() const { return flags & IsVMEFunction; } - bool hasArguments() const { return flags & HasArguments; } - bool isSignal() const { return flags & IsSignal; } - bool isVMESignal() const { return flags & IsVMESignal; } - bool isV4Function() const { return flags & IsV4Function; } - 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) && - overrideIndex >= 0; } - bool hasRevision() const { return !(flags & HasAccessors) && revision != 0; } - - // Returns -1 if not a value type virtual property - inline int getValueTypeCoreIndex() const; - - // Returns the "encoded" index for use with bindings. Encoding is: - // coreIndex | ((valueTypeCoreIndex + 1) << 16) - inline int encodedIndex() const; - static int encodeValueTypePropertyIndex(int coreIndex, int valueTypeCoreIndex) - { return coreIndex | ((valueTypeCoreIndex + 1) << 16); } - static int decodeValueTypePropertyIndex(int index, int *coreIndex = 0) { - if (coreIndex) *coreIndex = index & 0xffff; - return (index >> 16) - 1; + + Flags flags() const { return _flags; } + void setFlags(Flags f) + { + unsigned otherBits = _flags._otherBits; + _flags = f; + _flags._otherBits = otherBits; } - union { - int propType; // When !NotFullyResolved - const char *propTypeName; // When NotFullyResolved - }; - union { - // The notify index is in the range returned by QObjectPrivate::signalIndex(). - // This is different from QMetaMethod::methodIndex(). - int notifyIndex; // When !IsFunction - void *arguments; // When IsFunction && HasArguments - }; + bool isValid() const { return coreIndex() != -1; } + + bool isConstant() const { return _flags.isConstant; } + bool isWritable() const { return _flags.isWritable; } + void setWritable(bool onoff) { _flags.isWritable = onoff; } + bool isResettable() const { return _flags.isResettable; } + bool isAlias() const { return _flags.isAlias; } + bool isFinal() const { return _flags.isFinal; } + bool isOverridden() const { return _flags.isOverridden; } + bool isDirect() const { return _flags.isDirect; } + bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; } + bool isFunction() const { return _flags.type == Flags::FunctionType; } + bool isQObject() const { return _flags.type == Flags::QObjectDerivedType; } + bool isEnum() const { return _flags.type == Flags::EnumType; } + bool isQList() const { return _flags.type == Flags::QListType; } + bool isQmlBinding() const { return _flags.type == Flags::QmlBindingType; } + bool isQJSValue() const { return _flags.type == Flags::QJSValueType; } + bool isV4Handle() const { return _flags.type == Flags::V4HandleType; } + bool isVarProperty() const { return _flags.type == Flags::VarPropertyType; } + bool isQVariant() const { return _flags.type == Flags::QVariantType; } + bool isVMEFunction() const { return _flags.isVMEFunction; } + bool hasArguments() const { return _flags.hasArguments; } + bool isSignal() const { return _flags.isSignal; } + bool isVMESignal() const { return _flags.isVMESignal; } + bool isV4Function() const { return _flags.isV4Function; } + bool isSignalHandler() const { return _flags.isSignalHandler; } + bool isOverload() const { return _flags.isOverload; } + void setOverload(bool onoff) { _flags.isOverload = onoff; } + bool isCloned() const { return _flags.isCloned; } + bool isConstructor() const { return _flags.isConstructor; } + + bool hasOverride() const { return overrideIndex() >= 0; } + bool hasRevision() const { return revision() != 0; } + + bool isFullyResolved() const { return !_flags.notFullyResolved; } + + int propType() const { Q_ASSERT(isFullyResolved()); return _propType; } + void setPropType(int pt) + { + Q_ASSERT(pt >= 0); + Q_ASSERT(pt <= std::numeric_limits<qint16>::max()); + _propType = quint16(pt); + } - union { - struct { // When !HasAccessors - qint16 revision; - qint16 metaObjectOffset; - - union { - struct { // When IsValueTypeVirtual - quint16 valueTypeFlags; // flags of the access property on the value type proxy - // object - quint16 valueTypePropType; // The QVariant::Type of access property on the value - // type proxy object - quint16 valueTypeCoreIndex; // The prop index of the access property on the value - // type proxy object - }; - - struct { // When !IsValueTypeVirtual - uint overrideIndexIsProperty : 1; - signed int overrideIndex : 31; - }; - }; - }; - struct { // When HasAccessors - QQmlAccessors *accessors; - }; - }; - int coreIndex; + int notifyIndex() const { return _notifyIndex; } + void setNotifyIndex(int idx) + { + Q_ASSERT(idx >= std::numeric_limits<qint16>::min()); + Q_ASSERT(idx <= std::numeric_limits<qint16>::max()); + _notifyIndex = qint16(idx); + } + + bool overrideIndexIsProperty() const { return _flags.overrideIndexIsProperty; } + void setOverrideIndexIsProperty(bool onoff) { _flags.overrideIndexIsProperty = onoff; } + + int overrideIndex() const { return _overrideIndex; } + void setOverrideIndex(int idx) + { + Q_ASSERT(idx >= std::numeric_limits<qint16>::min()); + Q_ASSERT(idx <= std::numeric_limits<qint16>::max()); + _overrideIndex = qint16(idx); + } + + int coreIndex() const { return _coreIndex; } + void setCoreIndex(int idx) + { + Q_ASSERT(idx >= std::numeric_limits<qint16>::min()); + Q_ASSERT(idx <= std::numeric_limits<qint16>::max()); + _coreIndex = qint16(idx); + } + + int revision() const { return _revision; } + void setRevision(int rev) + { + Q_ASSERT(rev >= std::numeric_limits<qint16>::min()); + Q_ASSERT(rev <= std::numeric_limits<qint16>::max()); + _revision = qint16(rev); + } + + QQmlPropertyCacheMethodArguments *arguments() const { return _arguments; } + void setArguments(QQmlPropertyCacheMethodArguments *args) { _arguments = args; } + + int metaObjectOffset() const { return _metaObjectOffset; } + void setMetaObjectOffset(int off) + { + Q_ASSERT(off >= std::numeric_limits<qint16>::min()); + Q_ASSERT(off <= std::numeric_limits<qint16>::max()); + _metaObjectOffset = qint16(off); + } + + StaticMetaCallFunction staticMetaCallFunction() const { return _staticMetaCallFunction; } + void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex) + { + if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) { + _flags._otherBits = relativePropertyIndex; + _staticMetaCallFunction = f; + } + } + quint16 relativePropertyIndex() const { Q_ASSERT(hasStaticMetaCallFunction()); return _flags._otherBits; } private: + Flags _flags; + qint16 _coreIndex; + quint16 _propType; + + // The notify index is in the range returned by QObjectPrivate::signalIndex(). + // This is different from QMetaMethod::methodIndex(). + qint16 _notifyIndex; + qint16 _overrideIndex; + + qint16 _revision; + qint16 _metaObjectOffset; + + QQmlPropertyCacheMethodArguments *_arguments; + StaticMetaCallFunction _staticMetaCallFunction; + friend class QQmlPropertyData; friend class QQmlPropertyCache; - quint32 flags; }; -Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyRawData::Flags) + +#if QT_POINTER_SIZE == 4 +Q_STATIC_ASSERT(sizeof(QQmlPropertyRawData) == 24); +#else // QT_POINTER_SIZE == 8 +Q_STATIC_ASSERT(sizeof(QQmlPropertyRawData) == 32); +#endif class QQmlPropertyData : public QQmlPropertyRawData { public: + enum WriteFlag { + BypassInterceptor = 0x01, + DontRemoveBinding = 0x02, + RemoveBindingOnAliasWrite = 0x04 + }; + Q_DECLARE_FLAGS(WriteFlags, WriteFlag) + inline QQmlPropertyData(); inline QQmlPropertyData(const QQmlPropertyRawData &); @@ -238,11 +296,57 @@ public: void markAsOverrideOf(QQmlPropertyData *predecessor); + inline void readProperty(QObject *target, void *property) const + { + void *args[] = { property, 0 }; + readPropertyWithArgs(target, args); + } + + inline void readPropertyWithArgs(QObject *target, void *args[]) const + { + if (hasStaticMetaCallFunction()) + staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args); + else if (isDirect()) + target->qt_metacall(QMetaObject::ReadProperty, coreIndex(), args); + else + QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex(), args); + } + + bool writeProperty(QObject *target, void *value, WriteFlags flags) const + { + int status = -1; + void *argv[] = { value, 0, &status, &flags }; + if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction()) + staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv); + else if (flags.testFlag(BypassInterceptor) && isDirect()) + target->qt_metacall(QMetaObject::WriteProperty, coreIndex(), argv); + else + QMetaObject::metacall(target, QMetaObject::WriteProperty, coreIndex(), argv); + return true; + } + + static Flags defaultSignalFlags() + { + Flags f; + f.isSignal = true; + f.type = Flags::FunctionType; + f.isVMESignal = true; + return f; + } + + static Flags defaultSlotFlags() + { + Flags f; + f.type = Flags::FunctionType; + f.isVMEFunction = true; + return f; + } + private: friend class QQmlPropertyCache; void lazyLoad(const QMetaProperty &); void lazyLoad(const QMetaMethod &); - bool notFullyResolved() const { return flags & NotFullyResolved; } + bool notFullyResolved() const { return _flags.notFullyResolved; } }; class QQmlPropertyCacheMethodArguments; @@ -261,21 +365,21 @@ public: QQmlPropertyCache *copy(); QQmlPropertyCache *copyAndAppend(const QMetaObject *, - QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags, - QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags, - QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags); + QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyData::Flags(), + QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(), + QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags()); QQmlPropertyCache *copyAndAppend(const QMetaObject *, int revision, - QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags, - QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags, - QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags); + QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyData::Flags(), + QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(), + QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags()); QQmlPropertyCache *copyAndReserve(int propertyCount, int methodCount, int signalCount); - void appendProperty(const QString &, - quint32 flags, int coreIndex, int propType, int notifyIndex); - void appendSignal(const QString &, quint32, int coreIndex, const int *types = 0, - const QList<QByteArray> &names = QList<QByteArray>()); - void appendMethod(const QString &, quint32 flags, int coreIndex, + void appendProperty(const QString &, QQmlPropertyRawData::Flags flags, int coreIndex, + int propType, int notifyIndex); + void appendSignal(const QString &, QQmlPropertyRawData::Flags, int coreIndex, + const int *types = 0, const QList<QByteArray> &names = QList<QByteArray>()); + void appendMethod(const QString &, QQmlPropertyData::Flags flags, int coreIndex, const QList<QByteArray> &names = QList<QByteArray>()); const QMetaObject *metaObject() const; @@ -292,7 +396,6 @@ public: QQmlPropertyData *method(int) const; QQmlPropertyData *signal(int index) const; int methodIndexToSignalIndex(int) const; - QStringList propertyNames() const; QString defaultPropertyName() const; QQmlPropertyData *defaultProperty() const; @@ -330,6 +433,11 @@ public: inline bool callJSFactoryMethod(QObject *object, void **args) const; + static bool determineMetaObjectSizes(const QMetaObject &mo, int *fieldCount, int *stringCount); + static bool addToHash(QCryptographicHash &hash, const QMetaObject &mo); + + QByteArray checksum(bool *ok); + protected: virtual void destroy(); virtual void clear(); @@ -337,16 +445,17 @@ protected: private: friend class QQmlEnginePrivate; friend class QQmlCompiler; - friend class QQmlPropertyCacheCreator; + template <typename T> friend class QQmlPropertyCacheCreator; + template <typename T> friend class QQmlPropertyCacheAliasCreator; friend class QQmlComponentAndAliasResolver; friend class QQmlMetaObject; inline QQmlPropertyCache *copy(int reserve); void append(const QMetaObject *, int revision, - QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags, - QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags, - QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags); + QQmlPropertyRawData::Flags propertyFlags = QQmlPropertyRawData::Flags(), + QQmlPropertyRawData::Flags methodFlags = QQmlPropertyData::Flags(), + QQmlPropertyRawData::Flags signalFlags = QQmlPropertyData::Flags()); QQmlPropertyCacheMethodArguments *createArgumentsObject(int count, const QList<QByteArray> &names); @@ -359,7 +468,7 @@ private: QQmlPropertyData *ensureResolved(QQmlPropertyData*) const; - void resolve(QQmlPropertyData *) const; + Q_NEVER_INLINE void resolve(QQmlPropertyData *) const; void updateRecur(const QMetaObject *); template<typename K> @@ -399,6 +508,7 @@ private: QString _defaultPropertyName; QQmlPropertyCacheMethodArguments *argumentsCache; int _jsFactoryMethodIndex; + QByteArray _checksum; }; // QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache. @@ -411,6 +521,8 @@ class QQmlEnginePrivate; class Q_QML_EXPORT QQmlMetaObject { public: + typedef QVarLengthArray<int, 9> ArgTypeStorage; + inline QQmlMetaObject(); inline QQmlMetaObject(QObject *); inline QQmlMetaObject(const QMetaObject *); @@ -430,7 +542,8 @@ public: QQmlPropertyCache *propertyCache(QQmlEnginePrivate *) const; int methodReturnType(const QQmlPropertyData &data, QByteArray *unknownTypeError) const; - int *methodParameterTypes(int index, QVarLengthArray<int, 9> &dummy, QByteArray *unknownTypeError) const; + int *methodParameterTypes(int index, ArgTypeStorage *argStorage, + QByteArray *unknownTypeError) const; static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to); @@ -440,6 +553,9 @@ public: protected: QBiPointer<QQmlPropertyCache, const QMetaObject> _m; + int *methodParameterTypes(const QMetaMethod &method, ArgTypeStorage *argStorage, + QByteArray *unknownTypeError) const; + }; class QQmlObjectOrGadget: public QQmlMetaObject @@ -458,18 +574,91 @@ public: private: QBiPointer<QObject, void> ptr; + +protected: + QQmlObjectOrGadget(const QMetaObject* metaObject) + : QQmlMetaObject(metaObject) + {} + +}; + +class QQmlStaticMetaObject : public QQmlObjectOrGadget { +public: + QQmlStaticMetaObject(const QMetaObject* metaObject) + : QQmlObjectOrGadget(metaObject) + {} + int *constructorParameterTypes(int index, ArgTypeStorage *dummy, QByteArray *unknownTypeError) const; }; +QQmlPropertyRawData::Flags::Flags() + : _otherBits(0) + , isConstant(false) + , isWritable(false) + , isResettable(false) + , isAlias(false) + , isFinal(false) + , isOverridden(false) + , isDirect(false) + , type(OtherType) + , isVMEFunction(false) + , hasArguments(false) + , isSignal(false) + , isVMESignal(false) + , isV4Function(false) + , isSignalHandler(false) + , isOverload(false) + , isCloned(false) + , isConstructor(false) + , notFullyResolved(false) + , overrideIndexIsProperty(false) +{} + +bool QQmlPropertyRawData::Flags::operator==(const QQmlPropertyRawData::Flags &other) const +{ + return isConstant == other.isConstant && + isWritable == other.isWritable && + isResettable == other.isResettable && + isAlias == other.isAlias && + isFinal == other.isFinal && + isOverridden == other.isOverridden && + type == other.type && + isVMEFunction == other.isVMEFunction && + hasArguments == other.hasArguments && + isSignal == other.isSignal && + isVMESignal == other.isVMESignal && + isV4Function == other.isV4Function && + isSignalHandler == other.isSignalHandler && + isOverload == other.isOverload && + isCloned == other.isCloned && + isConstructor == other.isConstructor && + notFullyResolved == other.notFullyResolved && + overrideIndexIsProperty == other.overrideIndexIsProperty; +} + +void QQmlPropertyRawData::Flags::copyPropertyTypeFlags(QQmlPropertyRawData::Flags from) +{ + switch (from.type) { + case QObjectDerivedType: + case EnumType: + case QListType: + case QmlBindingType: + case QJSValueType: + case V4HandleType: + case QVariantType: + type = from.type; + } +} + QQmlPropertyData::QQmlPropertyData() { - propType = 0; - coreIndex = -1; - notifyIndex = -1; - overrideIndexIsProperty = false; - overrideIndex = -1; - revision = 0; - metaObjectOffset = -1; - flags = 0; + setCoreIndex(-1); + setPropType(0); + setNotifyIndex(-1); + setOverrideIndex(-1); + setRevision(0); + setMetaObjectOffset(-1); + setArguments(nullptr); + trySetStaticMetaCallFunction(nullptr, 0); } QQmlPropertyData::QQmlPropertyData(const QQmlPropertyRawData &d) @@ -479,32 +668,34 @@ QQmlPropertyData::QQmlPropertyData(const QQmlPropertyRawData &d) bool QQmlPropertyData::operator==(const QQmlPropertyRawData &other) { - return flags == other.flags && - propType == other.propType && - coreIndex == other.coreIndex && - notifyIndex == other.notifyIndex && - revision == other.revision && - (!isValueTypeVirtual() || - (valueTypeCoreIndex == other.valueTypeCoreIndex && - valueTypePropType == other.valueTypePropType)); + return flags() == other.flags() && + propType() == other.propType() && + coreIndex() == other.coreIndex() && + notifyIndex() == other.notifyIndex() && + revision() == other.revision(); } -int QQmlPropertyRawData::getValueTypeCoreIndex() const +inline QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) const { - return isValueTypeVirtual()?valueTypeCoreIndex:-1; + if (p && Q_UNLIKELY(p->notFullyResolved())) + resolve(p); + + return p; } -int QQmlPropertyRawData::encodedIndex() const +// Returns this property cache's metaObject. May be null if it hasn't been created yet. +inline const QMetaObject *QQmlPropertyCache::metaObject() const { - return isValueTypeVirtual()?QQmlPropertyData::encodeValueTypePropertyIndex(coreIndex, valueTypeCoreIndex):coreIndex; + return _metaObject; } -inline QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) const +// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by +// QML +inline const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const { - if (p && p->notFullyResolved()) - resolve(p); - - return p; + while (_parent && (_metaObject == 0 || _ownMetaObject)) + return _parent->firstCppMetaObject(); + return _metaObject; } inline QQmlPropertyData *QQmlPropertyCache::property(int index) const @@ -519,22 +710,73 @@ inline QQmlPropertyData *QQmlPropertyCache::property(int index) const return ensureResolved(rv); } +inline QQmlPropertyData *QQmlPropertyCache::method(int index) const +{ + if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count())) + return 0; + + if (index < methodIndexCacheStart) + return _parent->method(index); + + QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart)); + return ensureResolved(rv); +} + +/*! \internal + \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()). + This is different from QMetaMethod::methodIndex(). +*/ +inline QQmlPropertyData *QQmlPropertyCache::signal(int index) const +{ + if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count())) + return 0; + + if (index < signalHandlerIndexCacheStart) + return _parent->signal(index); + + QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart)); + Q_ASSERT(rv->isSignal() || rv->coreIndex() == -1); + return ensureResolved(rv); +} + +inline int QQmlPropertyCache::methodIndexToSignalIndex(int index) const +{ + if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count())) + return index; + + if (index < methodIndexCacheStart) + return _parent->methodIndexToSignalIndex(index); + + return index - methodIndexCacheStart + signalHandlerIndexCacheStart; +} + +// Returns the name of the default property for this cache +inline QString QQmlPropertyCache::defaultPropertyName() const +{ + return _defaultPropertyName; +} + +inline QQmlPropertyCache *QQmlPropertyCache::parent() const +{ + return _parent; +} + QQmlPropertyData * QQmlPropertyCache::overrideData(QQmlPropertyData *data) const { if (!data->hasOverride()) return 0; - if (data->overrideIndexIsProperty) - return property(data->overrideIndex); + if (data->overrideIndexIsProperty()) + return property(data->overrideIndex()); else - return method(data->overrideIndex); + return method(data->overrideIndex()); } bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const { - return (data->hasAccessors() || (data->metaObjectOffset == -1 && data->revision == 0)) || - (allowedRevisionCache[data->metaObjectOffset] >= data->revision); + return (data->metaObjectOffset() == -1 && data->revision() == 0) || + (allowedRevisionCache[data->metaObjectOffset()] >= data->revision()); } int QQmlPropertyCache::propertyCount() const @@ -651,6 +893,51 @@ const QMetaObject *QQmlMetaObject::metaObject() const else return _m.asT2(); } +class QQmlPropertyCacheVector +{ +public: + QQmlPropertyCacheVector() {} + QQmlPropertyCacheVector(QQmlPropertyCacheVector &&other) + : data(std::move(other.data)) {} + QQmlPropertyCacheVector &operator=(QQmlPropertyCacheVector &&other) { + QVector<QFlagPointer<QQmlPropertyCache>> moved(std::move(other.data)); + data.swap(moved); + return *this; + } + + ~QQmlPropertyCacheVector() { clear(); } + void resize(int size) { return data.resize(size); } + int count() const { return data.count(); } + void clear() + { + for (int i = 0; i < data.count(); ++i) { + if (QQmlPropertyCache *cache = data.at(i).data()) + cache->release(); + } + data.clear(); + } + + void append(QQmlPropertyCache *cache) { cache->addref(); data.append(cache); } + QQmlPropertyCache *at(int index) const { return data.at(index).data(); } + void set(int index, QQmlPropertyCache *replacement) { + if (QQmlPropertyCache *oldCache = data.at(index).data()) { + if (replacement == oldCache) + return; + oldCache->release(); + } + data[index] = replacement; + replacement->addref(); + } + + void setNeedsVMEMetaObject(int index) { data[index].setFlag(); } + bool needsVMEMetaObject(int index) const { return data.at(index).flag(); } +private: + Q_DISABLE_COPY(QQmlPropertyCacheVector) + QVector<QFlagPointer<QQmlPropertyCache>> data; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags) + QT_END_NAMESPACE #endif // QQMLPROPERTYCACHE_P_H diff --git a/src/qml/qml/qqmlpropertyindex_p.h b/src/qml/qml/qqmlpropertyindex_p.h new file mode 100644 index 0000000000..ebc1828efb --- /dev/null +++ b/src/qml/qml/qqmlpropertyindex_p.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLPROPERTYINDEX_P_H +#define QQMLPROPERTYINDEX_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qglobal_p.h> + +QT_BEGIN_NAMESPACE + +class QQmlPropertyIndex +{ + qint32 index; + +public: + QQmlPropertyIndex() + { index = -1; } + + static QQmlPropertyIndex fromEncoded(qint32 encodedIndex) + { + QQmlPropertyIndex idx; + idx.index = encodedIndex; + return idx; + } + + explicit QQmlPropertyIndex(int coreIndex) + { index = encode(coreIndex, -1); } + + explicit QQmlPropertyIndex(int coreIndex, int valueTypeIndex) + : index(encode(coreIndex, valueTypeIndex)) + {} + + bool isValid() const + { return index != -1; } + + int coreIndex() const + { + if (index == -1) + return -1; + return index & 0xffff; + } + + int valueTypeIndex() const + { + if (index == -1) + return -1; + return (index >> 16) - 1; + } + + bool hasValueTypeIndex() const + { + if (index == -1) + return false; + return index >> 16; + } + + qint32 toEncoded() const + { return index; } + + int intValue() const + { return index; } + + bool operator==(const QQmlPropertyIndex &other) const + { return index == other.index; } + + bool operator!=(const QQmlPropertyIndex &other) const + { return !operator==(other); } + +private: + static qint32 encode(int coreIndex, int valueTypeIndex) + { + Q_ASSERT(coreIndex >= -1); + Q_ASSERT(coreIndex <= 0xffff); + Q_ASSERT(valueTypeIndex >= -1); + Q_ASSERT(valueTypeIndex < 0xffff); + + if (coreIndex == -1) + return -1; + else + return coreIndex | ((valueTypeIndex + 1) << 16); + } +}; + +QT_END_NAMESPACE + +#endif // QQMLPROPERTYINDEX_P_H diff --git a/src/qml/qml/qqmlpropertyvalueinterceptor_p.h b/src/qml/qml/qqmlpropertyvalueinterceptor_p.h index 0c10d13aea..a3d6b0c8c7 100644 --- a/src/qml/qml/qqmlpropertyvalueinterceptor_p.h +++ b/src/qml/qml/qqmlpropertyvalueinterceptor_p.h @@ -52,6 +52,7 @@ // #include <private/qtqmlglobal_p.h> +#include <private/qqmlpropertyindex_p.h> #include <QtCore/qobject.h> QT_BEGIN_NAMESPACE @@ -68,8 +69,7 @@ public: private: friend class QQmlInterceptorMetaObject; - int m_coreIndex; - int m_valueTypeCoreIndex; + QQmlPropertyIndex m_propertyIndex; QQmlPropertyValueInterceptor *m_next; }; diff --git a/src/qml/qml/qqmlproxymetaobject.cpp b/src/qml/qml/qqmlproxymetaobject.cpp index bbaab1e155..27e3c13ff8 100644 --- a/src/qml/qml/qqmlproxymetaobject.cpp +++ b/src/qml/qml/qqmlproxymetaobject.cpp @@ -45,7 +45,7 @@ QT_BEGIN_NAMESPACE QQmlProxyMetaObject::QQmlProxyMetaObject(QObject *obj, QList<ProxyData> *mList) : metaObjects(mList), proxies(0), parent(0), object(obj) { - *static_cast<QMetaObject *>(this) = *metaObjects->first().metaObject; + *static_cast<QMetaObject *>(this) = *metaObjects->constFirst().metaObject; QObjectPrivate *op = QObjectPrivate::get(obj); if (op->metaObject) @@ -71,7 +71,7 @@ int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void if ((c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty) && - id >= metaObjects->last().propertyOffset) { + id >= metaObjects->constLast().propertyOffset) { for (int ii = 0; ii < metaObjects->count(); ++ii) { const ProxyData &data = metaObjects->at(ii); @@ -107,7 +107,7 @@ int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void } } } else if (c == QMetaObject::InvokeMetaMethod && - id >= metaObjects->last().methodOffset) { + id >= metaObjects->constLast().methodOffset) { QMetaMethod m = object->metaObject()->method(id); if (m.methodType() == QMetaMethod::Signal) { QMetaObject::activate(object, id, a); diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index f2f5cffbf8..09b9dcf452 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -45,14 +45,17 @@ #include <private/qqmlengine_p.h> #include <private/qqmlglobal_p.h> #include <private/qqmlthread_p.h> -#include <private/qqmlcompiler_p.h> #include <private/qqmlcomponent_p.h> #include <private/qqmlprofiler_p.h> #include <private/qqmlmemoryprofiler_p.h> #include <private/qqmltypecompiler_p.h> +#include <private/qqmlpropertyvalidator_p.h> +#include <private/qqmlpropertycachecreator_p.h> +#include <private/qdeferredcleanup_p.h> #include <QtCore/qdir.h> #include <QtCore/qfile.h> +#include <QtCore/qdatetime.h> #include <QtCore/qdebug.h> #include <QtCore/qmutex.h> #include <QtCore/qthread.h> @@ -60,8 +63,11 @@ #include <QtCore/qdiriterator.h> #include <QtQml/qqmlcomponent.h> #include <QtCore/qwaitcondition.h> +#include <QtCore/qloggingcategory.h> #include <QtQml/qqmlextensioninterface.h> +#include <functional> + #if defined (Q_OS_UNIX) #include <sys/types.h> #include <sys/stat.h> @@ -98,6 +104,11 @@ #endif DEFINE_BOOL_CONFIG_OPTION(dumpErrors, QML_DUMP_ERRORS); +DEFINE_BOOL_CONFIG_OPTION(disableDiskCache, QML_DISABLE_DISK_CACHE); +DEFINE_BOOL_CONFIG_OPTION(forceDiskCache, QML_FORCE_DISK_CACHE); + +Q_DECLARE_LOGGING_CATEGORY(DBG_DISK_CACHE) +Q_LOGGING_CATEGORY(DBG_DISK_CACHE, "qt.qml.diskcache") QT_BEGIN_NAMESPACE @@ -112,6 +123,7 @@ namespace { }; } +#if QT_CONFIG(qml_network) // This is a lame object that we need to ensure that slots connected to // QNetworkReply get called in the correct thread (the loader thread). // As QQmlTypeLoader lives in the main thread, and we can't use @@ -131,6 +143,7 @@ public slots: private: QQmlTypeLoader *l; }; +#endif // qml_network class QQmlTypeLoaderThread : public QQmlThread { @@ -138,9 +151,10 @@ class QQmlTypeLoaderThread : public QQmlThread public: QQmlTypeLoaderThread(QQmlTypeLoader *loader); +#if QT_CONFIG(qml_network) QNetworkAccessManager *networkAccessManager() const; QQmlTypeLoaderNetworkReplyProxy *networkReplyProxy() const; - +#endif // qml_network void load(QQmlDataBlob *b); void loadAsync(QQmlDataBlob *b); void loadWithStaticData(QQmlDataBlob *b, const QByteArray &); @@ -163,11 +177,13 @@ private: void initializeEngineMain(QQmlExtensionInterface *iface, const char *uri); QQmlTypeLoader *m_loader; +#if QT_CONFIG(qml_network) mutable QNetworkAccessManager *m_networkAccessManager; mutable QQmlTypeLoaderNetworkReplyProxy *m_networkReplyProxy; +#endif // qml_network }; - +#if QT_CONFIG(qml_network) QQmlTypeLoaderNetworkReplyProxy::QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l) : l(l) { @@ -196,7 +212,7 @@ void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply) l->networkReplyProgress(reply, replySize, replySize); l->networkReplyFinished(reply); } - +#endif // qml_network /*! \class QQmlDataBlob @@ -430,6 +446,39 @@ void QQmlDataBlob::setError(const QList<QQmlError> &errors) tryDone(); } +void QQmlDataBlob::setError(const QQmlCompileError &error) +{ + QQmlError e; + e.setColumn(error.location.column); + e.setLine(error.location.line); + e.setDescription(error.description); + e.setUrl(url()); + setError(e); +} + +void QQmlDataBlob::setError(const QVector<QQmlCompileError> &errors) +{ + QList<QQmlError> finalErrors; + finalErrors.reserve(errors.count()); + for (const QQmlCompileError &error: errors) { + QQmlError e; + e.setColumn(error.location.column); + e.setLine(error.location.line); + e.setDescription(error.description); + e.setUrl(url()); + finalErrors << e; + } + setError(finalErrors); +} + +void QQmlDataBlob::setError(const QString &description) +{ + QQmlError e; + e.setDescription(description); + e.setUrl(finalUrl()); + setError(e); +} + /*! Wait for \a blob to become complete or to error. If \a blob is already complete or in error, or this blob is already complete, this has no effect. @@ -480,6 +529,7 @@ void QQmlDataBlob::done() { } +#if QT_CONFIG(qml_network) /*! Invoked if there is a network error while fetching this blob. @@ -532,6 +582,7 @@ void QQmlDataBlob::networkError(QNetworkReply::NetworkError networkError) setError(error); } +#endif // qml_network /*! Called if \a blob, which was previously waited for, has an error. @@ -730,12 +781,16 @@ void QQmlDataBlob::ThreadData::setProgress(quint8 v) } QQmlTypeLoaderThread::QQmlTypeLoaderThread(QQmlTypeLoader *loader) -: m_loader(loader), m_networkAccessManager(0), m_networkReplyProxy(0) +: m_loader(loader) +#if QT_CONFIG(qml_network) +, m_networkAccessManager(0), m_networkReplyProxy(0) +#endif // qml_network { // Do that after initializing all the members. startup(); } +#if QT_CONFIG(qml_network) QNetworkAccessManager *QQmlTypeLoaderThread::networkAccessManager() const { Q_ASSERT(isThisThread()); @@ -753,6 +808,7 @@ QQmlTypeLoaderNetworkReplyProxy *QQmlTypeLoaderThread::networkReplyProxy() const Q_ASSERT(m_networkReplyProxy); // Must call networkAccessManager() first return m_networkReplyProxy; } +#endif // qml_network void QQmlTypeLoaderThread::load(QQmlDataBlob *b) { @@ -810,10 +866,12 @@ void QQmlTypeLoaderThread::initializeEngine(QQmlExtensionInterface *iface, void QQmlTypeLoaderThread::shutdownThread() { +#if QT_CONFIG(qml_network) delete m_networkAccessManager; m_networkAccessManager = 0; delete m_networkReplyProxy; m_networkReplyProxy = 0; +#endif // qml_network } void QQmlTypeLoaderThread::loadThread(QQmlDataBlob *b) @@ -899,12 +957,14 @@ void QQmlTypeLoader::invalidate() m_thread = 0; } +#if QT_CONFIG(qml_network) // Need to delete the network replies after // the loader thread is shutdown as it could be // getting new replies while we clear them for (NetworkReplies::Iterator iter = m_networkReplies.begin(); iter != m_networkReplies.end(); ++iter) (*iter)->release(); m_networkReplies.clear(); +#endif // qml_network } void QQmlTypeLoader::lock() @@ -1065,13 +1125,9 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob) QML_MEMORY_SCOPE_URL(blob->m_url); if (QQmlFile::isSynchronous(blob->m_url)) { - QQmlFile file(m_engine, blob->m_url); - - if (file.isError()) { - QQmlError error; - error.setUrl(blob->m_url); - error.setDescription(file.error()); - blob->setError(error); + const QString fileName = QQmlFile::urlToLocalFileOrQrc(blob->m_url); + if (!QQml_isFileCaseCorrect(fileName)) { + blob->setError(QLatin1String("File name case mismatch")); return; } @@ -1079,10 +1135,10 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob) if (blob->m_data.isAsync()) m_thread->callDownloadProgressChanged(blob, 1.); - setData(blob, &file); + setData(blob, fileName); } else { - +#if QT_CONFIG(qml_network) QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(blob->m_url)); QQmlTypeLoaderNetworkReplyProxy *nrp = m_thread->networkReplyProxy(); blob->addref(); @@ -1099,14 +1155,15 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob) #ifdef DATABLOB_DEBUG qWarning("QQmlDataBlob: requested %s", qPrintable(blob->url().toString())); -#endif - +#endif // DATABLOB_DEBUG +#endif // qml_network } } #define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16 #define TYPELOADER_MINIMUM_TRIM_THRESHOLD 64 +#if QT_CONFIG(qml_network) void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply) { Q_ASSERT(m_thread->isThisThread()); @@ -1162,6 +1219,7 @@ void QQmlTypeLoader::networkReplyProgress(QNetworkReply *reply, m_thread->callDownloadProgressChanged(blob, blob->m_data.progress()); } } +#endif // qml_network /*! Return the QQmlEngine associated with this loader @@ -1197,11 +1255,11 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QByteArray &data) setData(blob, d); } -void QQmlTypeLoader::setData(QQmlDataBlob *blob, QQmlFile *file) +void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QString &fileName) { QML_MEMORY_SCOPE_URL(blob->url()); QQmlDataBlob::Data d; - d.d = file; + d.d = &fileName; setData(blob, d); } @@ -1252,7 +1310,7 @@ void QQmlTypeLoader::shutdownThread() } QQmlTypeLoader::Blob::Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader) - : QQmlDataBlob(url, type, loader), m_importCache(loader), m_isSingleton(false) + : QQmlDataBlob(url, type, loader), m_importCache(loader) { } @@ -1394,13 +1452,10 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL bool incomplete = false; - QUrl qmldirUrl; - if (importQualifier.isEmpty()) { - qmldirUrl = finalUrl().resolved(QUrl(importUri + QLatin1String("/qmldir"))); - if (!QQmlImports::isLocal(qmldirUrl)) { - // This is a remote file; the import is currently incomplete - incomplete = true; - } + QUrl qmldirUrl = finalUrl().resolved(QUrl(importUri + QLatin1String("/qmldir"))); + if (!QQmlImports::isLocal(qmldirUrl)) { + // This is a remote file; the import is currently incomplete + incomplete = true; } if (!m_importCache.addFileImport(importDatabase, importUri, importQualifier, import->majorVersion, @@ -1416,51 +1471,6 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL return true; } -bool QQmlTypeLoader::Blob::addPragma(const QmlIR::Pragma &pragma, QList<QQmlError> *errors) -{ - Q_ASSERT(errors); - - if (pragma.type == QmlIR::Pragma::PragmaSingleton) { - QUrl myUrl = finalUrl(); - - QQmlType *ret = QQmlMetaType::qmlType(myUrl, true); - if (!ret) { - QQmlError error; - error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent.")); - error.setUrl(myUrl); - error.setLine(pragma.location.line); - error.setColumn(pragma.location.column); - errors->prepend(error); - return false; - } - - if (!ret->isCompositeSingleton()) { - QQmlError error; - error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(ret->qmlTypeName())); - error.setUrl(myUrl); - error.setLine(pragma.location.line); - error.setColumn(pragma.location.column); - errors->prepend(error); - return false; - } - // This flag is used for error checking when a qmldir file marks a type as - // composite singleton, but there is no pragma Singleton defined in QML. - m_isSingleton = true; - } else { - QQmlError error; - error.setDescription(QLatin1String("Invalid pragma")); - error.setUrl(finalUrl()); - error.setLine(pragma.location.line); - error.setColumn(pragma.location.column); - errors->prepend(error); - return false; - } - - return true; -} - - - void QQmlTypeLoader::Blob::dependencyError(QQmlDataBlob *blob) { if (blob->type() == QQmlDataBlob::QmldirFile) { @@ -1489,6 +1499,11 @@ void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob) } } +bool QQmlTypeLoader::Blob::isDebugging() const +{ + return QV8Engine::getV4(typeLoader()->engine())->debugger() != 0; +} + bool QQmlTypeLoader::Blob::qmldirDataAvailable(QQmlQmldirData *data, QList<QQmlError> *errors) { bool resolve = true; @@ -1951,9 +1966,11 @@ void QQmlTypeLoader::trimCache() for (TypeCache::Iterator iter = m_typeCache.begin(), end = m_typeCache.end(); iter != end; ++iter) { QQmlTypeData *typeData = iter.value(); - const bool hasError = !typeData->m_compiledData && !typeData->m_errors.isEmpty(); - const bool isNotReferenced = typeData->m_compiledData && typeData->m_compiledData->count() == 1; - if (typeData->count() == 1 && (hasError || isNotReferenced)) { + // typeData->m_compiledData may be set early on in the proccess of loading a file, so + // it's important to check the general loading status of the typeData before making any + // other decisions. + if (typeData->count() == 1 && (typeData->isError() || typeData->isComplete()) + && (!typeData->m_compiledData || typeData->m_compiledData->count() == 1)) { // There are no live objects of this type unneededTypes.append(iter); } @@ -1963,8 +1980,7 @@ void QQmlTypeLoader::trimCache() break; while (!unneededTypes.isEmpty()) { - TypeCache::Iterator iter = unneededTypes.last(); - unneededTypes.removeLast(); + TypeCache::Iterator iter = unneededTypes.takeLast(); iter.value()->release(); m_typeCache.erase(iter); @@ -1994,7 +2010,7 @@ QQmlTypeData::TypeDataCallback::~TypeDataCallback() QQmlTypeData::QQmlTypeData(const QUrl &url, QQmlTypeLoader *manager) : QQmlTypeLoader::Blob(url, QmlFile, manager), - m_typesResolved(false), m_compiledData(0), m_implicitImport(0), m_implicitImportLoaded(false) + m_typesResolved(false), m_implicitImportLoaded(false) { } @@ -2007,14 +2023,11 @@ QQmlTypeData::~QQmlTypeData() if (QQmlTypeData *tdata = m_compositeSingletons.at(ii).typeData) tdata->release(); } - for (QHash<int, TypeReference>::ConstIterator it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); + for (auto it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); it != end; ++it) { if (QQmlTypeData *tdata = it->typeData) tdata->release(); } - - if (m_compiledData) - m_compiledData->release(); } const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() const @@ -2022,19 +2035,9 @@ const QList<QQmlTypeData::ScriptReference> &QQmlTypeData::resolvedScripts() cons return m_scripts; } -const QSet<QString> &QQmlTypeData::namespaces() const -{ - return m_namespaces; -} - -const QList<QQmlTypeData::TypeReference> &QQmlTypeData::compositeSingletons() const -{ - return m_compositeSingletons; -} - -QQmlCompiledData *QQmlTypeData::compiledData() const +QV4::CompiledData::CompilationUnit *QQmlTypeData::compilationUnit() const { - return m_compiledData; + return m_compiledData.data(); } void QQmlTypeData::registerCallback(TypeDataCallback *callback) @@ -2050,10 +2053,115 @@ void QQmlTypeData::unregisterCallback(TypeDataCallback *callback) Q_ASSERT(!m_callbacks.contains(callback)); } +bool QQmlTypeData::tryLoadFromDiskCache() +{ + if (disableDiskCache() && !forceDiskCache()) + return false; + + if (isDebugging()) + return false; + + QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(typeLoader()->engine()); + if (!v4) + return false; + + QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading(); + { + QString error; + if (!unit->loadFromDisk(url(), v4->iselFactory.data(), &error)) { + qCDebug(DBG_DISK_CACHE) << "Error loading" << url().toString() << "from disk cache:" << error; + return false; + } + } + + m_compiledData = unit; + + for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i) + m_typeReferences.collectFromObject(m_compiledData->objectAt(i)); + + m_importCache.setBaseUrl(finalUrl(), finalUrlString()); + + // For remote URLs, we don't delay the loading of the implicit import + // because the loading probably requires an asynchronous fetch of the + // qmldir (so we can't load it just in time). + if (!finalUrl().scheme().isEmpty()) { + QUrl qmldirUrl = finalUrl().resolved(QUrl(QLatin1String("qmldir"))); + if (!QQmlImports::isLocal(qmldirUrl)) { + if (!loadImplicitImport()) + return false; + + // find the implicit import + for (quint32 i = 0; i < m_compiledData->data->nImports; ++i) { + const QV4::CompiledData::Import *import = m_compiledData->data->importAt(i); + if (m_compiledData->stringAt(import->uriIndex) == QLatin1String(".") + && import->qualifierIndex == 0 + && import->majorVersion == -1 + && import->minorVersion == -1) { + QList<QQmlError> errors; + if (!fetchQmldir(qmldirUrl, import, 1, &errors)) { + setError(errors); + return false; + } + break; + } + } + } + } + + for (int i = 0, count = m_compiledData->data->nImports; i < count; ++i) { + const QV4::CompiledData::Import *import = m_compiledData->data->importAt(i); + QList<QQmlError> errors; + if (!addImport(import, &errors)) { + Q_ASSERT(errors.size()); + QQmlError error(errors.takeFirst()); + error.setUrl(m_importCache.baseUrl()); + error.setLine(import->location.line); + error.setColumn(import->location.column); + errors.prepend(error); // put it back on the list after filling out information. + setError(errors); + return false; + } + } + + return true; +} + +void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &importCache, + const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache) +{ + Q_ASSERT(m_compiledData); + m_compiledData->importCache = importCache; + m_compiledData->resolvedTypes = resolvedTypeCache; + + QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine()); + + { + QQmlPropertyCacheCreator<QV4::CompiledData::CompilationUnit> propertyCacheCreator(&m_compiledData->propertyCaches, engine, m_compiledData, &m_importCache); + QQmlCompileError error = propertyCacheCreator.buildMetaObjects(); + if (error.isSet()) { + setError(error); + return; + } + } + + QQmlPropertyCacheAliasCreator<QV4::CompiledData::CompilationUnit> aliasCreator(&m_compiledData->propertyCaches, m_compiledData); + aliasCreator.appendAliasPropertiesToMetaObjects(); +} + void QQmlTypeData::done() { + QDeferredCleanup cleanup([this]{ + m_document.reset(); + m_typeReferences.clear(); + if (isError()) + m_compiledData = nullptr; + }); + + if (isError()) + return; + // Check all script dependencies for errors - for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) { + for (int ii = 0; ii < m_scripts.count(); ++ii) { const ScriptReference &script = m_scripts.at(ii); Q_ASSERT(script.script->isCompleteOrError()); if (script.script->isError()) { @@ -2065,16 +2173,17 @@ void QQmlTypeData::done() error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString())); errors.prepend(error); setError(errors); + return; } } // Check all type dependencies for errors - for (QHash<int, TypeReference>::ConstIterator it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); - !isError() && it != end; ++it) { + for (auto it = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); it != end; + ++it) { const TypeReference &type = *it; Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError()); if (type.typeData && type.typeData->isError()) { - QString typeName = m_document->stringAt(it.key()); + const QString typeName = stringAt(it.key()); QList<QQmlError> errors = type.typeData->errors(); QQmlError error; @@ -2084,11 +2193,12 @@ void QQmlTypeData::done() error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName)); errors.prepend(error); setError(errors); + return; } } // Check all composite singleton type dependencies for errors - for (int ii = 0; !isError() && ii < m_compositeSingletons.count(); ++ii) { + for (int ii = 0; ii < m_compositeSingletons.count(); ++ii) { const TypeReference &type = m_compositeSingletons.at(ii); Q_ASSERT(!type.typeData || type.typeData->isCompleteOrError()); if (type.typeData && type.typeData->isError()) { @@ -2102,27 +2212,102 @@ void QQmlTypeData::done() error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName)); errors.prepend(error); setError(errors); + return; + } + } + + QQmlRefPointer<QQmlTypeNameCache> importCache; + QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache; + { + QQmlCompileError error = buildTypeResolutionCaches(&importCache, &resolvedTypeCache); + if (error.isSet()) { + setError(error); + return; } } - // If the type is CompositeSingleton but there was no pragma Singleton in the - // QML file, lets report an error. - QQmlType *type = QQmlMetaType::qmlType(url(), true); - if (!isError() && type && type->isCompositeSingleton() && !m_isSingleton) { - QString typeName = type->qmlTypeName(); + QQmlEngine *const engine = typeLoader()->engine(); - QQmlError error; - error.setDescription(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName)); - error.setUrl(finalUrl()); - setError(error); + // verify if any dependencies changed if we're using a cache + if (m_document.isNull() && !m_compiledData->verifyChecksum(engine, resolvedTypeCache)) { + qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->url().toString(); + if (!loadFromSource()) + return; + m_backupSourceCode.clear(); + m_compiledData = nullptr; + } + + if (!m_document.isNull()) { + // Compile component + compile(importCache, resolvedTypeCache); + } else { + createTypeAndPropertyCaches(importCache, resolvedTypeCache); } - // Compile component - if (!isError()) - compile(); + if (isError()) + return; - m_document.reset(); - m_implicitImport = 0; + { + QQmlEnginePrivate *const enginePrivate = QQmlEnginePrivate::get(engine); + { + // Sanity check property bindings + QQmlPropertyValidator validator(enginePrivate, m_importCache, m_compiledData); + QVector<QQmlCompileError> errors = validator.validate(); + if (!errors.isEmpty()) { + setError(errors); + return; + } + } + + m_compiledData->finalize(enginePrivate); + } + + { + QQmlType *type = QQmlMetaType::qmlType(finalUrl(), true); + if (m_compiledData && m_compiledData->data->flags & QV4::CompiledData::Unit::IsSingleton) { + if (!type) { + QQmlError error; + error.setDescription(QQmlTypeLoader::tr("No matching type found, pragma Singleton files cannot be used by QQmlComponent.")); + setError(error); + return; + } else if (!type->isCompositeSingleton()) { + QQmlError error; + error.setDescription(QQmlTypeLoader::tr("pragma Singleton used with a non composite singleton type %1").arg(type->qmlTypeName())); + setError(error); + return; + } + } else { + // If the type is CompositeSingleton but there was no pragma Singleton in the + // QML file, lets report an error. + if (type && type->isCompositeSingleton()) { + QString typeName = type->qmlTypeName(); + setError(QQmlTypeLoader::tr("qmldir defines type as singleton, but no pragma Singleton found in type %1.").arg(typeName)); + return; + } + } + } + + { + // Collect imported scripts + m_compiledData->dependentScripts.reserve(m_scripts.count()); + for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) { + const QQmlTypeData::ScriptReference &script = m_scripts.at(scriptIndex); + + QStringRef qualifier(&script.qualifier); + QString enclosingNamespace; + + const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.')); + if (lastDotIndex != -1) { + enclosingNamespace = qualifier.left(lastDotIndex).toString(); + qualifier = qualifier.mid(lastDotIndex+1); + } + + m_compiledData->importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace); + QQmlScriptData *scriptData = script.script->scriptData(); + scriptData->addref(); + m_compiledData->dependentScripts << scriptData; + } + } } void QQmlTypeData::completed() @@ -2157,9 +2342,42 @@ bool QQmlTypeData::loadImplicitImport() void QQmlTypeData::dataReceived(const Data &data) { - QString code = QString::fromUtf8(data.data(), data.size()); + QString error; + m_backupSourceCode = data.readAll(&error, &m_sourceTimeStamp); + // if we failed to read the source code, process it _after_ we've tried + // to use the disk cache, in order to support scenarios where the source + // was removed deliberately. + + if (tryLoadFromDiskCache()) + return; + + if (isError()) + return; + + if (!error.isEmpty()) { + setError(error); + return; + } + + if (!loadFromSource()) + return; + + continueLoadFromIR(); +} + +void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) +{ + m_document.reset(new QmlIR::Document(isDebugging())); + unit->loadIR(m_document.data(), unit); + continueLoadFromIR(); +} + +bool QQmlTypeData::loadFromSource() +{ + QString code = QString::fromUtf8(m_backupSourceCode); + m_document.reset(new QmlIR::Document(isDebugging())); + m_document->jsModule.sourceTimeStamp = m_sourceTimeStamp; QQmlEngine *qmlEngine = typeLoader()->engine(); - m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger != 0)); QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames()); if (!compiler.generateFromQml(code, finalUrlString(), m_document.data())) { QList<QQmlError> errors; @@ -2173,23 +2391,14 @@ void QQmlTypeData::dataReceived(const Data &data) errors << e; } setError(errors); - return; + return false; } - - continueLoadFromIR(); -} - -void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) -{ - QQmlEngine *qmlEngine = typeLoader()->engine(); - m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger != 0)); - unit->loadIR(m_document.data(), unit); - continueLoadFromIR(); + return true; } void QQmlTypeData::continueLoadFromIR() { - m_document->collectTypeReferences(); + m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd()); m_importCache.setBaseUrl(finalUrl(), finalUrlString()); // For remote URLs, we don't delay the loading of the implicit import @@ -2202,14 +2411,14 @@ void QQmlTypeData::continueLoadFromIR() return; // This qmldir is for the implicit import QQmlJS::MemoryPool *pool = m_document->jsParserEngine.pool(); - m_implicitImport = pool->New<QV4::CompiledData::Import>(); - m_implicitImport->uriIndex = m_document->registerString(QLatin1String(".")); - m_implicitImport->qualifierIndex = 0; // empty string - m_implicitImport->majorVersion = -1; - m_implicitImport->minorVersion = -1; + auto implicitImport = pool->New<QV4::CompiledData::Import>(); + implicitImport->uriIndex = m_document->registerString(QLatin1String(".")); + implicitImport->qualifierIndex = 0; // empty string + implicitImport->majorVersion = -1; + implicitImport->minorVersion = -1; QList<QQmlError> errors; - if (!fetchQmldir(qmldirUrl, m_implicitImport, 1, &errors)) { + if (!fetchQmldir(qmldirUrl, implicitImport, 1, &errors)) { setError(errors); return; } @@ -2230,14 +2439,6 @@ void QQmlTypeData::continueLoadFromIR() return; } } - - foreach (QmlIR::Pragma *pragma, m_document->pragmas) { - if (!addPragma(*pragma, &errors)) { - Q_ASSERT(errors.size()); - setError(errors); - return; - } - } } void QQmlTypeData::allDependenciesDone() @@ -2282,20 +2483,34 @@ void QQmlTypeData::downloadProgressChanged(qreal p) QString QQmlTypeData::stringAt(int index) const { + if (m_compiledData) + return m_compiledData->stringAt(index); return m_document->jsGenerator.stringTable.stringForIndex(index); } -void QQmlTypeData::compile() +void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache) { - Q_ASSERT(m_compiledData == 0); + Q_ASSERT(m_compiledData.isNull()); - m_compiledData = new QQmlCompiledData(typeLoader()->engine()); - - QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), m_compiledData, this, m_document.data()); - if (!compiler.compile()) { + QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine()); + QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), importCache, resolvedTypeCache); + m_compiledData = compiler.compile(); + if (!m_compiledData) { setError(compiler.compilationErrors()); - m_compiledData->release(); - m_compiledData = 0; + return; + } + + const bool trySaveToDisk = (!disableDiskCache() || forceDiskCache()) && !m_document->jsModule.debugMode; + if (trySaveToDisk) { + QString errorString; + if (m_compiledData->saveToDisk(url(), &errorString)) { + QString error; + if (!m_compiledData->loadFromDisk(url(), enginePrivate->v4engine()->iselFactory.data(), &error)) { + // ignore error, keep using the in-memory compilation unit. + } + } else { + qCDebug(DBG_DISK_CACHE) << "Error saving cached version of" << m_compiledData->url().toString() << "to disk:" << errorString; + } } } @@ -2309,13 +2524,13 @@ void QQmlTypeData::resolveTypes() ScriptReference ref; //ref.location = ... - ref.qualifier = script.nameSpace; if (!script.qualifier.isEmpty()) { - ref.qualifier.prepend(script.qualifier + QLatin1Char('.')); - + ref.qualifier = script.qualifier + QLatin1Char('.') + script.nameSpace; // Add a reference to the enclosing namespace m_namespaces.insert(script.qualifier); + } else { + ref.qualifier = script.nameSpace; } ref.script = blob; @@ -2325,12 +2540,13 @@ void QQmlTypeData::resolveTypes() // Lets handle resolved composite singleton types foreach (const QQmlImports::CompositeSingletonReference &csRef, m_importCache.resolvedCompositeSingletons()) { TypeReference ref; - QString typeName = csRef.typeName; - + QString typeName; if (!csRef.prefix.isEmpty()) { - typeName.prepend(csRef.prefix + QLatin1Char('.')); + typeName = csRef.prefix + QLatin1Char('.') + csRef.typeName; // Add a reference to the enclosing namespace m_namespaces.insert(csRef.prefix); + } else { + typeName = csRef.typeName; } int majorVersion = csRef.majorVersion > -1 ? csRef.majorVersion : -1; @@ -2348,7 +2564,7 @@ void QQmlTypeData::resolveTypes() } } - for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_document->typeReferences.constBegin(), end = m_document->typeReferences.constEnd(); + for (QV4::CompiledData::TypeReferenceMap::ConstIterator unresolvedRef = m_typeReferences.constBegin(), end = m_typeReferences.constEnd(); unresolvedRef != end; ++unresolvedRef) { TypeReference ref; // resolved reference @@ -2418,6 +2634,57 @@ void QQmlTypeData::resolveTypes() } } +QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( + QQmlRefPointer<QQmlTypeNameCache> *importCache, + QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache + ) const +{ + importCache->adopt(new QQmlTypeNameCache); + + for (const QString &ns: m_namespaces) + (*importCache)->add(ns); + + // Add any Composite Singletons that were used to the import cache + for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons) + (*importCache)->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix); + + m_importCache.populateCache(*importCache); + + QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine()); + + for (auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) { + QScopedPointer<QV4::CompiledData::ResolvedTypeReference> ref(new QV4::CompiledData::ResolvedTypeReference); + QQmlType *qmlType = resolvedType->type; + if (resolvedType->typeData) { + if (resolvedType->needsCreation && qmlType->isCompositeSingleton()) { + return QQmlCompileError(resolvedType->location, tr("Composite Singleton Type %1 is not creatable.").arg(qmlType->qmlTypeName())); + } + ref->compilationUnit = resolvedType->typeData->compilationUnit(); + } else if (qmlType) { + ref->type = qmlType; + Q_ASSERT(ref->type); + + if (resolvedType->needsCreation && !ref->type->isCreatable()) { + QString reason = ref->type->noCreationReason(); + if (reason.isEmpty()) + reason = tr("Element is not creatable."); + return QQmlCompileError(resolvedType->location, reason); + } + + if (ref->type->containsRevisionedAttributes()) { + ref->typePropertyCache = engine->cache(ref->type, + resolvedType->minorVersion); + } + } + ref->majorVersion = resolvedType->majorVersion; + ref->minorVersion = resolvedType->minorVersion; + ref->doDynamicTypeCheck(); + resolvedTypeCache->insert(resolvedType.key(), ref.take()); + } + QQmlCompileError noError; + return noError; +} + bool QQmlTypeData::resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref) { QQmlImportNamespace *typeNamespace = 0; @@ -2539,10 +2806,6 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent ctxt->importedScripts = effectiveCtxt->importedScripts; } - if (ctxt->imports) { - ctxt->imports->addref(); - } - if (effectiveCtxt) { ctxt->setParent(effectiveCtxt, true); } else { @@ -2630,10 +2893,29 @@ struct EmptyCompilationUnit : public QV4::CompiledData::CompilationUnit void QQmlScriptBlob::dataReceived(const Data &data) { - QString source = QString::fromUtf8(data.data(), data.size()); - QV4::ExecutionEngine *v4 = QV8Engine::getV4(m_typeLoader->engine()); - QmlIR::Document irUnit(v4->debugger != 0); + + if (!disableDiskCache() || forceDiskCache()) { + QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading(); + QString error; + if (unit->loadFromDisk(url(), v4->iselFactory.data(), &error)) { + initializeFromCompilationUnit(unit); + return; + } else { + qCDebug(DBG_DISK_CACHE()) << "Error loading" << url().toString() << "from disk cache:" << error; + } + } + + + QmlIR::Document irUnit(isDebugging()); + + QString error; + QString source = QString::fromUtf8(data.readAll(&error, &irUnit.jsModule.sourceTimeStamp)); + if (!error.isEmpty()) { + setError(error); + return; + } + QmlIR::ScriptDirectivesCollector collector(&irUnit.jsParserEngine, &irUnit.jsGenerator); QList<QQmlError> errors; @@ -2650,14 +2932,22 @@ void QQmlScriptBlob::dataReceived(const Data &data) irUnit.javaScriptCompilationUnit = unit; irUnit.imports = collector.imports; if (collector.hasPragmaLibrary) - irUnit.unitFlags |= QV4::CompiledData::Unit::IsSharedLibrary; + irUnit.jsModule.unitFlags |= QV4::CompiledData::Unit::IsSharedLibrary; QmlIR::QmlUnitGenerator qmlGenerator; - QV4::CompiledData::Unit *unitData = qmlGenerator.generate(irUnit); + QV4::CompiledData::ResolvedTypeReferenceMap emptyDependencies; + QV4::CompiledData::Unit *unitData = qmlGenerator.generate(irUnit, m_typeLoader->engine(), emptyDependencies); Q_ASSERT(!unit->data); // The js unit owns the data and will free the qml unit. unit->data = unitData; + if (!disableDiskCache() || forceDiskCache()) { + QString errorString; + if (!unit->saveToDisk(url(), &errorString)) { + qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" << unit->url().toString() << "to disk:" << errorString; + } + } + initializeFromCompilationUnit(unit); } @@ -2668,8 +2958,11 @@ void QQmlScriptBlob::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit * void QQmlScriptBlob::done() { + if (isError()) + return; + // Check all script dependencies for errors - for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) { + for (int ii = 0; ii < m_scripts.count(); ++ii) { const ScriptReference &script = m_scripts.at(ii); Q_ASSERT(script.script->isCompleteOrError()); if (script.script->isError()) { @@ -2681,17 +2974,15 @@ void QQmlScriptBlob::done() error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->url().toString())); errors.prepend(error); setError(errors); + return; } } - if (isError()) - return; - m_scriptData->importCache = new QQmlTypeNameCache(); QSet<QString> ns; - for (int scriptIndex = 0; !isError() && scriptIndex < m_scripts.count(); ++scriptIndex) { + for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) { const ScriptReference &script = m_scripts.at(scriptIndex); m_scriptData->scripts.append(script.script); @@ -2785,7 +3076,12 @@ void QQmlQmldirData::setPriority(int priority) void QQmlQmldirData::dataReceived(const Data &data) { - m_content = QString::fromUtf8(data.data(), data.size()); + QString error; + m_content = QString::fromUtf8(data.readAll(&error)); + if (!error.isEmpty()) { + setError(error); + return; + } } void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *) @@ -2793,6 +3089,36 @@ void QQmlQmldirData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit * Q_UNIMPLEMENTED(); } +QByteArray QQmlDataBlob::Data::readAll(QString *error, qint64 *sourceTimeStamp) const +{ + Q_ASSERT(!d.isNull()); + error->clear(); + if (d.isT1()) { + if (sourceTimeStamp) + *sourceTimeStamp = 0; + return *d.asT1(); + } + QFile f(*d.asT2()); + if (!f.open(QIODevice::ReadOnly)) { + *error = f.errorString(); + return QByteArray(); + } + if (sourceTimeStamp) { + QDateTime timeStamp = QFileInfo(f).lastModified(); + // Files from the resource system do not have any time stamps, so fall back to the application + // executable. + if (!timeStamp.isValid()) + timeStamp = QFileInfo(QCoreApplication::applicationFilePath()).lastModified(); + *sourceTimeStamp = timeStamp.toMSecsSinceEpoch(); + } + QByteArray data(f.size(), Qt::Uninitialized); + if (f.read(data.data(), data.length()) != data.length()) { + *error = f.errorString(); + return QByteArray(); + } + return data; +} + QT_END_NAMESPACE #include "qqmltypeloader.moc" diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 51228eacc7..53cf4234e1 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -51,9 +51,12 @@ // We mean it. // +#include <QtQml/qtqmlglobal.h> #include <QtCore/qobject.h> #include <QtCore/qatomic.h> +#if QT_CONFIG(qml_network) #include <QtNetwork/qnetworkreply.h> +#endif #include <QtQml/qqmlerror.h> #include <QtQml/qqmlengine.h> #include <QtQml/qqmlfile.h> @@ -75,11 +78,11 @@ class QQmlScriptData; class QQmlScriptBlob; class QQmlQmldirData; class QQmlTypeLoader; -class QQmlCompiledData; class QQmlComponentPrivate; class QQmlTypeData; class QQmlTypeLoader; class QQmlExtensionInterface; +struct QQmlCompileError; namespace QmlIR { struct Document; @@ -129,34 +132,32 @@ public: class Data { public: - inline const char *data() const; - inline int size() const; - - inline QByteArray asByteArray() const; - - inline bool isFile() const; - inline QQmlFile *asFile() const; - + QByteArray readAll(QString *error, qint64 *sourceTimeStamp = 0) const; private: friend class QQmlDataBlob; friend class QQmlTypeLoader; inline Data(); Data(const Data &); Data &operator=(const Data &); - QBiPointer<const QByteArray, QQmlFile> d; + QBiPointer<const QByteArray, const QString> d; }; protected: // Can be called from within callbacks void setError(const QQmlError &); void setError(const QList<QQmlError> &errors); + void setError(const QQmlCompileError &error); + void setError(const QVector<QQmlCompileError> &errors); + void setError(const QString &description); void addDependency(QQmlDataBlob *); // Callbacks made in load thread virtual void dataReceived(const Data &) = 0; virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit*) = 0; virtual void done(); +#if QT_CONFIG(qml_network) virtual void networkError(QNetworkReply::NetworkError); +#endif virtual void dependencyError(QQmlDataBlob *); virtual void dependencyComplete(QQmlDataBlob *); virtual void allDependenciesDone(); @@ -233,7 +234,6 @@ public: protected: bool addImport(const QV4::CompiledData::Import *import, QList<QQmlError> *errors); - bool addPragma(const QmlIR::Pragma &pragma, QList<QQmlError> *errors); bool fetchQmldir(const QUrl &url, const QV4::CompiledData::Import *import, int priority, QList<QQmlError> *errors); bool updateQmldir(QQmlQmldirData *data, const QV4::CompiledData::Import *import, QList<QQmlError> *errors); @@ -249,8 +249,9 @@ public: protected: virtual QString stringAt(int) const { return QString(); } + bool isDebugging() const; + QQmlImports m_importCache; - bool m_isSingleton; QHash<const QV4::CompiledData::Import*, int> m_unresolvedImports; QList<QQmlQmldirData *> m_qmldirs; }; @@ -320,20 +321,24 @@ public: private: friend class QQmlDataBlob; friend class QQmlTypeLoaderThread; +#if QT_CONFIG(qml_network) friend class QQmlTypeLoaderNetworkReplyProxy; +#endif // qml_network void shutdownThread(); void loadThread(QQmlDataBlob *); void loadWithStaticDataThread(QQmlDataBlob *, const QByteArray &); void loadWithCachedUnitThread(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit); +#if QT_CONFIG(qml_network) void networkReplyFinished(QNetworkReply *); void networkReplyProgress(QNetworkReply *, qint64, qint64); typedef QHash<QNetworkReply *, QQmlDataBlob *> NetworkReplies; +#endif void setData(QQmlDataBlob *, const QByteArray &); - void setData(QQmlDataBlob *, QQmlFile *); + void setData(QQmlDataBlob *, const QString &fileName); void setData(QQmlDataBlob *, const QQmlDataBlob::Data &); void setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit); @@ -362,7 +367,9 @@ private: QQmlEngine *m_engine; QQmlTypeLoaderThread *m_thread; +#if QT_CONFIG(qml_network) NetworkReplies m_networkReplies; +#endif TypeCache m_typeCache; int m_typeCacheTrimThreshold; ScriptCache m_scriptCache; @@ -381,6 +388,7 @@ private: class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob { + Q_DECLARE_TR_FUNCTIONS(QQmlTypeData) public: struct TypeReference { @@ -412,13 +420,9 @@ private: public: ~QQmlTypeData(); - const QHash<int, TypeReference> &resolvedTypeRefs() const { return m_resolvedTypes; } - const QList<ScriptReference> &resolvedScripts() const; - const QSet<QString> &namespaces() const; - const QList<TypeReference> &compositeSingletons() const; - QQmlCompiledData *compiledData() const; + QV4::CompiledData::CompilationUnit *compilationUnit() const; // Used by QQmlComponent to get notifications struct TypeDataCallback { @@ -440,14 +444,27 @@ protected: virtual QString stringAt(int index) const; private: + bool tryLoadFromDiskCache(); + bool loadFromSource(); void continueLoadFromIR(); void resolveTypes(); - void compile(); + QQmlCompileError buildTypeResolutionCaches( + QQmlRefPointer<QQmlTypeNameCache> *importCache, + QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache + ) const; + void compile(const QQmlRefPointer<QQmlTypeNameCache> &importCache, + const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache); + void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &importCache, + const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache); bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref); virtual void scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace); + + qint64 m_sourceTimeStamp = 0; + QByteArray m_backupSourceCode; // used when cache verification fails. QScopedPointer<QmlIR::Document> m_document; + QV4::CompiledData::TypeReferenceMap m_typeReferences; QList<ScriptReference> m_scripts; @@ -455,14 +472,15 @@ private: QList<TypeReference> m_compositeSingletons; // map from name index to resolved type - QHash<int, TypeReference> m_resolvedTypes; + // While this could be a hash, a map is chosen here to provide a stable + // order, which is used to calculating a check-sum on dependent meta-objects. + QMap<int, TypeReference> m_resolvedTypes; bool m_typesResolved:1; - QQmlCompiledData *m_compiledData; + QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compiledData; QList<TypeDataCallback *> m_callbacks; - QV4::CompiledData::Import *m_implicitImport; bool m_implicitImportLoaded; bool loadImplicitImport(); }; @@ -572,40 +590,7 @@ QQmlDataBlob::Data::Data() { } -const char *QQmlDataBlob::Data::data() const -{ - Q_ASSERT(!d.isNull()); - - if (d.isT1()) return d.asT1()->constData(); - else return d.asT2()->data(); -} - -int QQmlDataBlob::Data::size() const -{ - Q_ASSERT(!d.isNull()); - - if (d.isT1()) return d.asT1()->size(); - else return d.asT2()->size(); -} - -bool QQmlDataBlob::Data::isFile() const -{ - return d.isT2(); -} -QByteArray QQmlDataBlob::Data::asByteArray() const -{ - Q_ASSERT(!d.isNull()); - - if (d.isT1()) return *d.asT1(); - else return d.asT2()->dataByteArray(); -} - -QQmlFile *QQmlDataBlob::Data::asFile() const -{ - if (d.isT2()) return d.asT2(); - else return 0; -} QT_END_NAMESPACE diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 7892555f08..5c3ad6b2a6 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -55,15 +55,19 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(QmlTypeWrapper); -Heap::QmlTypeWrapper::QmlTypeWrapper() - : mode(IncludeEnums) +void Heap::QmlTypeWrapper::init() { + Object::init(); + mode = IncludeEnums; + object.init(); } -Heap::QmlTypeWrapper::~QmlTypeWrapper() +void Heap::QmlTypeWrapper::destroy() { if (typeNamespace) typeNamespace->release(); + object.destroy(); + Object::destroy(); } bool QmlTypeWrapper::isSingleton() const diff --git a/src/qml/qml/qqmltypewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h index 8216526cb5..3b0ae04cc1 100644 --- a/src/qml/qml/qqmltypewrapper_p.h +++ b/src/qml/qml/qqmltypewrapper_p.h @@ -71,10 +71,10 @@ struct QmlTypeWrapper : Object { ExcludeEnums }; - QmlTypeWrapper(); - ~QmlTypeWrapper(); + void init(); + void destroy(); TypeNameMode mode; - QPointer<QObject> object; + QQmlQPointer<QObject> object; QQmlType *type; QQmlTypeNameCache *typeNamespace; diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp index 44fd47244d..bcefad0ee3 100644 --- a/src/qml/qml/qqmlvaluetype.cpp +++ b/src/qml/qml/qqmlvaluetype.cpp @@ -88,6 +88,7 @@ bool QQmlValueTypeFactoryImpl::isValueType(int idx) && idx != QVariant::StringList && idx != QMetaType::QObjectStar && idx != QMetaType::VoidStar + && idx != QMetaType::Nullptr && idx != QMetaType::QVariant && idx != QMetaType::QLocale) { return true; @@ -219,7 +220,7 @@ void QQmlValueType::read(QObject *obj, int idx) QMetaObject::metacall(obj, QMetaObject::ReadProperty, idx, a); } -void QQmlValueType::write(QObject *obj, int idx, QQmlPropertyPrivate::WriteFlags flags) +void QQmlValueType::write(QObject *obj, int idx, QQmlPropertyData::WriteFlags flags) { Q_ASSERT(gadgetPtr); int status = -1; @@ -259,7 +260,7 @@ int QQmlValueType::metaCall(QObject *, QMetaObject::Call type, int _id, void **a QString QQmlPointFValueType::toString() const { - return QString(QLatin1String("QPointF(%1, %2)")).arg(v.x()).arg(v.y()); + return QString::asprintf("QPointF(%g, %g)", v.x(), v.y()); } qreal QQmlPointFValueType::x() const @@ -306,7 +307,7 @@ void QQmlPointValueType::setY(int y) QString QQmlSizeFValueType::toString() const { - return QString(QLatin1String("QSizeF(%1, %2)")).arg(v.width()).arg(v.height()); + return QString::asprintf("QSizeF(%g, %g)", v.width(), v.height()); } qreal QQmlSizeFValueType::width() const @@ -352,7 +353,7 @@ void QQmlSizeValueType::setHeight(int h) QString QQmlRectFValueType::toString() const { - return QString(QLatin1String("QRectF(%1, %2, %3, %4)")).arg(v.x()).arg(v.y()).arg(v.width()).arg(v.height()); + return QString::asprintf("QRectF(%g, %g, %g, %g)", v.x(), v.y(), v.width(), v.height()); } qreal QQmlRectFValueType::x() const diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h index 910d39cf0a..11e1dfdb00 100644 --- a/src/qml/qml/qqmlvaluetype_p.h +++ b/src/qml/qml/qqmlvaluetype_p.h @@ -69,7 +69,7 @@ public: QQmlValueType(int userType, const QMetaObject *metaObject); ~QQmlValueType(); void read(QObject *, int); - void write(QObject *, int, QQmlPropertyPrivate::WriteFlags flags); + void write(QObject *, int, QQmlPropertyData::WriteFlags flags); QVariant value(); void setValue(const QVariant &); diff --git a/src/qml/qml/qqmlvaluetypeproxybinding.cpp b/src/qml/qml/qqmlvaluetypeproxybinding.cpp index 6858215a79..56f073121e 100644 --- a/src/qml/qml/qqmlvaluetypeproxybinding.cpp +++ b/src/qml/qml/qqmlvaluetypeproxybinding.cpp @@ -41,7 +41,7 @@ QT_BEGIN_NAMESPACE -QQmlValueTypeProxyBinding::QQmlValueTypeProxyBinding(QObject *o, int index) +QQmlValueTypeProxyBinding::QQmlValueTypeProxyBinding(QObject *o, QQmlPropertyIndex index) : QQmlAbstractBinding(), m_bindings(0) { @@ -58,7 +58,7 @@ QQmlValueTypeProxyBinding::~QQmlValueTypeProxyBinding() } } -void QQmlValueTypeProxyBinding::setEnabled(bool e, QQmlPropertyPrivate::WriteFlags flags) +void QQmlValueTypeProxyBinding::setEnabled(bool e, QQmlPropertyData::WriteFlags flags) { QQmlAbstractBinding *b = m_bindings.data(); while (b) { @@ -72,7 +72,7 @@ bool QQmlValueTypeProxyBinding::isValueTypeProxy() const return true; } -QQmlAbstractBinding *QQmlValueTypeProxyBinding::binding(int propertyIndex) +QQmlAbstractBinding *QQmlValueTypeProxyBinding::binding(QQmlPropertyIndex propertyIndex) { QQmlAbstractBinding *binding = m_bindings.data(); @@ -91,7 +91,7 @@ void QQmlValueTypeProxyBinding::removeBindings(quint32 mask) QQmlAbstractBinding *lastBinding = 0; while (binding) { - int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(binding->targetPropertyIndex()); + const int valueTypeIndex = binding->targetPropertyIndex().valueTypeIndex(); if (valueTypeIndex != -1 && (mask & (1 << valueTypeIndex))) { QQmlAbstractBinding *remove = binding; remove->setAddedToObject(false); diff --git a/src/qml/qml/qqmlvaluetypeproxybinding_p.h b/src/qml/qml/qqmlvaluetypeproxybinding_p.h index de5acc2984..9a487d6992 100644 --- a/src/qml/qml/qqmlvaluetypeproxybinding_p.h +++ b/src/qml/qml/qqmlvaluetypeproxybinding_p.h @@ -58,12 +58,12 @@ QT_BEGIN_NAMESPACE class QQmlValueTypeProxyBinding : public QQmlAbstractBinding { public: - QQmlValueTypeProxyBinding(QObject *o, int coreIndex); + QQmlValueTypeProxyBinding(QObject *o, QQmlPropertyIndex coreIndex); - QQmlAbstractBinding *binding(int targetPropertyIndex); + QQmlAbstractBinding *binding(QQmlPropertyIndex targetPropertyIndex); void removeBindings(quint32 mask); - virtual void setEnabled(bool, QQmlPropertyPrivate::WriteFlags); + virtual void setEnabled(bool, QQmlPropertyData::WriteFlags); virtual bool isValueTypeProxy() const; protected: diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp index 04a556f46c..b23bc033d1 100644 --- a/src/qml/qml/qqmlvaluetypewrapper.cpp +++ b/src/qml/qml/qqmlvaluetypewrapper.cpp @@ -50,6 +50,7 @@ #include <private/qv4functionobject_p.h> #include <private/qv4variantobject_p.h> #include <private/qv4alloca_p.h> +#include <private/qv4objectiterator_p.h> #include <private/qv4qobjectwrapper_p.h> QT_BEGIN_NAMESPACE @@ -62,8 +63,15 @@ namespace Heap { struct QQmlValueTypeReference : QQmlValueTypeWrapper { - QQmlValueTypeReference() {} - QPointer<QObject> object; + void init() { + QQmlValueTypeWrapper::init(); + object.init(); + } + void destroy() { + object.destroy(); + QQmlValueTypeWrapper::destroy(); + } + QQmlQPointer<QObject> object; int property; }; @@ -72,8 +80,7 @@ struct QQmlValueTypeReference : QQmlValueTypeWrapper struct QQmlValueTypeReference : public QQmlValueTypeWrapper { V4_OBJECT2(QQmlValueTypeReference, QQmlValueTypeWrapper) - - static void destroy(Heap::Base *that); + V4_NEEDS_DESTROY bool readReferenceValue() const; }; @@ -84,12 +91,13 @@ DEFINE_OBJECT_VTABLE(QV4::QQmlValueTypeReference); using namespace QV4; -Heap::QQmlValueTypeWrapper::~QQmlValueTypeWrapper() +void Heap::QQmlValueTypeWrapper::destroy() { if (gadgetPtr) { valueType->metaType.destruct(gadgetPtr); ::operator delete(gadgetPtr); } + Object::destroy(); } void Heap::QQmlValueTypeWrapper::setValue(const QVariant &value) const @@ -138,7 +146,7 @@ bool QQmlValueTypeReference::readReferenceValue() const ::operator delete(d()->gadgetPtr); } d()->gadgetPtr =0; - d()->propertyCache = cache; + d()->setPropertyCache(cache); d()->valueType = QQmlValueTypeFactory::valueType(variantReferenceType); if (!cache) return false; @@ -161,7 +169,7 @@ bool QQmlValueTypeReference::readReferenceValue() const void QQmlValueTypeWrapper::initProto(ExecutionEngine *v4) { - if (v4->valueTypeWrapperPrototype()->d()) + if (v4->valueTypeWrapperPrototype()->d_unchecked()) return; Scope scope(v4); @@ -178,7 +186,7 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, QObject *obj Scoped<QQmlValueTypeReference> r(scope, engine->memoryManager->allocObject<QQmlValueTypeReference>()); r->d()->object = object; r->d()->property = property; - r->d()->propertyCache = QJSEnginePrivate::get(engine)->cache(metaObject); + r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject)); r->d()->valueType = QQmlValueTypeFactory::valueType(typeId); r->d()->gadgetPtr = 0; return r->asReturnedValue(); @@ -190,7 +198,7 @@ ReturnedValue QQmlValueTypeWrapper::create(ExecutionEngine *engine, const QVaria initProto(engine); Scoped<QQmlValueTypeWrapper> r(scope, engine->memoryManager->allocObject<QQmlValueTypeWrapper>()); - r->d()->propertyCache = QJSEnginePrivate::get(engine)->cache(metaObject); + r->d()->setPropertyCache(QJSEnginePrivate::get(engine)->cache(metaObject)); r->d()->valueType = QQmlValueTypeFactory::valueType(typeId); r->d()->gadgetPtr = 0; r->d()->setValue(value); @@ -216,19 +224,13 @@ bool QQmlValueTypeWrapper::toGadget(void *data) const return true; } -void QQmlValueTypeWrapper::destroy(Heap::Base *that) -{ - Heap::QQmlValueTypeWrapper *w = static_cast<Heap::QQmlValueTypeWrapper *>(that); - w->Heap::QQmlValueTypeWrapper::~QQmlValueTypeWrapper(); -} - bool QQmlValueTypeWrapper::isEqualTo(Managed *m, Managed *other) { Q_ASSERT(m && m->as<QQmlValueTypeWrapper>() && other); QV4::QQmlValueTypeWrapper *lv = static_cast<QQmlValueTypeWrapper *>(m); if (QV4::VariantObject *rv = other->as<VariantObject>()) - return lv->isEqual(rv->d()->data); + return lv->isEqual(rv->d()->data()); if (QV4::QQmlValueTypeWrapper *v = other->as<QQmlValueTypeWrapper>()) return lv->isEqual(v->toVariant()); @@ -241,10 +243,38 @@ PropertyAttributes QQmlValueTypeWrapper::query(const Managed *m, String *name) Q_ASSERT(m->as<const QQmlValueTypeWrapper>()); const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m); - QQmlPropertyData *result = r->d()->propertyCache->property(name, 0, 0); + QQmlPropertyData *result = r->d()->propertyCache()->property(name, 0, 0); return result ? Attr_Data : Attr_Invalid; } +void QQmlValueTypeWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes) +{ + name->setM(0); + *index = UINT_MAX; + + QQmlValueTypeWrapper *that = static_cast<QQmlValueTypeWrapper*>(m); + + if (QQmlValueTypeReference *ref = that->as<QQmlValueTypeReference>()) { + if (!ref->readReferenceValue()) + return; + } + + if (that->d()->propertyCache()) { + const QMetaObject *mo = that->d()->propertyCache()->createMetaObject(); + const int propertyCount = mo->propertyCount(); + if (it->arrayIndex < static_cast<uint>(propertyCount)) { + Scope scope(that->engine()); + ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name()))); + name->setM(propName->d()); + ++it->arrayIndex; + *attributes = QV4::Attr_Data; + p->value = that->QV4::Object::get(propName); + return; + } + } + QV4::Object::advanceIterator(m, it, name, index, p, attributes); +} + bool QQmlValueTypeWrapper::isEqual(const QVariant& value) { if (QQmlValueTypeReference *ref = as<QQmlValueTypeReference>()) @@ -303,9 +333,9 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx) if (QMetaType::convert(w->d()->gadgetPtr, w->d()->valueType->typeId, &convertResult, QMetaType::QString)) { result = convertResult; } else { - result = QString::fromUtf8(QMetaType::typeName(w->d()->valueType->typeId)); - result += QLatin1Char('('); - const QMetaObject *mo = w->d()->propertyCache->metaObject(); + result += QString::fromUtf8(QMetaType::typeName(w->d()->valueType->typeId)) + + QLatin1Char('('); + const QMetaObject *mo = w->d()->propertyCache()->metaObject(); const int propCount = mo->propertyCount(); for (int i = 0; i < propCount; ++i) { if (mo->property(i).isDesignable()) { @@ -332,7 +362,7 @@ ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *ha return Primitive::undefinedValue().asReturnedValue(); } - QQmlPropertyData *result = r->d()->propertyCache->property(name, 0, 0); + QQmlPropertyData *result = r->d()->propertyCache()->property(name, 0, 0); if (!result) return Object::get(m, name, hasProperty); @@ -341,19 +371,19 @@ ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *ha if (result->isFunction()) // calling a Q_INVOKABLE function of a value type - return QV4::QObjectMethod::create(v4->rootContext(), r, result->coreIndex); + return QV4::QObjectMethod::create(v4->rootContext(), r, result->coreIndex()); #define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \ - if (result->propType == metatype) { \ + if (result->propType() == metatype) { \ cpptype v; \ void *args[] = { &v, 0 }; \ metaObject->d.static_metacall(reinterpret_cast<QObject*>(gadget), QMetaObject::ReadProperty, index, args); \ return QV4::Encode(constructor(v)); \ } - const QMetaObject *metaObject = r->d()->propertyCache->metaObject(); + const QMetaObject *metaObject = r->d()->propertyCache()->metaObject(); - int index = result->coreIndex; + int index = result->coreIndex(); QQmlMetaObject::resolveGadgetMethodOrPropertyIndex(QMetaObject::ReadProperty, &metaObject, &index); void *gadget = r->d()->gadgetPtr; @@ -366,10 +396,10 @@ ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *ha QVariant v; void *args[] = { Q_NULLPTR, Q_NULLPTR }; - if (result->propType == QMetaType::QVariant) { + if (result->propType() == QMetaType::QVariant) { args[0] = &v; } else { - v = QVariant(result->propType, static_cast<void *>(Q_NULLPTR)); + v = QVariant(result->propType(), static_cast<void *>(Q_NULLPTR)); args[0] = v.data(); } metaObject->d.static_metacall(reinterpret_cast<QObject*>(gadget), QMetaObject::ReadProperty, index, args); @@ -399,12 +429,10 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) writeBackPropertyType = writebackProperty.userType(); } - const QMetaObject *metaObject = r->d()->propertyCache->metaObject(); - const QQmlPropertyData *pd = r->d()->propertyCache->property(name, 0, 0); + const QMetaObject *metaObject = r->d()->propertyCache()->metaObject(); + const QQmlPropertyData *pd = r->d()->propertyCache()->property(name, 0, 0); if (!pd) return; - QMetaProperty property = metaObject->property(pd->coreIndex); - Q_ASSERT(property.isValid()); if (reference) { QV4::ScopedFunctionObject f(scope, value); @@ -420,27 +448,24 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) QQmlContextData *context = v4->callingQmlContext(); QQmlPropertyData cacheData; - cacheData.setFlags(QQmlPropertyData::IsWritable | - QQmlPropertyData::IsValueTypeVirtual); - cacheData.propType = writeBackPropertyType; - cacheData.coreIndex = reference->d()->property; - cacheData.valueTypeFlags = 0; - cacheData.valueTypeCoreIndex = pd->coreIndex; - cacheData.valueTypePropType = property.userType(); + cacheData.setWritable(true); + cacheData.setPropType(writeBackPropertyType); + cacheData.setCoreIndex(reference->d()->property); QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); bindingFunction->initBindingLocation(); - QQmlBinding *newBinding = new QQmlBinding(value, reference->d()->object, context); - newBinding->setTarget(reference->d()->object, cacheData); + QQmlBinding *newBinding = QQmlBinding::create(&cacheData, value, reference->d()->object, context); + newBinding->setTarget(reference->d()->object, cacheData, pd); QQmlPropertyPrivate::setBinding(newBinding); return; } else { - QQmlPropertyPrivate::removeBinding(reference->d()->object, QQmlPropertyData::encodeValueTypePropertyIndex(reference->d()->property, pd->coreIndex)); - + QQmlPropertyPrivate::removeBinding(reference->d()->object, QQmlPropertyIndex(reference->d()->property, pd->coreIndex())); } } + QMetaProperty property = metaObject->property(pd->coreIndex()); + Q_ASSERT(property.isValid()); QVariant v = v4->toVariant(value, property.userType()); @@ -469,9 +494,4 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) } } -void QQmlValueTypeReference::destroy(Heap::Base *that) -{ - static_cast<Heap::QQmlValueTypeReference*>(that)->Heap::QQmlValueTypeReference::~QQmlValueTypeReference(); -} - QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h index c2861f5bfa..b8ca5a16f4 100644 --- a/src/qml/qml/qqmlvaluetypewrapper_p.h +++ b/src/qml/qml/qqmlvaluetypewrapper_p.h @@ -66,14 +66,24 @@ namespace QV4 { namespace Heap { struct QQmlValueTypeWrapper : Object { - QQmlValueTypeWrapper() {} - ~QQmlValueTypeWrapper(); - QQmlRefPointer<QQmlPropertyCache> propertyCache; + void init() { Object::init(); } + void destroy(); + QQmlPropertyCache *propertyCache() const { return _propertyCache; } + void setPropertyCache(QQmlPropertyCache *c) { + if (c) + c->addref(); + if (_propertyCache) + _propertyCache->release(); + _propertyCache = c; + } mutable void *gadgetPtr; QQmlValueType *valueType; void setValue(const QVariant &value) const; QVariant toVariant() const; + +private: + QQmlPropertyCache *_propertyCache; }; } @@ -82,7 +92,7 @@ struct Q_QML_EXPORT QQmlValueTypeWrapper : Object { V4_OBJECT2(QQmlValueTypeWrapper, Object) V4_PROTOTYPE(valueTypeWrapperPrototype) - static void destroy(Heap::Base *b); + V4_NEEDS_DESTROY public: @@ -99,6 +109,7 @@ public: static void put(Managed *m, String *name, const Value &value); static bool isEqualTo(Managed *m, Managed *other); static PropertyAttributes query(const Managed *, String *name); + static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); static QV4::ReturnedValue method_toString(CallContext *ctx); diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp index 5f9fa69944..01c4f476d6 100644 --- a/src/qml/qml/qqmlvme.cpp +++ b/src/qml/qml/qqmlvme.cpp @@ -39,7 +39,6 @@ #include "qqmlvme_p.h" -#include "qqmlcompiler_p.h" #include "qqmlboundsignal_p.h" #include "qqmlstringconverters_p.h" #include <private/qmetaobjectbuilder_p.h> diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h index ac9db5c046..99d63380ad 100644 --- a/src/qml/qml/qqmlvme_p.h +++ b/src/qml/qml/qqmlvme_p.h @@ -69,7 +69,6 @@ QT_BEGIN_NAMESPACE class QObject; class QJSValue; class QQmlScriptData; -class QQmlCompiledData; class QQmlContextData; namespace QQmlVMETypes { @@ -84,10 +83,9 @@ namespace QQmlVMETypes { struct State { enum Flag { Deferred = 0x00000001 }; - State() : flags(0), context(0), compiledData(0), instructionStream(0) {} + State() : flags(0), context(0), instructionStream(0) {} quint32 flags; QQmlContextData *context; - QQmlCompiledData *compiledData; const char *instructionStream; QBitField bindingSkipList; }; diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 775309d04a..b08a0e5087 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -59,6 +59,32 @@ QT_BEGIN_NAMESPACE +static void list_append(QQmlListProperty<QObject> *prop, QObject *o) +{ + QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data); + list->append(o); + static_cast<QQmlVMEMetaObject *>(prop->dummy1)->activate(prop->object, reinterpret_cast<quintptr>(prop->dummy2), 0); +} + +static int list_count(QQmlListProperty<QObject> *prop) +{ + QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data); + return list->count(); +} + +static QObject *list_at(QQmlListProperty<QObject> *prop, int index) +{ + QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data); + return list->at(index); +} + +static void list_clear(QQmlListProperty<QObject> *prop) +{ + QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data); + list->clear(); + static_cast<QQmlVMEMetaObject *>(prop->dummy1)->activate(prop->object, reinterpret_cast<quintptr>(prop->dummy2), 0); +} + QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr() : QQmlGuard<QObject>(0), m_target(0), m_index(-1) { @@ -74,10 +100,10 @@ void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *) return; if (m_index >= 0) { - QV4::ExecutionEngine *v4 = m_target->properties.engine(); + QV4::ExecutionEngine *v4 = m_target->propertyAndMethodStorage.engine(); if (v4) { QV4::Scope scope(v4); - QV4::Scoped<QV4::MemberData> sp(scope, m_target->properties.value()); + QV4::Scoped<QV4::MemberData> sp(scope, m_target->propertyAndMethodStorage.value()); if (sp) *(sp->data() + m_index) = QV4::Primitive::nullValue(); } @@ -115,22 +141,31 @@ void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *e, void **) void QQmlVMEMetaObjectEndpoint::tryConnect() { + Q_ASSERT(metaObject->compiledObject); int aliasId = this - metaObject->aliasEndpoints; if (metaObject.flag()) { // This is actually notify - int sigIdx = metaObject->methodOffset() + aliasId + metaObject->metaData->propertyCount; + int sigIdx = metaObject->methodOffset() + aliasId + metaObject->compiledObject->nProperties; metaObject->activate(metaObject->object, sigIdx, 0); } else { - QQmlVMEMetaData::AliasData *d = metaObject->metaData->aliasData() + aliasId; - if (!d->isObjectAlias()) { + const QV4::CompiledData::Alias *aliasData = &metaObject->compiledObject->aliasTable()[aliasId]; + if (!aliasData->isObjectAlias()) { QQmlContextData *ctxt = metaObject->ctxt; - QObject *target = ctxt->idValues[d->contextIdx].data(); + QObject *target = ctxt->idValues[aliasData->targetObjectId].data(); if (!target) return; - if (d->notifySignal != -1) - connect(target, d->notifySignal, ctxt->engine); + QQmlData *targetDData = QQmlData::get(target, /*create*/false); + if (!targetDData) + return; + int coreIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex).coreIndex(); + const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex); + if (!pd) + return; + + if (pd->notifyIndex() != -1) + connect(target, pd->notifyIndex(), ctxt->engine); } metaObject.setFlag(); @@ -163,10 +198,9 @@ QQmlInterceptorMetaObject::~QQmlInterceptorMetaObject() } -void QQmlInterceptorMetaObject::registerInterceptor(int index, int valueIndex, QQmlPropertyValueInterceptor *interceptor) +void QQmlInterceptorMetaObject::registerInterceptor(QQmlPropertyIndex index, QQmlPropertyValueInterceptor *interceptor) { - interceptor->m_coreIndex = index; - interceptor->m_valueTypeCoreIndex = valueIndex; + interceptor->m_propertyIndex = index; interceptor->m_next = interceptors; interceptors = interceptor; } @@ -184,14 +218,14 @@ int QQmlInterceptorMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a) { if (c == QMetaObject::WriteProperty && interceptors && - !(*reinterpret_cast<int*>(a[3]) & QQmlPropertyPrivate::BypassInterceptor)) { + !(*reinterpret_cast<int*>(a[3]) & QQmlPropertyData::BypassInterceptor)) { for (QQmlPropertyValueInterceptor *vi = interceptors; vi; vi = vi->m_next) { - if (vi->m_coreIndex != id) + if (vi->m_propertyIndex.coreIndex() != id) continue; - int valueIndex = vi->m_valueTypeCoreIndex; - int type = QQmlData::get(object)->propertyCache->property(id)->propType; + const int valueIndex = vi->m_propertyIndex.valueTypeIndex(); + int type = QQmlData::get(object)->propertyCache->property(id)->propType(); if (type != QVariant::Invalid) { if (valueIndex != -1) { @@ -242,7 +276,7 @@ bool QQmlInterceptorMetaObject::intercept(QMetaObject::Call c, int id, void **a) bool updated = false; if (newComponentValue != prevComponentValue) { valueProp.write(valueType, prevComponentValue); - valueType->write(object, id, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor); + valueType->write(object, id, QQmlPropertyData::DontRemoveBinding | QQmlPropertyData::BypassInterceptor); vi->write(newComponentValue); updated = true; @@ -278,136 +312,124 @@ QAbstractDynamicMetaObject *QQmlInterceptorMetaObject::toDynamicMetaObject(QObje } QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj, - QQmlPropertyCache *cache, - const QQmlVMEMetaData *meta) + QQmlPropertyCache *cache, QV4::CompiledData::CompilationUnit *qmlCompilationUnit, int qmlObjectId) : QQmlInterceptorMetaObject(obj, cache), - ctxt(QQmlData::get(obj, true)->outerContext), metaData(meta), - aliasEndpoints(0), - methods(0) + ctxt(QQmlData::get(obj, true)->outerContext), + aliasEndpoints(0), compilationUnit(qmlCompilationUnit), compiledObject(0) { - cache->addref(); - QQmlData::get(obj)->hasVMEMetaObject = true; - int qobject_type = qMetaTypeId<QObject*>(); - int variant_type = qMetaTypeId<QVariant>(); - // Need JS wrapper to ensure properties are marked. - // ### FIXME: I hope that this can be removed once we have the proper scope chain - // set up and the JS wrappers always exist. - bool needsJSWrapper = (metaData->propertyCount > 0); - - // ### Optimize - for (int ii = 0; ii < metaData->propertyCount; ++ii) { - int t = (metaData->propertyData() + ii)->propertyType; - if (t == qobject_type || t == variant_type) { - needsJSWrapper = true; - break; + if (compilationUnit && qmlObjectId >= 0) { + compiledObject = compilationUnit->data->objectAt(qmlObjectId); + + if (compiledObject->nProperties || compiledObject->nFunctions) { + Q_ASSERT(cache && cache->engine); + QV4::ExecutionEngine *v4 = cache->engine; + QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, compiledObject->nProperties + compiledObject->nFunctions); + propertyAndMethodStorage.set(v4, data); + std::fill(data->data, data->data + data->size, QV4::Encode::undefined()); + + // Need JS wrapper to ensure properties/methods are marked. + ensureQObjectWrapper(); } } - - if (needsJSWrapper) - ensureQObjectWrapper(); } QQmlVMEMetaObject::~QQmlVMEMetaObject() { if (parent.isT1()) parent.asT1()->objectDestroyed(object); delete [] aliasEndpoints; - delete [] methods; qDeleteAll(varObjectGuards); - - cache->release(); } -QV4::MemberData *QQmlVMEMetaObject::propertiesAsMemberData() +QV4::MemberData *QQmlVMEMetaObject::propertyAndMethodStorageAsMemberData() { - if (properties.isUndefined()) { - if (properties.valueRef()) + if (propertyAndMethodStorage.isUndefined()) { + if (propertyAndMethodStorage.valueRef()) // in some situations, the QObject wrapper (and associated data, // such as the varProperties array) will have been cleaned up, but the // QObject ptr will not yet have been deleted (eg, waiting on deleteLater). // In this situation, return 0. return 0; - allocateProperties(); } - return static_cast<QV4::MemberData*>(properties.asManaged()); + return static_cast<QV4::MemberData*>(propertyAndMethodStorage.asManaged()); } void QQmlVMEMetaObject::writeProperty(int id, int v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = QV4::Primitive::fromInt32(v); } void QQmlVMEMetaObject::writeProperty(int id, bool v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = QV4::Primitive::fromBoolean(v); } void QQmlVMEMetaObject::writeProperty(int id, double v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = QV4::Primitive::fromDouble(v); } void QQmlVMEMetaObject::writeProperty(int id, const QString& v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = cache->engine->newString(v); } void QQmlVMEMetaObject::writeProperty(int id, const QUrl& v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QDate& v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QDateTime& v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QPointF& v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, const QRectF& v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v)); } void QQmlVMEMetaObject::writeProperty(int id, QObject* v) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) *(md->data() + id) = QV4::QObjectWrapper::wrap(cache->engine, v); @@ -422,7 +444,7 @@ void QQmlVMEMetaObject::writeProperty(int id, QObject* v) int QQmlVMEMetaObject::readPropertyAsInt(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return 0; @@ -435,7 +457,7 @@ int QQmlVMEMetaObject::readPropertyAsInt(int id) bool QQmlVMEMetaObject::readPropertyAsBool(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return false; @@ -448,7 +470,7 @@ bool QQmlVMEMetaObject::readPropertyAsBool(int id) double QQmlVMEMetaObject::readPropertyAsDouble(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return 0.0; @@ -461,7 +483,7 @@ double QQmlVMEMetaObject::readPropertyAsDouble(int id) QString QQmlVMEMetaObject::readPropertyAsString(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QString(); @@ -474,77 +496,77 @@ QString QQmlVMEMetaObject::readPropertyAsString(int id) QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QUrl(); QV4::Scope scope(cache->engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); - if (!v || v->d()->data.type() != QVariant::Url) + if (!v || v->d()->data().type() != QVariant::Url) return QUrl(); - return v->d()->data.value<QUrl>(); + return v->d()->data().value<QUrl>(); } QDate QQmlVMEMetaObject::readPropertyAsDate(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QDate(); QV4::Scope scope(cache->engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); - if (!v || v->d()->data.type() != QVariant::Date) + if (!v || v->d()->data().type() != QVariant::Date) return QDate(); - return v->d()->data.value<QDate>(); + return v->d()->data().value<QDate>(); } QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QDateTime(); QV4::Scope scope(cache->engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); - if (!v || v->d()->data.type() != QVariant::DateTime) + if (!v || v->d()->data().type() != QVariant::DateTime) return QDateTime(); - return v->d()->data.value<QDateTime>(); + return v->d()->data().value<QDateTime>(); } QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QSizeF(); QV4::Scope scope(cache->engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); - if (!v || v->d()->data.type() != QVariant::SizeF) + if (!v || v->d()->data().type() != QVariant::SizeF) return QSizeF(); - return v->d()->data.value<QSizeF>(); + return v->d()->data().value<QSizeF>(); } QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QPointF(); QV4::Scope scope(cache->engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); - if (!v || v->d()->data.type() != QVariant::PointF) + if (!v || v->d()->data().type() != QVariant::PointF) return QPointF(); - return v->d()->data.value<QPointF>(); + return v->d()->data().value<QPointF>(); } QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return 0; @@ -558,34 +580,37 @@ QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id) QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return 0; QV4::Scope scope(cache->engine); QV4::Scoped<QV4::VariantObject> v(scope, *(md->data() + id)); - if (!v || (int)v->d()->data.userType() != qMetaTypeId<QList<QObject *> >()) { + if (!v || (int)v->d()->data().userType() != qMetaTypeId<QList<QObject *> >()) { QVariant variant(qVariantFromValue(QList<QObject*>())); v = cache->engine->newVariantObject(variant); *(md->data() + id) = v; } - return static_cast<QList<QObject *> *>(v->d()->data.data()); + return static_cast<QList<QObject *> *>(v->d()->data().data()); } QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QRectF(); QV4::Scope scope(cache->engine); QV4::ScopedValue sv(scope, *(md->data() + id)); const QV4::VariantObject *v = sv->as<QV4::VariantObject>(); - if (!v || v->d()->data.type() != QVariant::RectF) + if (!v || v->d()->data().type() != QVariant::RectF) return QRectF(); - return v->d()->data.value<QRectF>(); + return v->d()->data().value<QRectF>(); } +#if defined(Q_OS_WINRT) && defined(_M_ARM) +#pragma optimize("", off) +#endif int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void **a) { Q_ASSERT(o == object); @@ -596,15 +621,20 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * if (intercept(c, _id, a)) return -1; + const int propertyCount = compiledObject ? int(compiledObject->nProperties) : 0; + const int aliasCount = compiledObject ? int(compiledObject->nAliases) : 0; + const int signalCount = compiledObject ? int(compiledObject->nSignals) : 0; + const int methodCount = compiledObject ? int(compiledObject->nFunctions) : 0; + if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty) { if (id >= propOffset()) { id -= propOffset(); - if (id < metaData->propertyCount) { - int t = (metaData->propertyData() + id)->propertyType; + if (id < propertyCount) { + const QV4::CompiledData::Property::Type t = static_cast<QV4::CompiledData::Property::Type>(qint32(compiledObject->propertyTable()[id].type)); bool needActivate = false; - if (t == QQmlVMEMetaData::VarPropertyType) { + if (t == QV4::CompiledData::Property::Var) { // the context can be null if accessing var properties from cpp after re-parenting an item. QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine); QV8Engine *v8e = (ep == 0) ? 0 : ep->v8engine(); @@ -620,132 +650,180 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * } } else { + int fallbackMetaType = QMetaType::UnknownType; + switch (t) { + case QV4::CompiledData::Property::Font: + fallbackMetaType = QMetaType::QFont; + break; + case QV4::CompiledData::Property::Time: + fallbackMetaType = QMetaType::QTime; + break; + case QV4::CompiledData::Property::Color: + fallbackMetaType = QMetaType::QColor; + break; + case QV4::CompiledData::Property::Vector2D: + fallbackMetaType = QMetaType::QVector2D; + break; + case QV4::CompiledData::Property::Vector3D: + fallbackMetaType = QMetaType::QVector3D; + break; + case QV4::CompiledData::Property::Vector4D: + fallbackMetaType = QMetaType::QVector4D; + break; + case QV4::CompiledData::Property::Matrix4x4: + fallbackMetaType = QMetaType::QMatrix4x4; + break; + case QV4::CompiledData::Property::Quaternion: + fallbackMetaType = QMetaType::QQuaternion; + break; + default: break; + } + if (c == QMetaObject::ReadProperty) { - switch(t) { - case QVariant::Int: + switch (t) { + case QV4::CompiledData::Property::Int: *reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id); break; - case QVariant::Bool: + case QV4::CompiledData::Property::Bool: *reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id); break; - case QVariant::Double: + case QV4::CompiledData::Property::Real: *reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id); break; - case QVariant::String: + case QV4::CompiledData::Property::String: *reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id); break; - case QVariant::Url: + case QV4::CompiledData::Property::Url: *reinterpret_cast<QUrl *>(a[0]) = readPropertyAsUrl(id); break; - case QVariant::Date: + case QV4::CompiledData::Property::Date: *reinterpret_cast<QDate *>(a[0]) = readPropertyAsDate(id); break; - case QVariant::DateTime: + case QV4::CompiledData::Property::DateTime: *reinterpret_cast<QDateTime *>(a[0]) = readPropertyAsDateTime(id); break; - case QVariant::RectF: + case QV4::CompiledData::Property::Rect: *reinterpret_cast<QRectF *>(a[0]) = readPropertyAsRectF(id); break; - case QVariant::SizeF: + case QV4::CompiledData::Property::Size: *reinterpret_cast<QSizeF *>(a[0]) = readPropertyAsSizeF(id); break; - case QVariant::PointF: + case QV4::CompiledData::Property::Point: *reinterpret_cast<QPointF *>(a[0]) = readPropertyAsPointF(id); break; - case QMetaType::QObjectStar: + case QV4::CompiledData::Property::Custom: *reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id); break; - case QMetaType::QVariant: + case QV4::CompiledData::Property::Variant: *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id); break; - default: - { - if (t == qMetaTypeId<QQmlListProperty<QObject> >()) { - QList<QObject *> *list = readPropertyAsList(id); - QQmlListProperty<QObject> *p = static_cast<QQmlListProperty<QObject> *>(a[0]); - *p = QQmlListProperty<QObject>(object, list, - list_append, list_count, list_at, - list_clear); - p->dummy1 = this; - p->dummy2 = reinterpret_cast<void *>(quintptr(methodOffset() + id)); - } else { - QV4::MemberData *md = propertiesAsMemberData(); - if (md) { - QVariant propertyAsVariant; - if (QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>()) - propertyAsVariant = v->d()->data; - QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], t); - } - } + case QV4::CompiledData::Property::CustomList: { + QList<QObject *> *list = readPropertyAsList(id); + QQmlListProperty<QObject> *p = static_cast<QQmlListProperty<QObject> *>(a[0]); + *p = QQmlListProperty<QObject>(object, list, + list_append, list_count, list_at, + list_clear); + p->dummy1 = this; + p->dummy2 = reinterpret_cast<void *>(quintptr(methodOffset() + id)); break; } + case QV4::CompiledData::Property::Font: + case QV4::CompiledData::Property::Time: + case QV4::CompiledData::Property::Color: + case QV4::CompiledData::Property::Vector2D: + case QV4::CompiledData::Property::Vector3D: + case QV4::CompiledData::Property::Vector4D: + case QV4::CompiledData::Property::Matrix4x4: + case QV4::CompiledData::Property::Quaternion: + Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); + if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { + QVariant propertyAsVariant; + if (QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>()) + propertyAsVariant = v->d()->data(); + QQml_valueTypeProvider()->readValueType(propertyAsVariant, a[0], fallbackMetaType); + } + break; + case QV4::CompiledData::Property::Var: + Q_UNREACHABLE(); } } else if (c == QMetaObject::WriteProperty) { switch(t) { - case QVariant::Int: + case QV4::CompiledData::Property::Int: needActivate = *reinterpret_cast<int *>(a[0]) != readPropertyAsInt(id); writeProperty(id, *reinterpret_cast<int *>(a[0])); break; - case QVariant::Bool: + case QV4::CompiledData::Property::Bool: needActivate = *reinterpret_cast<bool *>(a[0]) != readPropertyAsBool(id); writeProperty(id, *reinterpret_cast<bool *>(a[0])); break; - case QVariant::Double: + case QV4::CompiledData::Property::Real: needActivate = *reinterpret_cast<double *>(a[0]) != readPropertyAsDouble(id); writeProperty(id, *reinterpret_cast<double *>(a[0])); break; - case QVariant::String: + case QV4::CompiledData::Property::String: needActivate = *reinterpret_cast<QString *>(a[0]) != readPropertyAsString(id); writeProperty(id, *reinterpret_cast<QString *>(a[0])); break; - case QVariant::Url: + case QV4::CompiledData::Property::Url: needActivate = *reinterpret_cast<QUrl *>(a[0]) != readPropertyAsUrl(id); writeProperty(id, *reinterpret_cast<QUrl *>(a[0])); break; - case QVariant::Date: + case QV4::CompiledData::Property::Date: needActivate = *reinterpret_cast<QDate *>(a[0]) != readPropertyAsDate(id); writeProperty(id, *reinterpret_cast<QDate *>(a[0])); break; - case QVariant::DateTime: + case QV4::CompiledData::Property::DateTime: needActivate = *reinterpret_cast<QDateTime *>(a[0]) != readPropertyAsDateTime(id); writeProperty(id, *reinterpret_cast<QDateTime *>(a[0])); break; - case QVariant::RectF: + case QV4::CompiledData::Property::Rect: needActivate = *reinterpret_cast<QRectF *>(a[0]) != readPropertyAsRectF(id); writeProperty(id, *reinterpret_cast<QRectF *>(a[0])); break; - case QVariant::SizeF: + case QV4::CompiledData::Property::Size: needActivate = *reinterpret_cast<QSizeF *>(a[0]) != readPropertyAsSizeF(id); writeProperty(id, *reinterpret_cast<QSizeF *>(a[0])); break; - case QVariant::PointF: + case QV4::CompiledData::Property::Point: needActivate = *reinterpret_cast<QPointF *>(a[0]) != readPropertyAsPointF(id); writeProperty(id, *reinterpret_cast<QPointF *>(a[0])); break; - case QMetaType::QObjectStar: + case QV4::CompiledData::Property::Custom: needActivate = *reinterpret_cast<QObject **>(a[0]) != readPropertyAsQObject(id); writeProperty(id, *reinterpret_cast<QObject **>(a[0])); break; - case QMetaType::QVariant: + case QV4::CompiledData::Property::Variant: writeProperty(id, *reinterpret_cast<QVariant *>(a[0])); break; - default: { - QV4::MemberData *md = propertiesAsMemberData(); - if (md) { + case QV4::CompiledData::Property::CustomList: + // Writing such a property is not supported. Content is added through the list property + // methods. + break; + case QV4::CompiledData::Property::Font: + case QV4::CompiledData::Property::Time: + case QV4::CompiledData::Property::Color: + case QV4::CompiledData::Property::Vector2D: + case QV4::CompiledData::Property::Vector3D: + case QV4::CompiledData::Property::Vector4D: + case QV4::CompiledData::Property::Matrix4x4: + case QV4::CompiledData::Property::Quaternion: + Q_ASSERT(fallbackMetaType != QMetaType::UnknownType); + if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) { QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); if (!v) { *(md->data() + id) = cache->engine->newVariantObject(QVariant()); v = (md->data() + id)->as<QV4::VariantObject>(); - QQml_valueTypeProvider()->initValueType(t, v->d()->data); + QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data()); } - needActivate = !QQml_valueTypeProvider()->equalValueType(t, a[0], v->d()->data); - QQml_valueTypeProvider()->writeValueType(t, a[0], v->d()->data); + needActivate = !QQml_valueTypeProvider()->equalValueType(fallbackMetaType, a[0], v->d()->data()); + QQml_valueTypeProvider()->writeValueType(fallbackMetaType, a[0], v->d()->data()); } break; - } + case QV4::CompiledData::Property::Var: + Q_UNREACHABLE(); } } @@ -758,56 +836,69 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * return -1; } - id -= metaData->propertyCount; - - if (id < metaData->aliasCount) { + id -= propertyCount; - QQmlVMEMetaData::AliasData *d = metaData->aliasData() + id; + if (id < aliasCount) { + const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[id]; - if (d->flags & QML_ALIAS_FLAG_PTR && c == QMetaObject::ReadProperty) + if ((aliasData->flags & QV4::CompiledData::Alias::AliasPointsToPointerObject) && c == QMetaObject::ReadProperty) *reinterpret_cast<void **>(a[0]) = 0; if (!ctxt) return -1; + while (aliasData->aliasToLocalAlias) + aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex]; + QQmlContext *context = ctxt->asQQmlContext(); QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context); - QObject *target = ctxtPriv->data->idValues[d->contextIdx].data(); + QObject *target = ctxtPriv->data->idValues[aliasData->targetObjectId].data(); if (!target) return -1; connectAlias(id); - if (d->isObjectAlias()) { + if (aliasData->isObjectAlias()) { *reinterpret_cast<QObject **>(a[0]) = target; return -1; } + QQmlData *targetDData = QQmlData::get(target, /*create*/false); + if (!targetDData) + return -1; + + QQmlPropertyIndex encodedIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex); + int coreIndex = encodedIndex.coreIndex(); + const int valueTypePropertyIndex = encodedIndex.valueTypeIndex(); + // Remove binding (if any) on write if(c == QMetaObject::WriteProperty) { int flags = *reinterpret_cast<int*>(a[3]); - if (flags & QQmlPropertyPrivate::RemoveBindingOnAliasWrite) { + if (flags & QQmlPropertyData::RemoveBindingOnAliasWrite) { QQmlData *targetData = QQmlData::get(target); - if (targetData && targetData->hasBindingBit(d->propertyIndex())) - QQmlPropertyPrivate::removeBinding(target, d->propertyIdx); + if (targetData && targetData->hasBindingBit(coreIndex)) + QQmlPropertyPrivate::removeBinding(target, encodedIndex); } } - if (d->isValueTypeAlias()) { + if (valueTypePropertyIndex != -1) { + if (!targetDData->propertyCache) + return -1; + const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex); // Value type property - QQmlValueType *valueType = QQmlValueTypeFactory::valueType(d->valueType()); + QQmlValueType *valueType = QQmlValueTypeFactory::valueType(pd->propType()); Q_ASSERT(valueType); - valueType->read(target, d->propertyIndex()); - int rv = QMetaObject::metacall(valueType, c, d->valueTypeIndex(), a); + valueType->read(target, coreIndex); + int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a); if (c == QMetaObject::WriteProperty) - valueType->write(target, d->propertyIndex(), 0x00); + valueType->write(target, coreIndex, 0x00); return rv; } else { - return QMetaObject::metacall(target, c, d->propertyIndex(), a); + return QMetaObject::metacall(target, c, coreIndex, a); } } @@ -820,8 +911,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * if (id >= methodOffset()) { id -= methodOffset(); - int plainSignals = metaData->signalCount + metaData->propertyCount + - metaData->aliasCount; + int plainSignals = signalCount + propertyCount + aliasCount; if (id < plainSignals) { activate(object, _id, a); return -1; @@ -829,7 +919,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * id -= plainSignals; - if (id < metaData->methodCount) { + if (id < methodCount) { if (!ctxt->engine) return -1; // We can't run the method @@ -845,31 +935,29 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * // are not rewritten correctly but this bug is deemed out-of-scope to fix for // performance reasons; see QTBUG-24064) and thus compilation will have failed. QQmlError e; - e.setDescription(QString::fromLatin1("Exception occurred during compilation of " - "function: %1") - .arg(QString::fromUtf8(QMetaObject::method(_id) - .methodSignature()))); + e.setDescription(QLatin1String("Exception occurred during compilation of " + "function: ") + + QString::fromUtf8(QMetaObject::method(_id) + .methodSignature())); ep->warning(e); return -1; // The dynamic method with that id is not available. } - QQmlVMEMetaData::MethodData *data = metaData->methodData() + id; - - QV4::ScopedCallData callData(scope, data->parameterCount); + const unsigned int parameterCount = function->formalParameterCount(); + QV4::ScopedCallData callData(scope, parameterCount); callData->thisObject = ep->v8engine()->global(); - for (int ii = 0; ii < data->parameterCount; ++ii) + for (uint ii = 0; ii < parameterCount; ++ii) callData->args[ii] = scope.engine->fromVariant(*(QVariant *)a[ii + 1]); - QV4::ScopedValue result(scope); - result = function->call(callData); + function->call(scope, callData); if (scope.hasException()) { QQmlError error = scope.engine->catchExceptionAsQmlError(); if (error.isValid()) ep->warning(error); if (a[0]) *(QVariant *)a[0] = QVariant(); } else { - if (a[0]) *(QVariant *)a[0] = scope.engine->toVariant(result, 0); + if (a[0]) *(QVariant *)a[0] = scope.engine->toVariant(scope.result, 0); } ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete. @@ -884,25 +972,29 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * else return object->qt_metacall(c, _id, a); } +#if defined(Q_OS_WINRT) && defined(_M_ARM) +#pragma optimize("", on) +#endif QV4::ReturnedValue QQmlVMEMetaObject::method(int index) { - if (!ctxt || !ctxt->isValid()) { + if (!ctxt || !ctxt->isValid() || !compiledObject) { qWarning("QQmlVMEMetaObject: Internal error - attempted to evaluate a function in an invalid context"); return QV4::Encode::undefined(); } - if (!methods) + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); + if (!md) return QV4::Encode::undefined(); - return methods[index].value(); + return (md->data() + index + compiledObject->nProperties)->asReturnedValue(); } QV4::ReturnedValue QQmlVMEMetaObject::readVarProperty(int id) { - Q_ASSERT((metaData->propertyData() + id)->propertyType == QQmlVMEMetaData::VarPropertyType); + Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var); - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) return (md->data() + id)->asReturnedValue(); return QV4::Primitive::undefinedValue().asReturnedValue(); @@ -910,14 +1002,14 @@ QV4::ReturnedValue QQmlVMEMetaObject::readVarProperty(int id) QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) { const QV4::QObjectWrapper *wrapper = (md->data() + id)->as<QV4::QObjectWrapper>(); if (wrapper) return QVariant::fromValue(wrapper->object()); const QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); if (v) - return v->d()->data; + return v->d()->data(); return cache->engine->toVariant(*(md->data() + id), -1); } return QVariant(); @@ -925,9 +1017,9 @@ QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id) void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value) { - Q_ASSERT((metaData->propertyData() + id)->propertyType == QQmlVMEMetaData::VarPropertyType); + Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var); - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return; @@ -965,8 +1057,8 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value) void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) { - if ((metaData->propertyData() + id)->propertyType == QQmlVMEMetaData::VarPropertyType) { - QV4::MemberData *md = propertiesAsMemberData(); + if (compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var) { + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return; @@ -996,12 +1088,12 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) needActivate = readPropertyAsQObject(id) != o; // TODO: still correct? writeProperty(id, o); } else { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (md) { QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>(); needActivate = (!v || - v->d()->data.userType() != value.userType() || - v->d()->data != value); + v->d()->data().userType() != value.userType() || + v->d()->data() != value); if (v) v->removeVmePropertyReference(); *(md->data() + id) = cache->engine->newVariantObject(value); @@ -1015,61 +1107,16 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value) } } -void QQmlVMEMetaObject::listChanged(int id) -{ - activate(object, methodOffset() + id, 0); -} - -void QQmlVMEMetaObject::list_append(QQmlListProperty<QObject> *prop, QObject *o) -{ - QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data); - list->append(o); - static_cast<QQmlVMEMetaObject *>(prop->dummy1)->activate(prop->object, reinterpret_cast<quintptr>(prop->dummy2), 0); -} - -int QQmlVMEMetaObject::list_count(QQmlListProperty<QObject> *prop) -{ - QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data); - return list->count(); -} - -QObject *QQmlVMEMetaObject::list_at(QQmlListProperty<QObject> *prop, int index) -{ - QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data); - return list->at(index); -} - -void QQmlVMEMetaObject::list_clear(QQmlListProperty<QObject> *prop) -{ - QList<QObject *> *list = static_cast<QList<QObject *> *>(prop->data); - list->clear(); - static_cast<QQmlVMEMetaObject *>(prop->dummy1)->activate(prop->object, reinterpret_cast<quintptr>(prop->dummy2), 0); -} - -quint16 QQmlVMEMetaObject::vmeMethodLineNumber(int index) -{ - if (index < methodOffset()) { - Q_ASSERT(parentVMEMetaObject()); - return parentVMEMetaObject()->vmeMethodLineNumber(index); - } - - int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; - Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount)); - - int rawIndex = index - methodOffset() - plainSignals; - - QQmlVMEMetaData::MethodData *data = metaData->methodData() + rawIndex; - return data->lineNumber; -} - QV4::ReturnedValue QQmlVMEMetaObject::vmeMethod(int index) { if (index < methodOffset()) { Q_ASSERT(parentVMEMetaObject()); return parentVMEMetaObject()->vmeMethod(index); } - int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; - Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount)); + if (!compiledObject) + return QV4::Primitive::undefinedValue().asReturnedValue(); + const int plainSignals = compiledObject->nSignals + compiledObject->nProperties + compiledObject->nAliases; + Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + int(compiledObject->nFunctions))); return method(index - methodOffset() - plainSignals); } @@ -1080,14 +1127,16 @@ void QQmlVMEMetaObject::setVmeMethod(int index, const QV4::Value &function) Q_ASSERT(parentVMEMetaObject()); return parentVMEMetaObject()->setVmeMethod(index, function); } - int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount; - Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount)); - - if (!methods) - methods = new QV4::PersistentValue[metaData->methodCount]; + if (!compiledObject) + return; + const int plainSignals = compiledObject->nSignals + compiledObject->nProperties + compiledObject->nAliases; + Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + int(compiledObject->nFunctions))); int methodIndex = index - methodOffset() - plainSignals; - methods[methodIndex].set(function.as<QV4::Object>()->engine(), function); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); + if (!md) + return; + *(md->data() + methodIndex + compiledObject->nProperties) = function; } QV4::ReturnedValue QQmlVMEMetaObject::vmeProperty(int index) @@ -1122,26 +1171,15 @@ void QQmlVMEMetaObject::mark(QV4::ExecutionEngine *e) if (v4 != e) return; - properties.markOnce(e); + propertyAndMethodStorage.markOnce(e); if (QQmlVMEMetaObject *parent = parentVMEMetaObject()) parent->mark(e); } -void QQmlVMEMetaObject::allocateProperties() -{ - Q_ASSERT(cache && cache->engine); - Q_ASSERT(!properties.valueRef()); - QV4::ExecutionEngine *v4 = cache->engine; - QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, metaData->propertyCount); - properties.set(v4, data); - for (uint i = 0; i < data->size; ++i) - data->data[i] = QV4::Encode::undefined(); -} - bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const { - Q_ASSERT(index >= propOffset() + metaData->propertyCount); + Q_ASSERT(compiledObject && (index >= propOffset() + int(compiledObject->nProperties))); *target = 0; *coreIndex = -1; @@ -1150,31 +1188,27 @@ bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, if (!ctxt) return false; - QQmlVMEMetaData::AliasData *d = metaData->aliasData() + (index - propOffset() - metaData->propertyCount); - QQmlContext *context = ctxt->asQQmlContext(); - QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context); - - *target = ctxtPriv->data->idValues[d->contextIdx].data(); + const int aliasId = index - propOffset() - compiledObject->nProperties; + const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId]; + *target = ctxt->idValues[aliasData->targetObjectId].data(); if (!*target) return false; - if (d->isObjectAlias()) { - } else if (d->isValueTypeAlias()) { - *coreIndex = d->propertyIndex(); - *valueTypeIndex = d->valueTypeIndex(); - } else { - *coreIndex = d->propertyIndex(); + if (!aliasData->isObjectAlias()) { + QQmlPropertyIndex encodedIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex); + *coreIndex = encodedIndex.coreIndex(); + *valueTypeIndex = encodedIndex.valueTypeIndex(); } - return true; } void QQmlVMEMetaObject::connectAlias(int aliasId) { + Q_ASSERT(compiledObject); if (!aliasEndpoints) - aliasEndpoints = new QQmlVMEMetaObjectEndpoint[metaData->aliasCount]; + aliasEndpoints = new QQmlVMEMetaObjectEndpoint[compiledObject->nAliases]; - QQmlVMEMetaData::AliasData *d = metaData->aliasData() + aliasId; + const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId]; QQmlVMEMetaObjectEndpoint *endpoint = aliasEndpoints + aliasId; if (endpoint->metaObject.data()) { @@ -1184,14 +1218,15 @@ void QQmlVMEMetaObject::connectAlias(int aliasId) } endpoint->metaObject = this; - endpoint->connect(&ctxt->idValues[d->contextIdx].bindings); + endpoint->connect(&ctxt->idValues[aliasData->targetObjectId].bindings); endpoint->tryConnect(); } void QQmlVMEMetaObject::connectAliasSignal(int index, bool indexInSignalRange) { - int aliasId = (index - (indexInSignalRange ? signalOffset() : methodOffset())) - metaData->propertyCount; - if (aliasId < 0 || aliasId >= metaData->aliasCount) + Q_ASSERT(compiledObject); + int aliasId = (index - (indexInSignalRange ? signalOffset() : methodOffset())) - compiledObject->nProperties; + if (aliasId < 0 || aliasId >= int(compiledObject->nAliases)) return; connectAlias(aliasId); diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h index 98fdae60ee..031bfdfb9b 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -64,82 +64,18 @@ #include <private/qobject_p.h> #include "qqmlguard_p.h" -#include "qqmlcompiler_p.h" #include "qqmlcontext_p.h" +#include "qqmlpropertycache_p.h" #include <private/qv8engine_p.h> #include <private/qflagpointer_p.h> +#include <private/qv4object_p.h> #include <private/qv4value_p.h> +#include <private/qqmlpropertyvalueinterceptor_p.h> QT_BEGIN_NAMESPACE -#define QML_ALIAS_FLAG_PTR 0x00000001 - -struct QQmlVMEMetaData -{ - short propertyCount; - short aliasCount; - short signalCount; - short methodCount; - // Make sure this structure is always aligned to int - - struct AliasData { - int contextIdx; - int propertyIdx; - int propType; - int flags; - int notifySignal; - - bool isObjectAlias() const { - return propertyIdx == -1; - } - bool isPropertyAlias() const { - return !isObjectAlias() && valueTypeIndex() == -1; - } - bool isValueTypeAlias() const { - return !isObjectAlias() && valueTypeIndex() != -1; - } - int propertyIndex() const { - int index; - QQmlPropertyData::decodeValueTypePropertyIndex(propertyIdx, &index); - return index; - } - int valueTypeIndex() const { - return QQmlPropertyData::decodeValueTypePropertyIndex(propertyIdx); - } - int valueType() const { - return (valueTypeIndex() != -1) ? propType : 0; - } - }; - - enum { - VarPropertyType = -1 - }; - - struct PropertyData { - int propertyType; - }; - - struct MethodData { - int runtimeFunctionIndex; - int parameterCount; - quint16 lineNumber; - }; - - PropertyData *propertyData() const { - return (PropertyData *)(((char *)const_cast<QQmlVMEMetaData *>(this)) + sizeof(QQmlVMEMetaData)); - } - - AliasData *aliasData() const { - return (AliasData *)(propertyData() + propertyCount); - } - - MethodData *methodData() const { - return (MethodData *)(aliasData() + aliasCount); - } -}; - class QQmlVMEMetaObject; class QQmlVMEVariantQObjectPtr : public QQmlGuard<QObject> { @@ -161,22 +97,31 @@ public: QQmlInterceptorMetaObject(QObject *obj, QQmlPropertyCache *cache); ~QQmlInterceptorMetaObject(); - void registerInterceptor(int index, int valueIndex, QQmlPropertyValueInterceptor *interceptor); + void registerInterceptor(QQmlPropertyIndex index, QQmlPropertyValueInterceptor *interceptor); static QQmlInterceptorMetaObject *get(QObject *obj); - virtual QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *o); + QAbstractDynamicMetaObject *toDynamicMetaObject(QObject *o) Q_DECL_OVERRIDE; // Used by auto-tests for inspection QQmlPropertyCache *propertyCache() const { return cache; } + bool intercepts(QQmlPropertyIndex propertyIndex) const + { + for (auto it = interceptors; it; it = it->m_next) { + if (it->m_propertyIndex == propertyIndex) + return true; + } + return false; + } + protected: - virtual int metaCall(QObject *o, QMetaObject::Call c, int id, void **a); + int metaCall(QObject *o, QMetaObject::Call c, int id, void **a) Q_DECL_OVERRIDE; bool intercept(QMetaObject::Call c, int id, void **a); public: QObject *object; - QQmlPropertyCache *cache; + QQmlRefPointer<QQmlPropertyCache> cache; QBiPointer<QDynamicMetaObjectData, const QMetaObject> parent; QQmlPropertyValueInterceptor *interceptors; @@ -195,18 +140,15 @@ inline QQmlInterceptorMetaObject *QQmlInterceptorMetaObject::get(QObject *obj) return 0; } -class QQmlVMEVariant; -class QQmlRefCount; class QQmlVMEMetaObjectEndpoint; class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QQmlInterceptorMetaObject { public: - QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, const QQmlVMEMetaData *data); + QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, QV4::CompiledData::CompilationUnit *qmlCompilationUnit, int qmlObjectId); ~QQmlVMEMetaObject(); bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const; QV4::ReturnedValue vmeMethod(int index); - quint16 vmeMethodLineNumber(int index); void setVmeMethod(int index, const QV4::Value &function); QV4::ReturnedValue vmeProperty(int index); void setVMEProperty(int index, const QV4::Value &v); @@ -219,16 +161,11 @@ public: static QQmlVMEMetaObject *getForSignal(QObject *o, int coreIndex); protected: - virtual int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a); + int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) Q_DECL_OVERRIDE; public: - friend class QQmlVMEMetaObjectEndpoint; - friend class QQmlVMEVariantQObjectPtr; - friend class QQmlPropertyCache; - QQmlGuardedContextData ctxt; - const QQmlVMEMetaData *metaData; inline int propOffset() const; inline int methodOffset() const; inline int signalOffset() const; @@ -236,9 +173,8 @@ public: QQmlVMEMetaObjectEndpoint *aliasEndpoints; - QV4::WeakValue properties; - inline void allocateProperties(); - QV4::MemberData *propertiesAsMemberData(); + QV4::WeakValue propertyAndMethodStorage; + QV4::MemberData *propertyAndMethodStorageAsMemberData(); int readPropertyAsInt(int id); bool readPropertyAsBool(int id); @@ -271,7 +207,6 @@ public: void connectAlias(int aliasId); - QV4::PersistentValue *methods; QV4::ReturnedValue method(int); QV4::ReturnedValue readVarProperty(int); @@ -281,18 +216,17 @@ public: inline QQmlVMEMetaObject *parentVMEMetaObject() const; - void listChanged(int); - - static void list_append(QQmlListProperty<QObject> *, QObject *); - static int list_count(QQmlListProperty<QObject> *); - static QObject *list_at(QQmlListProperty<QObject> *, int); - static void list_clear(QQmlListProperty<QObject> *); - void activate(QObject *, int, void **); QList<QQmlVMEVariantQObjectPtr *> varObjectGuards; QQmlVMEVariantQObjectPtr *getQObjectGuardForProperty(int) const; + + + // keep a reference to the compilation unit in order to still + // do property access when the context has been invalidated. + QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit; + const QV4::CompiledData::Object *compiledObject; }; QQmlVMEMetaObject *QQmlVMEMetaObject::get(QObject *obj) diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 24f49eb6e7..10b1cbcfd4 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -70,7 +70,7 @@ using namespace QV4; -#ifndef QT_NO_XMLSTREAMREADER +#if !defined(QT_NO_XMLSTREAMREADER) && QT_CONFIG(qml_network) #define V4THROW_REFERENCE(string) { \ ScopedObject error(scope, ctx->engine()->newReferenceErrorObject(QStringLiteral(string))); \ @@ -158,7 +158,7 @@ class DocumentImpl : public QQmlRefCount, public NodeImpl public: DocumentImpl() : root(0) { type = Document; } virtual ~DocumentImpl() { - if (root) delete root; + delete root; } QString version; @@ -174,33 +174,43 @@ public: namespace Heap { struct NamedNodeMap : Object { - NamedNodeMap(NodeImpl *data, const QList<NodeImpl *> &list); - ~NamedNodeMap() { + void init(NodeImpl *data, const QList<NodeImpl *> &list); + void destroy() { + delete listPtr; if (d) d->release(); + Object::destroy(); } - QList<NodeImpl *> list; // Only used in NamedNodeMap + QList<NodeImpl *> &list() { + if (listPtr == nullptr) + listPtr = new QList<NodeImpl *>; + return *listPtr; + } + + QList<NodeImpl *> *listPtr; // Only used in NamedNodeMap NodeImpl *d; }; struct NodeList : Object { - NodeList(NodeImpl *data); - ~NodeList() { + void init(NodeImpl *data); + void destroy() { if (d) d->release(); + Object::destroy(); } NodeImpl *d; }; struct NodePrototype : Object { - NodePrototype(); + void init(); }; struct Node : Object { - Node(NodeImpl *data); - ~Node() { + void init(NodeImpl *data); + void destroy() { if (d) d->release(); + Object::destroy(); } NodeImpl *d; }; @@ -221,10 +231,11 @@ public: static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); }; -Heap::NamedNodeMap::NamedNodeMap(NodeImpl *data, const QList<NodeImpl *> &list) - : list(list) - , d(data) +void Heap::NamedNodeMap::init(NodeImpl *data, const QList<NodeImpl *> &list) { + Object::init(); + d = data; + this->list() = list; if (d) d->addref(); } @@ -246,9 +257,10 @@ public: }; -Heap::NodeList::NodeList(NodeImpl *data) - : d(data) +void Heap::NodeList::init(NodeImpl *data) { + Object::init(); + d = data; if (d) d->addref(); } @@ -287,8 +299,9 @@ public: }; -Heap::NodePrototype::NodePrototype() +void Heap::NodePrototype::init() { + Object::init(); Scope scope(internalClass->engine); ScopedObject o(scope, this); @@ -320,9 +333,10 @@ struct Node : public Object bool isNull() const; }; -Heap::Node::Node(NodeImpl *data) - : d(data) +void Heap::Node::init(NodeImpl *data) { + Object::init(); + d = data; if (d) d->addref(); } @@ -502,7 +516,7 @@ ReturnedValue NodePrototype::method_get_firstChild(CallContext *ctx) if (r->d()->d->children.isEmpty()) return Encode::null(); else - return Node::create(scope.engine, r->d()->d->children.first()); + return Node::create(scope.engine, r->d()->d->children.constFirst()); } ReturnedValue NodePrototype::method_get_lastChild(CallContext *ctx) @@ -515,7 +529,7 @@ ReturnedValue NodePrototype::method_get_lastChild(CallContext *ctx) if (r->d()->d->children.isEmpty()) return Encode::null(); else - return Node::create(scope.engine, r->d()->d->children.last()); + return Node::create(scope.engine, r->d()->d->children.constLast()); } ReturnedValue NodePrototype::method_get_previousSibling(CallContext *ctx) @@ -715,7 +729,7 @@ ReturnedValue Text::method_isElementContentWhitespace(CallContext *ctx) Scoped<Node> r(scope, ctx->thisObject().as<Node>()); if (!r) return Encode::undefined(); - return Encode(r->d()->d->data.trimmed().isEmpty()); + return Encode(QStringRef(&r->d()->d->data).trimmed().isEmpty()); } ReturnedValue Text::method_wholeText(CallContext *ctx) @@ -877,10 +891,10 @@ ReturnedValue NamedNodeMap::getIndexed(const Managed *m, uint index, bool *hasPr const NamedNodeMap *r = static_cast<const NamedNodeMap *>(m); QV4::ExecutionEngine *v4 = r->engine(); - if ((int)index < r->d()->list.count()) { + if ((int)index < r->d()->list().count()) { if (hasProperty) *hasProperty = true; - return Node::create(v4, r->d()->list.at(index)); + return Node::create(v4, r->d()->list().at(index)); } if (hasProperty) *hasProperty = false; @@ -895,14 +909,14 @@ ReturnedValue NamedNodeMap::get(const Managed *m, String *name, bool *hasPropert name->makeIdentifier(v4); if (name->equals(v4->id_length())) - return Primitive::fromInt32(r->d()->list.count()).asReturnedValue(); + return Primitive::fromInt32(r->d()->list().count()).asReturnedValue(); QString str = name->toQString(); - for (int ii = 0; ii < r->d()->list.count(); ++ii) { - if (r->d()->list.at(ii)->name == str) { + for (int ii = 0; ii < r->d()->list().count(); ++ii) { + if (r->d()->list().at(ii)->name == str) { if (hasProperty) *hasProperty = true; - return Node::create(v4, r->d()->list.at(ii)); + return Node::create(v4, r->d()->list().at(ii)); } } @@ -1016,8 +1030,8 @@ public: ReturnedValue abort(Object *thisObject, QQmlContextData *context); void addHeader(const QString &, const QString &); - QString header(const QString &name); - QString headers(); + QString header(const QString &name) const; + QString headers() const; QString responseBody(); const QByteArray & rawResponseBody() const; @@ -1144,26 +1158,27 @@ void QQmlXMLHttpRequest::addHeader(const QString &name, const QString &value) } } -QString QQmlXMLHttpRequest::header(const QString &name) +QString QQmlXMLHttpRequest::header(const QString &name) const { - QByteArray utfname = name.toLower().toUtf8(); - - foreach (const HeaderPair &header, m_headersList) { - if (header.first == utfname) - return QString::fromUtf8(header.second); + if (!m_headersList.isEmpty()) { + const QByteArray utfname = name.toLower().toUtf8(); + for (const HeaderPair &header : m_headersList) { + if (header.first == utfname) + return QString::fromUtf8(header.second); + } } return QString(); } -QString QQmlXMLHttpRequest::headers() +QString QQmlXMLHttpRequest::headers() const { QString ret; - foreach (const HeaderPair &header, m_headersList) { + for (const HeaderPair &header : m_headersList) { if (ret.length()) ret.append(QLatin1String("\r\n")); - ret = ret % QString::fromUtf8(header.first) % QLatin1String(": ") - % QString::fromUtf8(header.second); + ret += QString::fromUtf8(header.first) + QLatin1String(": ") + + QString::fromUtf8(header.second); } return ret; } @@ -1235,7 +1250,8 @@ void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url) } else if (m_method == QLatin1String("DELETE")) { m_network = networkAccessManager()->deleteResource(request); } else if ((m_method == QLatin1String("OPTIONS")) || - m_method == QLatin1String("PROPFIND")) { + m_method == QLatin1String("PROPFIND") || + m_method == QLatin1String("PATCH")) { QBuffer *buffer = new QBuffer; buffer->setData(m_data); buffer->open(QIODevice::ReadOnly); @@ -1559,7 +1575,7 @@ void QQmlXMLHttpRequest::dispatchCallback(Object *thisObj, QQmlContextData *cont QV4::ScopedCallData callData(scope); callData->thisObject = Encode::undefined(); - callback->call(callData); + callback->call(scope, callData); if (scope.engine->hasException) { QQmlError error = scope.engine->catchExceptionAsQmlError(); @@ -1585,15 +1601,20 @@ namespace QV4 { namespace Heap { struct QQmlXMLHttpRequestWrapper : Object { - QQmlXMLHttpRequestWrapper(QQmlXMLHttpRequest *request); - ~QQmlXMLHttpRequestWrapper() { + void init(QQmlXMLHttpRequest *request) { + Object::init(); + this->request = request; + } + + void destroy() { delete request; + Object::destroy(); } QQmlXMLHttpRequest *request; }; struct QQmlXMLHttpRequestCtor : FunctionObject { - QQmlXMLHttpRequestCtor(ExecutionEngine *engine); + void init(ExecutionEngine *engine); Pointer<Object> proto; }; @@ -1606,11 +1627,6 @@ struct QQmlXMLHttpRequestWrapper : public Object V4_NEEDS_DESTROY }; -Heap::QQmlXMLHttpRequestWrapper::QQmlXMLHttpRequestWrapper(QQmlXMLHttpRequest *request) - : request(request) -{ -} - struct QQmlXMLHttpRequestCtor : public FunctionObject { V4_OBJECT2(QQmlXMLHttpRequestCtor, FunctionObject) @@ -1620,22 +1636,23 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject c->proto->mark(e); FunctionObject::markObjects(that, e); } - static ReturnedValue construct(const Managed *that, QV4::CallData *) + static void construct(const Managed *that, Scope &scope, QV4::CallData *) { - Scope scope(static_cast<const QQmlXMLHttpRequestCtor *>(that)->engine()); Scoped<QQmlXMLHttpRequestCtor> ctor(scope, that->as<QQmlXMLHttpRequestCtor>()); - if (!ctor) - return scope.engine->throwTypeError(); + if (!ctor) { + scope.result = scope.engine->throwTypeError(); + return; + } QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->v8Engine->networkAccessManager()); Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->allocObject<QQmlXMLHttpRequestWrapper>(r)); ScopedObject proto(scope, ctor->d()->proto); w->setPrototype(proto); - return w.asReturnedValue(); + scope.result = w.asReturnedValue(); } - static ReturnedValue call(const Managed *, QV4::CallData *) { - return Primitive::undefinedValue().asReturnedValue(); + static void call(const Managed *, Scope &scope, QV4::CallData *) { + scope.result = Primitive::undefinedValue(); } void setupProto(); @@ -1661,9 +1678,9 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject DEFINE_OBJECT_VTABLE(QQmlXMLHttpRequestWrapper); -Heap::QQmlXMLHttpRequestCtor::QQmlXMLHttpRequestCtor(ExecutionEngine *engine) - : Heap::FunctionObject(engine->rootContext(), QStringLiteral("XMLHttpRequest")) +void Heap::QQmlXMLHttpRequestCtor::init(ExecutionEngine *engine) { + Heap::FunctionObject::init(engine->rootContext(), QStringLiteral("XMLHttpRequest")); Scope scope(engine); Scoped<QV4::QQmlXMLHttpRequestCtor> ctor(scope, this); @@ -1735,7 +1752,8 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx) method != QLatin1String("POST") && method != QLatin1String("DELETE") && method != QLatin1String("OPTIONS") && - method != QLatin1String("PROPFIND")) + method != QLatin1String("PROPFIND") && + method != QLatin1String("PATCH")) V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type"); // Argument 1 - URL @@ -2038,6 +2056,6 @@ void *qt_add_qmlxmlhttprequest(ExecutionEngine *v4) QT_END_NAMESPACE -#endif // QT_NO_XMLSTREAMREADER +#endif // QT_NO_XMLSTREAMREADER && qml_network #include <qqmlxmlhttprequest.moc> diff --git a/src/qml/qml/qqmlxmlhttprequest_p.h b/src/qml/qml/qqmlxmlhttprequest_p.h index 7bbfb5243c..fdb6194537 100644 --- a/src/qml/qml/qqmlxmlhttprequest_p.h +++ b/src/qml/qml/qqmlxmlhttprequest_p.h @@ -55,7 +55,7 @@ #include <QtCore/qglobal.h> #include <private/qqmlglobal_p.h> -#ifndef QT_NO_XMLSTREAMREADER +#if !defined(QT_NO_XMLSTREAMREADER) && QT_CONFIG(qml_network) QT_BEGIN_NAMESPACE @@ -64,7 +64,7 @@ void qt_rem_qmlxmlhttprequest(QV4::ExecutionEngine *engine, void *); QT_END_NAMESPACE -#endif // QT_NO_XMLSTREAMREADER +#endif // QT_NO_XMLSTREAMREADER && qml_network #endif // QQMLXMLHTTPREQUEST_P_H diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index b9fb1f4ffe..cf0fd57773 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -42,9 +42,11 @@ #include <QtQml/qqmlcomponent.h> #include <private/qqmlengine_p.h> #include <private/qqmlcomponent_p.h> +#include <private/qqmlloggingcategory_p.h> #include <private/qqmlstringconverters_p.h> #include <private/qqmllocale_p.h> #include <private/qv8engine_p.h> +#include <private/qqmldelayedcallqueue_p.h> #include <QFileInfo> #include <private/qqmldebugconnector_p.h> @@ -75,6 +77,8 @@ #include <QtCore/qcoreapplication.h> #include <QtCore/qloggingcategory.h> +#include <QDebug> + QT_BEGIN_NAMESPACE using namespace QV4; @@ -87,10 +91,11 @@ struct StaticQtMetaObject : public QObject { return &staticQtMetaObject; } }; -Heap::QtObject::QtObject(QQmlEngine *qmlEngine) - : enumeratorIterator(0) - , keyIterator(0) +void Heap::QtObject::init(QQmlEngine *qmlEngine) { + Heap::Object::init(); + enumeratorIterator = 0; + keyIterator = 0; Scope scope(internalClass->engine); ScopedObject o(scope, this); @@ -136,6 +141,7 @@ Heap::QtObject::QtObject(QQmlEngine *qmlEngine) o->defineDefaultProperty(QStringLiteral("darker"), QV4::QtObject::method_darker); o->defineDefaultProperty(QStringLiteral("tint"), QV4::QtObject::method_tint); o->defineDefaultProperty(QStringLiteral("quit"), QV4::QtObject::method_quit); + o->defineDefaultProperty(QStringLiteral("exit"), QV4::QtObject::method_exit); o->defineDefaultProperty(QStringLiteral("createQmlObject"), QV4::QtObject::method_createQmlObject); o->defineDefaultProperty(QStringLiteral("createComponent"), QV4::QtObject::method_createComponent); } @@ -146,6 +152,8 @@ Heap::QtObject::QtObject(QQmlEngine *qmlEngine) o->defineAccessorProperty(QStringLiteral("inputMethod"), QV4::QtObject::method_get_inputMethod, 0); #endif o->defineAccessorProperty(QStringLiteral("styleHints"), QV4::QtObject::method_get_styleHints, 0); + + o->defineDefaultProperty(QStringLiteral("callLater"), QV4::QtObject::method_callLater); } void QtObject::addAll() @@ -989,6 +997,8 @@ This function causes the QQmlEngine::quit() signal to be emitted. Within the \l {Prototyping with qmlscene}, this causes the launcher application to exit; to quit a C++ application when this method is called, connect the QQmlEngine::quit() signal to the QCoreApplication::quit() slot. + +\sa exit() */ ReturnedValue QtObject::method_quit(CallContext *ctx) { @@ -997,6 +1007,28 @@ ReturnedValue QtObject::method_quit(CallContext *ctx) } /*! + \qmlmethod Qt::exit(int retCode) + + This function causes the QQmlEngine::exit(int) signal to be emitted. + Within the \l {Prototyping with qmlscene}, this causes the launcher application to exit + the specified return code. To exit from the event loop with a specified return code when this + method is called, a C++ application can connect the QQmlEngine::exit(int) signal + to the QCoreApplication::exit(int) slot. + + \sa quit() +*/ +ReturnedValue QtObject::method_exit(CallContext *ctx) +{ + if (ctx->argc() != 1) + V4THROW_ERROR("Qt.exit(): Invalid arguments"); + + int retCode = ctx->args()[0].toNumber(); + + QQmlEnginePrivate::get(ctx->engine()->qmlEngine())->sendExit(retCode); + return QV4::Encode::undefined(); +} + +/*! \qmlmethod object Qt::createQmlObject(string qml, object parent, string filepath) Returns a new object created from the given \a string of QML which will have the specified \a parent, @@ -1029,7 +1061,9 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx) struct Error { static ReturnedValue create(QV4::ExecutionEngine *v4, const QList<QQmlError> &errors) { Scope scope(v4); - QString errorstr = QLatin1String("Qt.createQmlObject(): failed to create object: "); + QString errorstr; + // '+=' reserves extra capacity. Follow-up appending will be probably free. + errorstr += QLatin1String("Qt.createQmlObject(): failed to create object: "); QV4::ScopedArrayObject qmlerrors(scope, v4->newArrayObject()); QV4::ScopedObject qmlerror(scope); @@ -1269,24 +1303,24 @@ ReturnedValue QtObject::method_locale(CallContext *ctx) return QQmlLocale::locale(ctx->engine(), code); } -Heap::QQmlBindingFunction::QQmlBindingFunction(const QV4::FunctionObject *originalFunction) - : QV4::Heap::FunctionObject(originalFunction->scope(), originalFunction->name()) - , originalFunction(originalFunction->d()) +void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *originalFunction) { + QV4::Heap::FunctionObject::init(originalFunction->scope(), originalFunction->name()); + bindingLocation = new QQmlSourceLocation; + this->originalFunction = originalFunction->d(); } void QQmlBindingFunction::initBindingLocation() { QV4::StackFrame frame = engine()->currentStackFrame(); - d()->bindingLocation.sourceFile = frame.source; - d()->bindingLocation.line = frame.line; + d()->bindingLocation->sourceFile = frame.source; + d()->bindingLocation->line = frame.line; } -ReturnedValue QQmlBindingFunction::call(const Managed *that, CallData *callData) +void QQmlBindingFunction::call(const Managed *that, Scope &scope, CallData *callData) { - Scope scope(static_cast<const QQmlBindingFunction*>(that)->engine()); ScopedFunctionObject function(scope, static_cast<const QQmlBindingFunction*>(that)->d()->originalFunction); - return function->call(callData); + function->call(scope, callData); } void QQmlBindingFunction::markObjects(Heap::Base *that, ExecutionEngine *e) @@ -1404,8 +1438,9 @@ ReturnedValue QtObject::method_get_styleHints(CallContext *ctx) } -QV4::Heap::ConsoleObject::ConsoleObject() +void QV4::Heap::ConsoleObject::init() { + Object::init(); QV4::Scope scope(internalClass->engine); QV4::ScopedObject o(scope, this); @@ -1462,28 +1497,42 @@ static QString jsStack(QV4::ExecutionEngine *engine) { static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *ctx, bool printStack = false) { + QLoggingCategory *loggingCategory = 0; QString result; QV4::ExecutionEngine *v4 = ctx->d()->engine; - for (int i = 0; i < ctx->argc(); ++i) { - if (i != 0) + int start = 0; + if (ctx->argc() > 0) { + if (const QObjectWrapper* wrapper = ctx->args()[0].as<QObjectWrapper>()) { + if (QQmlLoggingCategory* category = qobject_cast<QQmlLoggingCategory*>(wrapper->object())) { + if (category->category()) + loggingCategory = category->category(); + else + V4THROW_ERROR("A QmlLoggingCatgory was provided without a valid name"); + start = 1; + } + } + } + + + for (int i = start; i < ctx->argc(); ++i) { + if (i != start) result.append(QLatin1Char(' ')); if (ctx->args()[i].as<ArrayObject>()) - result.append(QLatin1Char('[') + ctx->args()[i].toQStringNoThrow() + QLatin1Char(']')); + result += QLatin1Char('[') + ctx->args()[i].toQStringNoThrow() + QLatin1Char(']'); else result.append(ctx->args()[i].toQStringNoThrow()); } - if (printStack) { - result.append(QLatin1Char('\n')); - result.append(jsStack(v4)); - } + if (printStack) + result += QLatin1Char('\n') + jsStack(v4); static QLoggingCategory qmlLoggingCategory("qml"); static QLoggingCategory jsLoggingCategory("js"); - QLoggingCategory *loggingCategory = v4->qmlEngine() ? &qmlLoggingCategory : &jsLoggingCategory; + if (!loggingCategory) + loggingCategory = v4->qmlEngine() ? &qmlLoggingCategory : &jsLoggingCategory; QV4::StackFrame frame = v4->currentStackFrame(); const QByteArray baSource = frame.source.toUtf8(); const QByteArray baFunction = frame.function.toUtf8(); @@ -1513,6 +1562,8 @@ static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *c return QV4::Encode::undefined(); } +DEFINE_OBJECT_VTABLE(ConsoleObject); + QV4::ReturnedValue ConsoleObject::method_error(CallContext *ctx) { return writeToConsole(Error, ctx); @@ -1995,6 +2046,31 @@ ReturnedValue GlobalExtensions::method_string_arg(CallContext *ctx) return ctx->d()->engine->newString(value.arg(arg->toQString()))->asReturnedValue(); } +/*! +\qmlmethod Qt::callLater(function) +\qmlmethod Qt::callLater(function, argument1, argument2, ...) +\since 5.8 +Use this function to eliminate redundant calls to a function or signal. + +The function passed as the first argument to Qt.callLater() +will be called later, once the QML engine returns to the event loop. + +When this function is called multiple times in quick succession with the +same function as its first argument, that function will be called only once. + +For example: +\snippet qml/qtLater.qml 0 + +Any additional arguments passed to Qt.callLater() will +be passed on to the function invoked. Note that if redundant calls +are eliminated, then only the last set of arguments will be passed to the +function. +*/ +ReturnedValue QtObject::method_callLater(CallContext *ctx) +{ + QV8Engine *v8engine = ctx->engine()->v8Engine; + return v8engine->delayedCallQueue()->addUniquelyAndExecuteLater(ctx); +} QT_END_NAMESPACE diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index dc806c6031..7602a92582 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -64,7 +64,7 @@ namespace QV4 { namespace Heap { struct QtObject : Object { - QtObject(QQmlEngine *qmlEngine); + void init(QQmlEngine *qmlEngine); QObject *platform; QObject *application; @@ -77,14 +77,18 @@ struct QtObject : Object { }; struct ConsoleObject : Object { - ConsoleObject(); + void init(); }; struct QQmlBindingFunction : FunctionObject { - QQmlBindingFunction(const QV4::FunctionObject *originalFunction); + void init(const QV4::FunctionObject *originalFunction); + void destroy() { + delete bindingLocation; + Object::destroy(); + } Pointer<FunctionObject> originalFunction; // Set when the binding is created later - QQmlSourceLocation bindingLocation; + QQmlSourceLocation *bindingLocation; }; } @@ -122,6 +126,7 @@ struct QtObject : Object static ReturnedValue method_btoa(CallContext *ctx); static ReturnedValue method_atob(CallContext *ctx); static ReturnedValue method_quit(CallContext *ctx); + static ReturnedValue method_exit(CallContext *ctx); static ReturnedValue method_resolvedUrl(CallContext *ctx); static ReturnedValue method_createQmlObject(CallContext *ctx); static ReturnedValue method_createComponent(CallContext *ctx); @@ -135,6 +140,8 @@ struct QtObject : Object #endif static ReturnedValue method_get_styleHints(CallContext *ctx); + static ReturnedValue method_callLater(CallContext *ctx); + private: void addAll(); ReturnedValue findAndAdd(const QString *name, bool &foundProperty) const; @@ -142,9 +149,7 @@ private: struct ConsoleObject : Object { - typedef Heap::ConsoleObject Data; - const Data *d() const { return static_cast<const Data *>(Object::d()); } - Data *d() { return static_cast<Data *>(Object::d()); } + V4_OBJECT2(ConsoleObject, Object) static ReturnedValue method_error(CallContext *ctx); static ReturnedValue method_log(CallContext *ctx); @@ -186,7 +191,7 @@ struct QQmlBindingFunction : public QV4::FunctionObject void initBindingLocation(); // from caller stack trace - static ReturnedValue call(const Managed *that, CallData *callData); + static void call(const Managed *that, Scope &scope, CallData *callData); static void markObjects(Heap::Base *that, ExecutionEngine *e); }; diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 46fd4fbbeb..b0599dd0a2 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -150,6 +150,7 @@ QV8Engine::QV8Engine(QJSEngine* qq) m_v4Engine = new QV4::ExecutionEngine; m_v4Engine->v8Engine = this; + m_delayedCallQueue.init(m_v4Engine); QV4::QObjectWrapper::initializeBindings(m_v4Engine); } @@ -159,18 +160,23 @@ QV8Engine::~QV8Engine() qDeleteAll(m_extensionData); m_extensionData.clear(); +#if !defined(QT_NO_XMLSTREAMREADER) && QT_CONFIG(qml_network) qt_rem_qmlxmlhttprequest(m_v4Engine, m_xmlHttpRequestData); m_xmlHttpRequestData = 0; +#endif + delete m_listModelData; m_listModelData = 0; delete m_v4Engine; } +#if QT_CONFIG(qml_network) QNetworkAccessManager *QV8Engine::networkAccessManager() { return QQmlEnginePrivate::get(m_engine)->getNetworkAccessManager(); } +#endif const QSet<QString> &QV8Engine::illegalNames() const { @@ -189,8 +195,10 @@ void QV8Engine::initializeGlobal() QQmlDateExtension::registerExtension(m_v4Engine); QQmlNumberExtension::registerExtension(m_v4Engine); +#if !defined(QT_NO_XMLSTREAMREADER) && QT_CONFIG(qml_network) qt_add_domexceptions(m_v4Engine); m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(m_v4Engine); +#endif qt_add_sqlexceptions(m_v4Engine); diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h index 2cfa996409..0cbe34fd30 100644 --- a/src/qml/qml/v8/qv8engine_p.h +++ b/src/qml/qml/v8/qv8engine_p.h @@ -67,6 +67,7 @@ #include <private/qv4value_p.h> #include <private/qv4identifier_p.h> #include <private/qv4context_p.h> +#include <private/qqmldelayedcallqueue_p.h> QT_BEGIN_NAMESPACE @@ -76,12 +77,6 @@ namespace QV4 { struct QObjectMethod; } -// Uncomment the following line to enable global handle debugging. When enabled, all the persistent -// handles allocated using qPersistentNew() (or registered with qPersistentRegsiter()) and disposed -// with qPersistentDispose() are tracked. If you try and do something illegal, like double disposing -// a handle, qFatal() is called. -// #define QML_GLOBAL_HANDLE_DEBUGGING - #define V4THROW_ERROR(string) \ return ctx->engine()->throwError(QString::fromUtf8(string)); @@ -184,6 +179,7 @@ public: QQmlEngine *engine() { return m_engine; } QJSEngine *publicEngine() { return q; } QV4::ReturnedValue global(); + QQmlDelayedCallQueue *delayedCallQueue() { return &m_delayedCallQueue; } void *xmlHttpRequestData() { return m_xmlHttpRequestData; } @@ -192,10 +188,12 @@ public: void freezeObject(const QV4::Value &value); +#if QT_CONFIG(qml_network) // Return the network access manager for this engine. By default this returns the network // access manager of the QQmlEngine. It is overridden in the case of a threaded v8 // instance (like in WorkerScript). virtual QNetworkAccessManager *networkAccessManager(); +#endif // Return the list of illegal id names (the names of the properties on the global object) const QSet<QString> &illegalNames() const; @@ -217,6 +215,7 @@ public: protected: QJSEngine* q; QQmlEngine *m_engine; + QQmlDelayedCallQueue m_delayedCallQueue; QV4::ExecutionEngine *m_v4Engine; diff --git a/src/qml/qml/v8/v8.pri b/src/qml/qml/v8/v8.pri index 3d6a012481..4592022939 100644 --- a/src/qml/qml/v8/v8.pri +++ b/src/qml/qml/v8/v8.pri @@ -9,4 +9,3 @@ SOURCES += \ $$PWD/qv4domerrors.cpp \ $$PWD/qv4sqlerrors.cpp \ $$PWD/qqmlbuiltinfunctions.cpp - |