diff options
Diffstat (limited to 'src/qml/qml')
65 files changed, 2431 insertions, 2159 deletions
diff --git a/src/qml/qml/ftw/ftw.pri b/src/qml/qml/ftw/ftw.pri index a671cfa12d..addf1d9ff8 100644 --- a/src/qml/qml/ftw/ftw.pri +++ b/src/qml/qml/ftw/ftw.pri @@ -11,7 +11,6 @@ HEADERS += \ $$PWD/qdeletewatcher_p.h \ $$PWD/qrecyclepool_p.h \ $$PWD/qflagpointer_p.h \ - $$PWD/qpointervaluepair_p.h \ $$PWD/qlazilyallocated_p.h \ $$PWD/qqmlnullablevalue_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..cc394b78cb 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 \ @@ -39,7 +38,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 +48,8 @@ SOURCES += \ $$PWD/qqmltypewrapper.cpp \ $$PWD/qqmlfileselector.cpp \ $$PWD/qqmlobjectcreator.cpp \ - $$PWD/qqmldirparser.cpp + $$PWD/qqmldirparser.cpp \ + $$PWD/qqmldelayedcallqueue.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 \ @@ -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,8 @@ HEADERS += \ $$PWD/qqmlfileselector_p.h \ $$PWD/qqmlfileselector.h \ $$PWD/qqmlobjectcreator_p.h \ - $$PWD/qqmldirparser_p.h + $$PWD/qqmldirparser_p.h \ + $$PWD/qqmldelayedcallqueue_p.h include(ftw/ftw.pri) include(v8/v8.pri) diff --git a/src/qml/qml/qqmlabstractbinding_p.h b/src/qml/qml/qqmlabstractbinding_p.h index 674178153a..0ccfae4610 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 @@ -83,7 +82,7 @@ public: // 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) {} @@ -113,8 +114,15 @@ protected: inline void setNextBinding(QQmlAbstractBinding *); int 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 index 55562a5307..e98663adfe 100644 --- a/src/qml/qml/qqmlaccessors_p.h +++ b/src/qml/qml/qqmlaccessors_p.h @@ -102,11 +102,15 @@ class QQmlNotifier; } \ } while (false); -#define QML_PRIVATE_ACCESSOR(clazz, cpptype, name, variable) \ +#define QML_PRIVATE_ACCESSOR(clazz, cpptype, name, variable, setter) \ 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; \ + } \ + static void clazz ## _ ## name ## Write(QObject *o, void *rv) \ + { \ + static_cast<clazz *>(o)->setter(*static_cast<cpptype *>(rv)); \ } #define QML_PROPERTY_NAME(name) #name, sizeof #name - 1 @@ -115,6 +119,7 @@ class QQmlAccessors { public: void (*read)(QObject *object, void *output); + void (*write)(QObject *object, void *output); void (*notifier)(QObject *object, QQmlNotifier **notifier); }; diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp index 57cdd3f47f..8c342e0592 100644 --- a/src/qml/qml/qqmlapplicationengine.cpp +++ b/src/qml/qml/qqmlapplicationengine.cpp @@ -211,11 +211,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 +225,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..10d16a8a12 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -42,8 +42,8 @@ #include "qqml.h" #include "qqmlcontext.h" #include "qqmlinfo.h" -#include "qqmlcompiler_p.h" #include "qqmldata_p.h" +#include "qqmlaccessors_p.h" #include <private/qqmlprofiler_p.h> #include <private/qqmlexpression_p.h> #include <private/qqmlscriptstring_p.h> @@ -57,27 +57,28 @@ 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(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(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 +91,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(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(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(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 +157,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 +166,73 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) if (QQmlData::wasDeleted(targetObject())) return; + // Check for a binding update loop + if (Q_UNLIKELY(updatingFlag())) { + QQmlProperty p = QQmlPropertyPrivate::restore(targetObject(), getPropertyData(), 0); + QQmlAbstractBinding::printBindingLoopError(p); + return; + } + setUpdatingFlag(true); + + DeleteWatcher watcher(this); + 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); - QQmlAbstractBinding::printBindingLoopError(p); - return; - } + if (canUseAccessor()) + flags.setFlag(QQmlPropertyData::BypassInterceptor); QQmlBindingProfiler prof(ep->profiler, this, f); - setUpdatingFlag(true); - - QQmlJavaScriptExpression::DeleteWatcher watcher(this); + doUpdate(this, watcher, flags, scope, f); - QQmlPropertyData pd = getPropertyData(); + if (!watcher.wasDeleted()) + setUpdatingFlag(false); +} - if (pd.propType == qMetaTypeId<QQmlBinding *>()) { +// 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(QQmlBinding *binding, const DeleteWatcher &, + QQmlPropertyData::WriteFlags flags, QV4::Scope &, + const QV4::ScopedFunctionObject &) Q_DECL_OVERRIDE Q_DECL_FINAL + { + QQmlPropertyData pd = getPropertyData(); int idx = pd.coreIndex; Q_ASSERT(idx != -1); - QQmlBinding *t = this; int status = -1; - void *a[] = { &t, 0, &status, &flags }; + void *a[] = { &binding, 0, &status, &flags }; QMetaObject::metacall(*m_target, QMetaObject::WriteProperty, idx, a); + } +}; - } else { +template<int StaticPropType> +class GenericBinding: public QQmlBinding +{ +protected: + void doUpdate(QQmlBinding *binding, 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); + binding->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()) { @@ -214,59 +252,65 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) ep->dereferenceScarceResources(); } - if (!watcher.wasDeleted()) - setUpdatingFlag(false); -} - -// 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) -{ - 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); + // 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) + { + QQmlPropertyData pd = getPropertyData(); + 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; + Q_ASSERT(targetObject()); + + if (Q_LIKELY(!isUndefined && !pd.isValueTypeVirtual())) { + 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, 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 QV4::Value &result, + bool isUndefined, QQmlPropertyData::WriteFlags flags) +{ QQmlEngine *engine = context()->engine; QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine); @@ -378,11 +422,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() @@ -409,11 +454,18 @@ 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())) { + int coreIndex = getPropertyCoreIndex(); + if (coreIndex == -1 || interceptorMetaObject->intercepts(coreIndex)) + m_nextBinding.clearFlag2(); + } + if (e) update(flags); } @@ -509,4 +561,39 @@ QQmlPropertyData QQmlBinding::getPropertyData() const return d; } +Q_ALWAYS_INLINE int QQmlBinding::getPropertyCoreIndex() const +{ + int coreIndex; + int valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(m_targetIndex, &coreIndex); + if (valueTypeIndex != -1) { + return -1; + } else { + return coreIndex; + } +} + +QQmlBinding *QQmlBinding::newBinding(const QQmlPropertyData *property) +{ + 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>; + } +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h index 7814b9dee8..0c797d7df2 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,12 +72,12 @@ 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 &); @@ -86,13 +85,11 @@ public: 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,28 @@ public: QVariant evaluate(); - virtual QString expressionIdentifier(); - virtual void expressionChanged(); + QString expressionIdentifier() Q_DECL_OVERRIDE; + void expressionChanged() Q_DECL_OVERRIDE; + +protected: + virtual void doUpdate(QQmlBinding *binding, const DeleteWatcher &watcher, + QQmlPropertyData::WriteFlags flags, QV4::Scope &scope, + const QV4::ScopedFunctionObject &f) = 0; + + QQmlPropertyData getPropertyData() const; + int getPropertyCoreIndex() const; + int getPropertyType() const; + + bool slowWrite(const QQmlPropertyData &core, 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(const QQmlPropertyData *property); }; bool QQmlBinding::updatingFlag() const diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index c6a7cde240..ef837183db 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> @@ -83,9 +81,7 @@ 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 += 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 c64851cac5..9c7b4fe1c0 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" @@ -335,14 +334,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(); @@ -356,10 +352,7 @@ void QQmlComponentPrivate::clear() typeData = 0; } - if (cc) { - cc->release(); - cc = 0; - } + compilationUnit = nullptr; } /*! @@ -393,8 +386,6 @@ QQmlComponent::~QQmlComponent() d->typeData->unregisterCallback(d); d->typeData->release(); } - if (d->cc) - d->cc->release(); } /*! @@ -422,7 +413,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; @@ -512,11 +503,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); } /*! @@ -531,10 +519,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); } @@ -546,11 +533,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; - d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName))); } /*! @@ -562,25 +546,22 @@ 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; d->loadUrl(d->engine->baseUrl().resolved(QUrl::fromLocalFile(fileName)), mode); } /*! \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; } @@ -873,7 +854,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; @@ -893,11 +874,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; @@ -914,7 +897,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; } @@ -1058,9 +1041,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); @@ -1193,7 +1176,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); @@ -1282,7 +1265,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(); @@ -1515,7 +1498,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); } } @@ -1546,7 +1529,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..6621f48e20 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) { @@ -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/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 ad2456a68d..a9f2acdb06 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.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. @@ -179,10 +185,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; @@ -223,7 +229,7 @@ public: static inline void flushPendingBinding(QObject *, int coreIndex); - static void ensurePropertyCache(QJSEngine *engine, QObject *object); + static QQmlPropertyCache *ensurePropertyCache(QJSEngine *engine, QObject *object); private: // For attachedProperties 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/qqmlmemoryprofiler_p.h b/src/qml/qml/qqmldelayedcallqueue_p.h index 4b0ba823ba..ef899170a2 100644 --- a/src/qml/qml/qqmlmemoryprofiler_p.h +++ b/src/qml/qml/qqmldelayedcallqueue_p.h @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef QQMLMEMORYPROFILER_H -#define QQMLMEMORYPROFILER_H +#ifndef QQMLDELAYEDCALLQUEUE_P_H +#define QQMLDELAYEDCALLQUEUE_P_H // // W A R N I N G @@ -51,37 +51,54 @@ // We mean it. // -#include <private/qtqmlglobal_p.h> +#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 -class QUrl; - -class Q_QML_PRIVATE_EXPORT QQmlMemoryScope +class QV8Engine; +class QQmlDelayedCallQueue : public QObject { + Q_OBJECT public: - explicit QQmlMemoryScope(const QUrl &url); - explicit QQmlMemoryScope(const char *string); - ~QQmlMemoryScope(); + QQmlDelayedCallQueue(); + ~QQmlDelayedCallQueue(); + + void init(QV4::ExecutionEngine *); + + QV4::ReturnedValue addUniquelyAndExecuteLater(QV4::CallContext *ctx); + +public Q_SLOTS: + void ticked(); private: - bool pushed; -}; + struct DelayedFunctionCall + { + DelayedFunctionCall() {} + DelayedFunctionCall(QV4::PersistentValue function) + : m_function(function), m_guarded(false) { } -class Q_QML_PRIVATE_EXPORT QQmlMemoryProfiler -{ -public: - static void enable(); - static void disable(); - static bool isEnabled(); + void execute(QV4::ExecutionEngine *engine) const; - static void clear(); - static void stats(int *allocCount, int *bytesAllocated); - static void save(const char *filename); -}; + QV4::PersistentValue m_function; + QV4::PersistentValue m_args; + QQmlGuard<QObject> m_objectGuard; + bool m_guarded; + }; -#define QML_MEMORY_SCOPE_URL(url) QQmlMemoryScope _qml_memory_scope(url) -#define QML_MEMORY_SCOPE_STRING(s) QQmlMemoryScope _qml_memory_scope(s) + void storeAnyArguments(DelayedFunctionCall& dfc, const QV4::CallData *callData, int offset, QV4::ExecutionEngine *engine); + void executeAllExpired_Later(); + + QV4::ExecutionEngine *m_engine; + QVector<DelayedFunctionCall> m_delayedFunctionCalls; + QMetaMethod m_tickedMethod; + bool m_callbackOutstanding; +}; QT_END_NAMESPACE -#endif // QQMLMEMORYPROFILER_H + +#endif // QQMLDELAYEDCALLQUEUE_P_H diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 28f8bf4855..e4e7530af7 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> + +#ifndef QT_NO_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> @@ -94,17 +91,15 @@ #include <private/qqmlinstantiator_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) @@ -182,6 +177,7 @@ 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"); @@ -493,6 +489,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 @@ -531,6 +531,7 @@ The following functions are also on the Qt object. \li application.active \li application.state \li application.layoutDirection + \li application.font \endlist */ @@ -601,12 +602,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), +#ifndef QT_NO_NETWORK + networkAccessManager(0), networkAccessManagerFactory(0), +#endif + urlInterceptor(0), scarceResourcesRefCount(0), importDatabase(e), typeLoader(e), uniqueId(1), incubatorCount(0), incubationController(0) { } @@ -614,7 +620,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); @@ -635,7 +640,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 @@ -643,12 +648,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) @@ -677,7 +679,7 @@ QQmlData::QQmlData() hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false), hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false), bindingBitsSize(0), bindingBits(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(); @@ -845,8 +847,8 @@ void QQmlData::flushPendingBindingImpl(int coreIndex) b = b->nextBinding(); if (b && b->targetPropertyIndex() == coreIndex) - b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor | - QQmlPropertyPrivate::DontRemoveBinding); + b->setEnabled(true, QQmlPropertyData::BypassInterceptor | + QQmlPropertyData::DontRemoveBinding); } bool QQmlEnginePrivate::baseModulesUninitialized = true; @@ -1066,7 +1068,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); + } +} +#ifndef QT_NO_NETWORK /*! Sets the \a factory to use for creating QNetworkAccessManager(s). @@ -1095,16 +1107,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); @@ -1143,6 +1145,7 @@ QNetworkAccessManager *QQmlEngine::networkAccessManager() const Q_D(const QQmlEngine); return d->getNetworkAccessManager(); } +#endif // QT_NO_NETWORK /*! @@ -1405,7 +1408,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; @@ -1636,13 +1639,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; } @@ -1665,7 +1668,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 { @@ -1801,14 +1804,16 @@ void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex) QQmlData_setBit(this, obj, coreIndex * 2 + 1); } -void QQmlData::ensurePropertyCache(QJSEngine *engine, QObject *object) +QQmlPropertyCache *QQmlData::ensurePropertyCache(QJSEngine *engine, QObject *object) { Q_ASSERT(engine); QQmlData *ddata = QQmlData::get(object, /*create*/true); - if (ddata->propertyCache) - return; - ddata->propertyCache = QJSEnginePrivate::get(engine)->cache(object); - if (ddata->propertyCache) ddata->propertyCache->addref(); + if (!ddata->propertyCache) { + ddata->propertyCache = QJSEnginePrivate::get(engine)->cache(object); + if (ddata->propertyCache) + ddata->propertyCache->addref(); + } + return ddata->propertyCache; } void QQmlEnginePrivate::sendQuit() @@ -2219,9 +2224,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 +2236,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 +2248,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 +2261,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 +2271,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 +2291,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 +2325,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 +2357,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 +2365,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..132af78f80 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; +#ifndef QT_NO_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); +#ifndef QT_NO_NETWORK void setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *); QQmlNetworkAccessManagerFactory *networkAccessManagerFactory() const; QNetworkAccessManager *networkAccessManager() const; +#endif void setUrlInterceptor(QQmlAbstractUrlInterceptor* urlInterceptor); QQmlAbstractUrlInterceptor* urlInterceptor() const; diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 003cfa0112..949060f395 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; - +#ifndef QT_NO_NETWORK QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const; QNetworkAccessManager *getNetworkAccessManager() const; mutable QNetworkAccessManager *networkAccessManager; mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory; - +#endif QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders; QQmlAbstractUrlInterceptor* urlInterceptor; @@ -216,8 +220,8 @@ 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; @@ -260,7 +264,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/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..741c25e206 100644 --- a/src/qml/qml/qqmlexpression_p.h +++ b/src/qml/qml/qqmlexpression_p.h @@ -57,7 +57,6 @@ #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 +76,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..4769402855 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; + +#ifndef QT_NO_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; - +#ifndef QT_NO_NETWORK QQmlFileNetworkReply *reply; +#endif }; +#ifndef QT_NO_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 // QT_NO_NETWORK QQmlFilePrivate::QQmlFilePrivate() -: error(None), reply(0) +: error(None) +#ifndef QT_NO_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() { +#ifndef QT_NO_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; +#ifndef QT_NO_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 { +#ifndef QT_NO_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 { +#ifndef QT_NO_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(); } +#ifndef QT_NO_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..3dd683a2cd 100644 --- a/src/qml/qml/qqmlfile.h +++ b/src/qml/qml/qqmlfile.h @@ -80,10 +80,12 @@ public: void clear(); void clear(QObject *); +#ifndef QT_NO_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 b51c78b8d4..9393f74a8d 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())); @@ -913,7 +913,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 +921,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; @@ -1702,10 +1702,7 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader, resolvedPath += Slash; foreach (const QString &suffix, suffixes) { - QString pluginFileName = prefix; - - pluginFileName += baseName; - pluginFileName += suffix; + QString pluginFileName = prefix + baseName + suffix; QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + pluginFileName); if (!absolutePath.isEmpty()) @@ -1820,7 +1817,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 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 8ba4b5eba1..5d96240e5b 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,12 @@ QQmlJavaScriptExpression::~QQmlJavaScriptExpression() void QQmlJavaScriptExpression::setNotifyOnValueChanged(bool v) { activeGuards.setFlagValue(v); - if (!v) clearGuards(); + if (!v) clearActiveGuards(); } void QQmlJavaScriptExpression::resetNotifyOnValueChanged() { - clearGuards(); + clearActiveGuards(); } void QQmlJavaScriptExpression::setContext(QQmlContextData *context) @@ -147,16 +148,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 +158,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 +178,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 +186,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 +196,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 +213,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 +235,17 @@ void QQmlPropertyCapture::captureProperty(QQmlNotifier *n) g->connect(n); } - expression->activeGuards.prepend(g); + if (duration == OnlyOnce) + 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 +284,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 +304,40 @@ void QQmlPropertyCapture::registerQmlDependencies(QV4::ExecutionEngine *engine, if (!capture) 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 +421,18 @@ void QQmlJavaScriptExpression::createQmlBinding(QQmlContextData *ctxt, QObject * } -void QQmlJavaScriptExpression::clearGuards() +void QQmlJavaScriptExpression::clearActiveGuards() { while (QQmlJavaScriptExpressionGuard *g = activeGuards.takeFirst()) g->Delete(); } +void QQmlJavaScriptExpression::clearPermanentGuards() +{ + 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..a5c7a80153 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, @@ -159,10 +158,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 +180,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/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..271b4f1b31 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); } @@ -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..c94db8e168 100644 --- a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp +++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp @@ -41,6 +41,8 @@ QT_BEGIN_NAMESPACE +#ifndef QT_NO_NETWORK + /*! \class QQmlNetworkAccessManagerFactory \since 5.0 @@ -101,4 +103,6 @@ QQmlNetworkAccessManagerFactory::~QQmlNetworkAccessManagerFactory() implementation of this method is reentrant. */ +#endif //QT_NO_NETWORK + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.h b/src/qml/qml/qqmlnetworkaccessmanagerfactory.h index 8e3b94fad3..ba3561b9f4 100644 --- a/src/qml/qml/qqmlnetworkaccessmanagerfactory.h +++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.h @@ -45,6 +45,7 @@ QT_BEGIN_NAMESPACE +#ifndef QT_NO_NETWORK class QNetworkAccessManager; class Q_QML_EXPORT QQmlNetworkAccessManagerFactory @@ -55,6 +56,8 @@ public: }; +#endif //QT_NO_NETWORK + QT_END_NAMESPACE #endif // QQMLNETWORKACCESSMANAGERFACTORY_H diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 831965f36a..3000f3e695 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -54,6 +54,7 @@ #include <private/qqmlscriptstring_p.h> #include <private/qqmlpropertyvalueinterceptor_p.h> #include <private/qqmlvaluetypeproxybinding_p.h> +#include <private/qqmlaccessors_p.h> QT_USE_NAMESPACE @@ -69,12 +70,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) , activeVMEDataForRootContext(activeVMEDataForRootContext) { init(parentContext); @@ -82,24 +82,26 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile sharedState = new QQmlObjectCreatorSharedState; topLevelCreator = true; 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) , activeVMEDataForRootContext(0) { init(parentContext); @@ -114,10 +116,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 +162,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 +184,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 +202,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 +239,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 +258,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,11 +278,7 @@ 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; @@ -317,16 +306,14 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const } 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)); } 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) { @@ -334,8 +321,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const _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); @@ -344,8 +330,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const _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 +338,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 +358,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 +377,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: { @@ -422,8 +399,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const 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); + property->writeProperty(_qobject, &buffer, propertyWriteFlags); } } break; @@ -432,16 +408,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 +428,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 +436,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 +488,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 +500,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 +513,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 +526,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: @@ -576,39 +538,34 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const 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> >()) { 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> >()) { 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> >()) { 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> >()) { 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>()) { QJSValue value; @@ -623,8 +580,7 @@ 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; } @@ -640,8 +596,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const break; } - argv[0] = value.data(); - QMetaObject::metacall(_qobject, QMetaObject::WriteProperty, property->coreIndex, argv); + property->writeProperty(_qobject, value.data(), propertyWriteFlags); } break; } @@ -658,14 +613,14 @@ 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) { @@ -673,7 +628,7 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) 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); } @@ -691,7 +646,7 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) 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) { @@ -709,9 +664,17 @@ 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()) { @@ -736,7 +699,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) { @@ -763,8 +726,8 @@ 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); @@ -816,7 +779,7 @@ 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; } @@ -828,7 +791,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con QQmlPropertyPrivate::removeBinding(_bindingTarget, 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()); @@ -842,8 +805,6 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con 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, @@ -853,6 +814,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con if (_valueTypeProperty) targetCorePropertyData = QQmlPropertyPrivate::saveValueType(*_valueTypeProperty, _qobject->metaObject(), property->coreIndex, engine); + QQmlBinding *qmlBinding = QQmlBinding::create(&targetCorePropertyData, function, _scopeObject, context); sharedState->allCreatedBindings.push(QQmlAbstractBinding::Ptr(qmlBinding)); qmlBinding->setTarget(_bindingTarget, targetCorePropertyData); @@ -943,8 +905,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con 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 }; @@ -1009,9 +971,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); @@ -1026,18 +988,17 @@ void QQmlObjectCreator::setupFunctions() 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 +1011,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,23 +1023,22 @@ 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())); + compilationUnit, obj, type->qmlTypeName(), context->url())); instance = type->create(); if (!instance) { recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex))); @@ -1097,17 +1059,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 +1115,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 +1159,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); @@ -1224,8 +1184,8 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru QQmlData *data = QQmlData::get(b->targetObject()); Q_ASSERT(data); data->clearPendingBindingBit(b->targetPropertyIndex()); - b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor | - QQmlPropertyPrivate::DontRemoveBinding); + b->setEnabled(true, QQmlPropertyData::BypassInterceptor | + QQmlPropertyData::DontRemoveBinding); if (watcher.hasRecursed() || interrupt.shouldInterrupt()) return 0; @@ -1294,7 +1254,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 +1269,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 +1285,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/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 df2ff05de1..b3eb0a5619 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" @@ -317,8 +317,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) 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 } @@ -859,7 +858,7 @@ 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); @@ -1035,15 +1034,13 @@ QVariant QQmlPropertyPrivate::readValueProperty() } else if (core.isQList()) { QQmlListProperty<QObject> prop; - void *args[] = { &prop, 0 }; - QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args); + 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 { @@ -1060,7 +1057,7 @@ QVariant QQmlPropertyPrivate::readValueProperty() value = QVariant(core.propType, (void*)0); args[0] = value.data(); } - QMetaObject::metacall(object, QMetaObject::ReadProperty, core.coreIndex, args); + core.readPropertyWithArgs(object, args); if (core.propType != QMetaType::QVariant && args[0] != value.data()) return QVariant((QVariant::Type)core.propType, args[0]); @@ -1148,7 +1145,7 @@ 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); } @@ -1157,10 +1154,10 @@ bool QQmlPropertyPrivate::writeValueProperty(QObject *object, const QQmlPropertyData &core, const QVariant &value, - QQmlContextData *context, WriteFlags flags) + QQmlContextData *context,QQmlPropertyData::WriteFlags flags) { // Remove any existing bindings on this property - if (!(flags & DontRemoveBinding) && object) + if (!(flags & QQmlPropertyData::DontRemoveBinding) && object) removeBinding(object, core.encodedIndex()); bool rv = false; @@ -1190,145 +1187,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); 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)); } else { QQmlType *type = QQmlMetaType::qmlType(QQmlMetaType::listType(property.propType)); - if (!type) return false; + 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); @@ -1368,7 +1371,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()); @@ -1411,8 +1415,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; } @@ -1428,10 +1431,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(); } /*! @@ -1513,7 +1515,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; diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h index 58fea9c239..9398c74621 100644 --- a/src/qml/qml/qqmlproperty_p.h +++ b/src/qml/qml/qqmlproperty_p.h @@ -68,13 +68,6 @@ 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; @@ -97,7 +90,7 @@ 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, @@ -105,9 +98,9 @@ public: static bool writeValueProperty(QObject *, const QQmlPropertyData &, const QVariant &, QQmlContextData *, - WriteFlags flags = 0); + QQmlPropertyData::WriteFlags flags = 0); static bool write(QObject *, const QQmlPropertyData &, const QVariant &, - QQmlContextData *, WriteFlags flags = 0); + QQmlContextData *, QQmlPropertyData::WriteFlags flags = 0); static void findAliasTarget(QObject *, int, QObject **, int *); enum BindingFlag { @@ -116,7 +109,7 @@ 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); @@ -144,7 +137,7 @@ public: QQmlBoundSignalExpression *); static void takeSignalExpression(const QQmlProperty &that, QQmlBoundSignalExpression *); - static bool write(const QQmlProperty &that, const QVariant &, WriteFlags); + static bool write(const QQmlProperty &that, const QVariant &, QQmlPropertyData::WriteFlags); static int valueTypeCoreIndex(const QQmlProperty &that); static int bindingIndex(const QQmlProperty &that); static int bindingIndex(const QQmlPropertyData &that); @@ -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 0522aa93ee..322e519706 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -184,10 +184,16 @@ void QQmlPropertyData::load(const QMetaMethod &m) { coreIndex = m.methodIndex(); arguments = 0; + + propType = m.returnType(); + flags |= IsFunction; if (m.methodType() == QMetaMethod::Signal) flags |= IsSignal; - propType = m.returnType(); + else if (m.methodType() == QMetaMethod::Constructor) { + flags |= IsConstructor; + propType = QMetaType::QObjectStar; + } if (m.parameterCount()) { flags |= HasArguments; @@ -206,11 +212,15 @@ void QQmlPropertyData::load(const QMetaMethod &m) void QQmlPropertyData::lazyLoad(const QMetaMethod &m) { coreIndex = m.methodIndex(); + propType = QMetaType::Void; arguments = 0; flags |= IsFunction; if (m.methodType() == QMetaMethod::Signal) flags |= IsSignal; - propType = QMetaType::Void; + else if (m.methodType() == QMetaMethod::Constructor) { + flags |= IsConstructor; + propType = QMetaType::QObjectStar; + } const char *returnType = m.typeName(); if (!returnType) @@ -220,9 +230,10 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m) flags |= NotFullyResolved; } - if (m.parameterCount()) { + const int paramCount = m.parameterCount(); + if (paramCount) { flags |= HasArguments; - if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) { + if ((paramCount == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) { flags |= IsV4Function; } } @@ -249,11 +260,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) + : QQmlPropertyCache(e) { - Q_ASSERT(engine); Q_ASSERT(metaObject); update(metaObject); @@ -416,12 +424,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,34 +439,19 @@ 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 * @@ -523,11 +510,12 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, bool hasFastProperty = false; for (int ii = 0; ii < classInfoCount; ++ii) { int idx = ii + classInfoOffset; - - if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) { + QMetaClassInfo mci = metaObject->classInfo(idx); + const char *name = mci.name(); + if (0 == qstrcmp(name, "qt_HasQmlAccessors")) { hasFastProperty = true; - } else if (0 == qstrcmp(metaObject->classInfo(idx).name(), "DefaultProperty")) { - _defaultPropertyName = QString::fromUtf8(metaObject->classInfo(idx).value()); + } else if (0 == qstrcmp(name, "DefaultProperty")) { + _defaultPropertyName = QString::fromUtf8(mci.value()); } } @@ -610,7 +598,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; } @@ -802,48 +790,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); @@ -860,11 +806,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; } } @@ -891,11 +837,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 @@ -1296,6 +1246,215 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) } } +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) { + const QByteArrayDataPtr data = { const_cast<QByteArrayData*>(&mo.d.stringdata[i]) }; + hash.addData(QByteArray(data)); + } + + return true; +} + +QByteArray QQmlPropertyCache::checksum(bool *ok) +{ + if (!_checksum.isEmpty()) { + *ok = true; + 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(). @@ -1451,7 +1610,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); @@ -1506,39 +1666,53 @@ int *QQmlMetaObject::methodParameterTypes(int index, QVarLengthArray<int, 9> &du } 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); @@ -1546,4 +1720,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 96dbc72f32..750537e707 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -61,9 +61,11 @@ #include <QtCore/qvector.h> #include <private/qv4value_p.h> +#include <private/qqmlaccessors_p.h> QT_BEGIN_NAMESPACE +class QCryptographicHash; class QMetaProperty; class QQmlEngine; class QJSEngine; @@ -72,7 +74,8 @@ 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 @@ -115,9 +118,10 @@ public: IsSignalHandler = 0x00800000, // Function is a signal handler IsOverload = 0x01000000, // Function is an overload of another function IsCloned = 0x02000000, // The function was marked as cloned + IsConstructor = 0x04000000, // The function was marked is a constructor // Internal QQmlPropertyCache flags - NotFullyResolved = 0x04000000, // True if the type data is to be lazily resolved + NotFullyResolved = 0x08000000, // True if the type data is to be lazily resolved // Flags that are set based on the propType field PropTypeFlagMask = IsQObjectDerived | IsEnumType | IsQList | IsQmlBinding | IsQJSValue | @@ -156,12 +160,15 @@ public: bool isSignalHandler() const { return flags & IsSignalHandler; } bool isOverload() const { return flags & IsOverload; } bool isCloned() const { return flags & IsCloned; } + bool isConstructor() const { return flags & IsConstructor; } bool hasOverride() const { return !(flags & IsValueTypeVirtual) && !(flags & HasAccessors) && overrideIndex >= 0; } bool hasRevision() const { return !(flags & HasAccessors) && revision != 0; } + bool isFullyResolved() const { return !(flags & NotFullyResolved); } + // Returns -1 if not a value type virtual property inline int getValueTypeCoreIndex() const; @@ -223,6 +230,13 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyRawData::Flags) class QQmlPropertyData : public QQmlPropertyRawData { public: + enum WriteFlag { + BypassInterceptor = 0x01, + DontRemoveBinding = 0x02, + RemoveBindingOnAliasWrite = 0x04 + }; + Q_DECLARE_FLAGS(WriteFlags, WriteFlag) + inline QQmlPropertyData(); inline QQmlPropertyData(const QQmlPropertyRawData &); @@ -236,6 +250,33 @@ 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 (hasAccessors()) { + accessors->read(target, args[0]); + } else { + QMetaObject::metacall(target, QMetaObject::ReadProperty, coreIndex, args); + } + } + + bool writeProperty(QObject *target, void *value, WriteFlags flags) const + { + if (flags.testFlag(BypassInterceptor) && hasAccessors() && accessors->write) { + accessors->write(target, value); + } else { + int status = -1; + void *argv[] = { value, 0, &status, &flags }; + QMetaObject::metacall(target, QMetaObject::WriteProperty, coreIndex, argv); + } + return true; + } + private: friend class QQmlPropertyCache; void lazyLoad(const QMetaProperty &); @@ -326,6 +367,11 @@ public: void toMetaObjectBuilder(QMetaObjectBuilder &); + 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(); @@ -333,7 +379,8 @@ 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; @@ -394,6 +441,7 @@ private: QByteArray _dynamicStringData; QString _defaultPropertyName; QQmlPropertyCacheMethodArguments *argumentsCache; + QByteArray _checksum; }; // QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache. @@ -406,6 +454,8 @@ class QQmlEnginePrivate; class Q_QML_EXPORT QQmlMetaObject { public: + typedef QVarLengthArray<int, 9> ArgTypeStorage; + inline QQmlMetaObject(); inline QQmlMetaObject(QObject *); inline QQmlMetaObject(const QMetaObject *); @@ -425,7 +475,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); @@ -435,6 +486,9 @@ public: protected: QBiPointer<QQmlPropertyCache, const QMetaObject> _m; + int *methodParameterTypes(const QMetaMethod &method, ArgTypeStorage *argStorage, + QByteArray *unknownTypeError) const; + }; class QQmlObjectOrGadget: public QQmlMetaObject @@ -453,6 +507,20 @@ 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; }; QQmlPropertyData::QQmlPropertyData() @@ -502,6 +570,21 @@ inline QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) return p; } +// Returns this property cache's metaObject. May be null if it hasn't been created yet. +inline const QMetaObject *QQmlPropertyCache::metaObject() const +{ + return _metaObject; +} + +// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by +// QML +inline const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const +{ + while (_parent && (_metaObject == 0 || _ownMetaObject)) + return _parent->firstCppMetaObject(); + return _metaObject; +} + inline QQmlPropertyData *QQmlPropertyCache::property(int index) const { if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count())) @@ -514,6 +597,57 @@ 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 { @@ -635,6 +769,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/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 739a833a30..c54af43a6f 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -45,14 +45,16 @@ #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 <QtCore/qdir.h> #include <QtCore/qfile.h> +#include <QtCore/qdatetime.h> #include <QtCore/qdebug.h> #include <QtCore/qmutex.h> #include <QtCore/qthread.h> @@ -62,6 +64,8 @@ #include <QtCore/qwaitcondition.h> #include <QtQml/qqmlextensioninterface.h> +#include <functional> + #if defined (Q_OS_UNIX) #include <sys/types.h> #include <sys/stat.h> @@ -98,6 +102,8 @@ #endif DEFINE_BOOL_CONFIG_OPTION(dumpErrors, QML_DUMP_ERRORS); +DEFINE_BOOL_CONFIG_OPTION(diskCache, QML_DISK_CACHE); +DEFINE_BOOL_CONFIG_OPTION(forceDiskCacheRefresh, QML_FORCE_DISK_CACHE_REFRESH); QT_BEGIN_NAMESPACE @@ -110,8 +116,23 @@ namespace { LockHolder(LockType *l) : lock(*l) { lock.lock(); } ~LockHolder() { lock.unlock(); } }; + + struct DeferredCall + { + std::function<void()> callback; + ~DeferredCall() { callback(); } + }; + + template <typename Callback> + DeferredCall defer(Callback &&cb) + { + DeferredCall c; + c.callback = std::move(cb); + return c; + } } +#ifndef QT_NO_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 +152,7 @@ public slots: private: QQmlTypeLoader *l; }; +#endif // QT_NO_NETWORK class QQmlTypeLoaderThread : public QQmlThread { @@ -138,9 +160,10 @@ class QQmlTypeLoaderThread : public QQmlThread public: QQmlTypeLoaderThread(QQmlTypeLoader *loader); +#ifndef QT_NO_NETWORK QNetworkAccessManager *networkAccessManager() const; QQmlTypeLoaderNetworkReplyProxy *networkReplyProxy() const; - +#endif // QT_NO_NETWORK void load(QQmlDataBlob *b); void loadAsync(QQmlDataBlob *b); void loadWithStaticData(QQmlDataBlob *b, const QByteArray &); @@ -163,11 +186,13 @@ private: void initializeEngineMain(QQmlExtensionInterface *iface, const char *uri); QQmlTypeLoader *m_loader; +#ifndef QT_NO_NETWORK mutable QNetworkAccessManager *m_networkAccessManager; mutable QQmlTypeLoaderNetworkReplyProxy *m_networkReplyProxy; +#endif // QT_NO_NETWORK }; - +#ifndef QT_NO_NETWORK QQmlTypeLoaderNetworkReplyProxy::QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l) : l(l) { @@ -196,7 +221,7 @@ void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply) l->networkReplyProgress(reply, replySize, replySize); l->networkReplyFinished(reply); } - +#endif // QT_NO_NETWORK /*! \class QQmlDataBlob @@ -430,6 +455,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 +538,7 @@ void QQmlDataBlob::done() { } +#ifndef QT_NO_NETWORK /*! Invoked if there is a network error while fetching this blob. @@ -532,6 +591,7 @@ void QQmlDataBlob::networkError(QNetworkReply::NetworkError networkError) setError(error); } +#endif // QT_NO_NETWORK /*! Called if \a blob, which was previously waited for, has an error. @@ -730,12 +790,16 @@ void QQmlDataBlob::ThreadData::setProgress(quint8 v) } QQmlTypeLoaderThread::QQmlTypeLoaderThread(QQmlTypeLoader *loader) -: m_loader(loader), m_networkAccessManager(0), m_networkReplyProxy(0) +: m_loader(loader) +#ifndef QT_NO_NETWORK +, m_networkAccessManager(0), m_networkReplyProxy(0) +#endif // QT_NO_NETWORK { // Do that after initializing all the members. startup(); } +#ifndef QT_NO_NETWORK QNetworkAccessManager *QQmlTypeLoaderThread::networkAccessManager() const { Q_ASSERT(isThisThread()); @@ -753,6 +817,7 @@ QQmlTypeLoaderNetworkReplyProxy *QQmlTypeLoaderThread::networkReplyProxy() const Q_ASSERT(m_networkReplyProxy); // Must call networkAccessManager() first return m_networkReplyProxy; } +#endif // QT_NO_NETWORK void QQmlTypeLoaderThread::load(QQmlDataBlob *b) { @@ -810,10 +875,12 @@ void QQmlTypeLoaderThread::initializeEngine(QQmlExtensionInterface *iface, void QQmlTypeLoaderThread::shutdownThread() { +#ifndef QT_NO_NETWORK delete m_networkAccessManager; m_networkAccessManager = 0; delete m_networkReplyProxy; m_networkReplyProxy = 0; +#endif // QT_NO_NETWORK } void QQmlTypeLoaderThread::loadThread(QQmlDataBlob *b) @@ -899,12 +966,14 @@ void QQmlTypeLoader::invalidate() m_thread = 0; } +#ifndef QT_NO_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 // QT_NO_NETWORK } void QQmlTypeLoader::lock() @@ -1065,13 +1134,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 +1144,10 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob) if (blob->m_data.isAsync()) m_thread->callDownloadProgressChanged(blob, 1.); - setData(blob, &file); + setData(blob, fileName); } else { - +#ifndef QT_NO_NETWORK QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(blob->m_url)); QQmlTypeLoaderNetworkReplyProxy *nrp = m_thread->networkReplyProxy(); blob->addref(); @@ -1099,14 +1164,15 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob) #ifdef DATABLOB_DEBUG qWarning("QQmlDataBlob: requested %s", qPrintable(blob->url().toString())); -#endif - +#endif // DATABLOB_DEBUG +#endif // QT_NO_NETWORK } } #define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16 #define TYPELOADER_MINIMUM_TRIM_THRESHOLD 64 +#ifndef QT_NO_NETWORK void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply) { Q_ASSERT(m_thread->isThisThread()); @@ -1162,6 +1228,7 @@ void QQmlTypeLoader::networkReplyProgress(QNetworkReply *reply, m_thread->callDownloadProgressChanged(blob, blob->m_data.progress()); } } +#endif // QT_NO_NETWORK /*! Return the QQmlEngine associated with this loader @@ -1197,11 +1264,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 +1319,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) { } @@ -1416,51 +1483,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) { @@ -1950,7 +1972,9 @@ void QQmlTypeLoader::trimCache() QList<TypeCache::Iterator> unneededTypes; for (TypeCache::Iterator iter = m_typeCache.begin(), end = m_typeCache.end(); iter != end; ++iter) { QQmlTypeData *typeData = iter.value(); - if (typeData->m_compiledData && typeData->count() == 1 + // 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->isComplete() && typeData->m_compiledData && typeData->count() == 1 && typeData->m_compiledData->count() == 1) { // There are no live objects of this type unneededTypes.append(iter); @@ -1992,7 +2016,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) { } @@ -2005,14 +2029,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 @@ -2020,19 +2041,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 +QV4::CompiledData::CompilationUnit *QQmlTypeData::compilationUnit() const { - return m_compositeSingletons; -} - -QQmlCompiledData *QQmlTypeData::compiledData() const -{ - return m_compiledData; + return m_compiledData.data(); } void QQmlTypeData::registerCallback(TypeDataCallback *callback) @@ -2048,10 +2059,120 @@ void QQmlTypeData::unregisterCallback(TypeDataCallback *callback) Q_ASSERT(!m_callbacks.contains(callback)); } +bool QQmlTypeData::tryLoadFromDiskCache() +{ + if (!diskCache()) + return false; + + if (forceDiskCacheRefresh()) + 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)) { + qDebug() << "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::rebuildTypeAndPropertyCaches() +{ + Q_ASSERT(m_compiledData); + + QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine()); + + { + QQmlCompileError error = buildTypeResolutionCaches(&m_compiledData->importCache, &m_compiledData->resolvedTypes); + if (error.isSet()) { + setError(error); + return; + } + } + + { + 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() { + auto cleanup = defer([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()) { @@ -2063,16 +2184,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; @@ -2082,11 +2204,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()) { @@ -2100,27 +2223,81 @@ void QQmlTypeData::done() error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName)); errors.prepend(error); setError(errors); + 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(); + if (!m_document.isNull()) { + // Compile component + compile(); + } else { + rebuildTypeAndPropertyCaches(); + } - 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); + if (isError()) + return; + + { + QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine()); + { + // Sanity check property bindings + QQmlPropertyValidator validator(engine, m_importCache, m_compiledData); + QVector<QQmlCompileError> errors = validator.validate(); + if (!errors.isEmpty()) { + setError(errors); + return; + } + } + + m_compiledData->finalize(engine); } - // Compile component - if (!isError()) - compile(); + { + 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_document.reset(); - m_implicitImport = 0; + m_compiledData->importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace); + QQmlScriptData *scriptData = script.script->scriptData(); + scriptData->addref(); + m_compiledData->dependentScripts << scriptData; + } + } } void QQmlTypeData::completed() @@ -2155,9 +2332,19 @@ bool QQmlTypeData::loadImplicitImport() void QQmlTypeData::dataReceived(const Data &data) { - QString code = QString::fromUtf8(data.data(), data.size()); + if (tryLoadFromDiskCache()) + return; + + qint64 sourceTimeStamp; + QString error; + QString code = QString::fromUtf8(data.readAll(&error, &sourceTimeStamp)); + if (!error.isEmpty()) { + setError(error); + return; + } QQmlEngine *qmlEngine = typeLoader()->engine(); - m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger != 0)); + m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger() != 0)); + m_document->jsModule.sourceTimeStamp = sourceTimeStamp; QmlIR::IRBuilder compiler(QV8Engine::get(qmlEngine)->illegalNames()); if (!compiler.generateFromQml(code, finalUrlString(), m_document.data())) { QList<QQmlError> errors; @@ -2180,14 +2367,14 @@ void QQmlTypeData::dataReceived(const Data &data) void QQmlTypeData::initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit *unit) { QQmlEngine *qmlEngine = typeLoader()->engine(); - m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger != 0)); + m_document.reset(new QmlIR::Document(QV8Engine::getV4(qmlEngine)->debugger() != 0)); unit->loadIR(m_document.data(), unit); continueLoadFromIR(); } 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 @@ -2200,14 +2387,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; } @@ -2228,14 +2415,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() @@ -2280,20 +2459,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() { - Q_ASSERT(m_compiledData == 0); + Q_ASSERT(m_compiledData.isNull()); - m_compiledData = new QQmlCompiledData(typeLoader()->engine()); + QQmlRefPointer<QQmlTypeNameCache> importCache; + QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache; + QQmlCompileError error = buildTypeResolutionCaches(&importCache, &resolvedTypeCache); + if (error.isSet()) { + setError(error); + return; + } - QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), m_compiledData, this, m_document.data()); - if (!compiler.compile()) { + QQmlTypeCompiler compiler(QQmlEnginePrivate::get(typeLoader()->engine()), this, m_document.data(), importCache, resolvedTypeCache); + m_compiledData = compiler.compile(); + if (!m_compiledData) { setError(compiler.compilationErrors()); - m_compiledData->release(); - m_compiledData = 0; + return; + } + if (diskCache() || forceDiskCacheRefresh()) { + QString errorString; + if (!m_compiledData->saveToDisk(&errorString)) { + qDebug() << "Error saving cached version of" << m_compiledData->url().toString() << "to disk:" << errorString; + } } } @@ -2346,7 +2539,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 @@ -2416,6 +2609,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; @@ -2537,10 +2781,6 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent ctxt->importedScripts = effectiveCtxt->importedScripts; } - if (ctxt->imports) { - ctxt->imports->addref(); - } - if (effectiveCtxt) { ctxt->setParent(effectiveCtxt, true); } else { @@ -2628,10 +2868,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 (diskCache() && !forceDiskCacheRefresh()) { + QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading(); + QString error; + if (unit->loadFromDisk(url(), v4->iselFactory.data(), &error)) { + initializeFromCompilationUnit(unit); + return; + } else { + qDebug() << "Error loading" << url().toString() << "from disk cache:" << error; + } + } + + + QmlIR::Document irUnit(v4->debugger() != 0); + + 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; @@ -2656,6 +2915,13 @@ void QQmlScriptBlob::dataReceived(const Data &data) // The js unit owns the data and will free the qml unit. unit->data = unitData; + if (diskCache() || forceDiskCacheRefresh()) { + QString errorString; + if (!unit->saveToDisk(&errorString)) { + qDebug() << "Error saving cached version of" << unit->url().toString() << "to disk:" << errorString; + } + } + initializeFromCompilationUnit(unit); } @@ -2666,8 +2932,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()) { @@ -2679,17 +2948,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); @@ -2783,7 +3050,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 *) @@ -2791,6 +3063,30 @@ 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) + *sourceTimeStamp = QFileInfo(f).lastModified().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..ab6b046fcf 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -53,7 +53,9 @@ #include <QtCore/qobject.h> #include <QtCore/qatomic.h> +#ifndef QT_NO_NETWORK #include <QtNetwork/qnetworkreply.h> +#endif #include <QtQml/qqmlerror.h> #include <QtQml/qqmlengine.h> #include <QtQml/qqmlfile.h> @@ -75,11 +77,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 +131,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(); +#ifndef QT_NO_NETWORK virtual void networkError(QNetworkReply::NetworkError); +#endif virtual void dependencyError(QQmlDataBlob *); virtual void dependencyComplete(QQmlDataBlob *); virtual void allDependenciesDone(); @@ -233,7 +233,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); @@ -250,7 +249,6 @@ public: virtual QString stringAt(int) const { return QString(); } QQmlImports m_importCache; - bool m_isSingleton; QHash<const QV4::CompiledData::Import*, int> m_unresolvedImports; QList<QQmlQmldirData *> m_qmldirs; }; @@ -320,20 +318,24 @@ public: private: friend class QQmlDataBlob; friend class QQmlTypeLoaderThread; +#ifndef QT_NO_NETWORK friend class QQmlTypeLoaderNetworkReplyProxy; +#endif // QT_NO_NETWORK void shutdownThread(); void loadThread(QQmlDataBlob *); void loadWithStaticDataThread(QQmlDataBlob *, const QByteArray &); void loadWithCachedUnitThread(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit); +#ifndef QT_NO_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 +364,9 @@ private: QQmlEngine *m_engine; QQmlTypeLoaderThread *m_thread; +#ifndef QT_NO_NETWORK NetworkReplies m_networkReplies; +#endif TypeCache m_typeCache; int m_typeCacheTrimThreshold; ScriptCache m_scriptCache; @@ -381,6 +385,7 @@ private: class Q_AUTOTEST_EXPORT QQmlTypeData : public QQmlTypeLoader::Blob { + Q_DECLARE_TR_FUNCTIONS(QQmlTypeData) public: struct TypeReference { @@ -412,13 +417,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 +441,21 @@ protected: virtual QString stringAt(int index) const; private: + bool tryLoadFromDiskCache(); void continueLoadFromIR(); void resolveTypes(); + QQmlCompileError buildTypeResolutionCaches( + QQmlRefPointer<QQmlTypeNameCache> *importCache, + QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache + ) const; void compile(); + void rebuildTypeAndPropertyCaches(); 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); QScopedPointer<QmlIR::Document> m_document; + QV4::CompiledData::TypeReferenceMap m_typeReferences; QList<ScriptReference> m_scripts; @@ -458,11 +466,10 @@ private: QHash<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 +579,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/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp index 44fd47244d..8e87ec7f63 100644 --- a/src/qml/qml/qqmlvaluetype.cpp +++ b/src/qml/qml/qqmlvaluetype.cpp @@ -219,7 +219,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; 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..595cd01d05 100644 --- a/src/qml/qml/qqmlvaluetypeproxybinding.cpp +++ b/src/qml/qml/qqmlvaluetypeproxybinding.cpp @@ -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) { diff --git a/src/qml/qml/qqmlvaluetypeproxybinding_p.h b/src/qml/qml/qqmlvaluetypeproxybinding_p.h index de5acc2984..6e297bb3ea 100644 --- a/src/qml/qml/qqmlvaluetypeproxybinding_p.h +++ b/src/qml/qml/qqmlvaluetypeproxybinding_p.h @@ -63,7 +63,7 @@ public: QQmlAbstractBinding *binding(int 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..b69eea61c5 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 @@ -245,6 +246,34 @@ PropertyAttributes QQmlValueTypeWrapper::query(const Managed *m, String *name) 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,8 +332,7 @@ 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('('); + 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) { @@ -431,7 +459,7 @@ void QQmlValueTypeWrapper::put(Managed *m, String *name, const Value &value) QV4::Scoped<QQmlBindingFunction> bindingFunction(scope, (const Value &)f); bindingFunction->initBindingLocation(); - QQmlBinding *newBinding = new QQmlBinding(value, reference->d()->object, context); + QQmlBinding *newBinding = QQmlBinding::create(&cacheData, value, reference->d()->object, context); newBinding->setTarget(reference->d()->object, cacheData); QQmlPropertyPrivate::setBinding(newBinding); return; diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h index c2861f5bfa..94eeba366a 100644 --- a/src/qml/qml/qqmlvaluetypewrapper_p.h +++ b/src/qml/qml/qqmlvaluetypewrapper_p.h @@ -99,6 +99,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..d5001674ad 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,32 @@ 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; + QQmlPropertyData::decodeValueTypePropertyIndex(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(); @@ -184,7 +220,7 @@ 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) @@ -242,7 +278,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 +314,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 +446,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 +459,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 +472,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 +485,7 @@ double QQmlVMEMetaObject::readPropertyAsDouble(int id) QString QQmlVMEMetaObject::readPropertyAsString(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QString(); @@ -474,7 +498,7 @@ QString QQmlVMEMetaObject::readPropertyAsString(int id) QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QUrl(); @@ -488,7 +512,7 @@ QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id) QDate QQmlVMEMetaObject::readPropertyAsDate(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QDate(); @@ -502,7 +526,7 @@ QDate QQmlVMEMetaObject::readPropertyAsDate(int id) QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QDateTime(); @@ -516,7 +540,7 @@ QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id) QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QSizeF(); @@ -530,7 +554,7 @@ QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id) QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QPointF(); @@ -544,7 +568,7 @@ QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id) QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return 0; @@ -558,7 +582,7 @@ QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id) QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return 0; @@ -574,7 +598,7 @@ QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id) QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id) { - QV4::MemberData *md = propertiesAsMemberData(); + QV4::MemberData *md = propertyAndMethodStorageAsMemberData(); if (!md) return QRectF(); @@ -596,15 +620,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 +649,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 +835,68 @@ 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; + + int coreIndex; + const int valueTypePropertyIndex = QQmlPropertyData::decodeValueTypePropertyIndex(aliasData->encodedMetaPropertyIndex, &coreIndex); + // 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, aliasData->encodedMetaPropertyIndex); } } - 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 +909,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 +917,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 @@ -853,23 +941,21 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * 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. @@ -887,22 +973,23 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * 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,7 +997,7 @@ 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) @@ -925,9 +1012,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 +1052,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,7 +1083,7 @@ 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 || @@ -1015,61 +1102,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 +1122,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 +1166,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 +1183,24 @@ 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()) + *valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(aliasData->encodedMetaPropertyIndex, coreIndex); 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 +1210,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..4a81fc50d2 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> { @@ -165,18 +101,27 @@ public: 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(int coreIndex) const + { + for (auto it = interceptors; it; it = it->m_next) { + if (it->m_coreIndex == coreIndex) + 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..201d634411 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) && !defined(QT_NO_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; @@ -715,7 +715,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) @@ -1235,7 +1235,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 +1560,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(); @@ -1620,22 +1621,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(); @@ -1735,7 +1737,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 +2041,6 @@ void *qt_add_qmlxmlhttprequest(ExecutionEngine *v4) QT_END_NAMESPACE -#endif // QT_NO_XMLSTREAMREADER +#endif // QT_NO_XMLSTREAMREADER && QT_NO_NETWORK #include <qqmlxmlhttprequest.moc> diff --git a/src/qml/qml/qqmlxmlhttprequest_p.h b/src/qml/qml/qqmlxmlhttprequest_p.h index 7bbfb5243c..df30873915 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) && !defined(QT_NO_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 && QT_NO_NETWORK #endif // QQMLXMLHTTPREQUEST_P_H diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index b9fb1f4ffe..76a900c846 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -45,6 +45,7 @@ #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> @@ -146,6 +147,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() @@ -1282,11 +1285,10 @@ void QQmlBindingFunction::initBindingLocation() 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) @@ -1995,6 +1997,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..d29983c476 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -135,6 +135,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; @@ -186,7 +188,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..e08ff3b979 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,22 @@ QV8Engine::~QV8Engine() qDeleteAll(m_extensionData); m_extensionData.clear(); +#if !defined(QT_NO_XMLSTREAMREADER) && defined(QT_NO_NETWORK) qt_rem_qmlxmlhttprequest(m_v4Engine, m_xmlHttpRequestData); m_xmlHttpRequestData = 0; +#endif delete m_listModelData; m_listModelData = 0; delete m_v4Engine; } +#ifndef QT_NO_NETWORK QNetworkAccessManager *QV8Engine::networkAccessManager() { return QQmlEnginePrivate::get(m_engine)->getNetworkAccessManager(); } +#endif const QSet<QString> &QV8Engine::illegalNames() const { @@ -189,8 +194,10 @@ void QV8Engine::initializeGlobal() QQmlDateExtension::registerExtension(m_v4Engine); QQmlNumberExtension::registerExtension(m_v4Engine); +#if !defined(QT_NO_XMLSTREAMREADER) && !defined(QT_NO_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..390831609b 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); +#ifndef QT_NO_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 - |