diff options
author | Liang Qi <liang.qi@qt.io> | 2016-05-13 00:28:14 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2016-05-13 08:28:27 +0200 |
commit | ae745746a666134d9e9258b8c2ff00540624d835 (patch) | |
tree | 8294fffa3d752d61f79004fb04e21e927472fd8f /src/qml | |
parent | a7b383ab989e74ef552c2ef9c38377e065f1ab0e (diff) | |
parent | 531d00c1909527cb1bc28f17197267ccde408b0c (diff) |
Merge remote-tracking branch 'origin/5.7' into dev
Conflicts:
src/qml/jsapi/qjsengine.cpp
src/qml/qml/qqmlengine_p.h
src/quick/items/qquickanchors.cpp
src/quick/items/qquickanimatedimage_p_p.h
src/quick/items/qquickitem_p.h
tests/auto/qml/qqmlecmascript/testtypes.h
tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
tests/benchmarks/qml/creation/tst_creation.cpp
Change-Id: I65861e32f16e8a04c7090a90231627e1ebf6ba6f
Diffstat (limited to 'src/qml')
35 files changed, 415 insertions, 242 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 6b83bdc7b6..df0b1f67b1 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -249,8 +249,8 @@ void Document::collectTypeReferences() void Document::removeScriptPragmas(QString &script) { - const QString pragma(QLatin1String("pragma")); - const QString library(QLatin1String("library")); + const QLatin1String pragma("pragma"); + const QLatin1String library("library"); QQmlJS::Lexer l(0); l.setCode(script, 0); @@ -268,7 +268,7 @@ void Document::removeScriptPragmas(QString &script) if (token != QQmlJSGrammar::T_PRAGMA || l.tokenStartLine() != startLine || - script.mid(l.tokenOffset(), l.tokenLength()) != pragma) + script.midRef(l.tokenOffset(), l.tokenLength()) != pragma) return; token = l.lex(); @@ -277,7 +277,7 @@ void Document::removeScriptPragmas(QString &script) l.tokenStartLine() != startLine) return; - QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength()); + const QStringRef pragmaValue = script.midRef(l.tokenOffset(), l.tokenLength()); int endOffset = l.tokenLength() + l.tokenOffset(); token = l.lex(); diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index a71793f2b6..da00496cb2 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -179,16 +179,16 @@ bool QQmlTypeCompiler::compile() for (int scriptIndex = 0; scriptIndex < scripts.count(); ++scriptIndex) { const QQmlTypeData::ScriptReference &script = scripts.at(scriptIndex); - QString qualifier = script.qualifier; + QStringRef qualifier(&script.qualifier); QString enclosingNamespace; const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.')); if (lastDotIndex != -1) { - enclosingNamespace = qualifier.left(lastDotIndex); + enclosingNamespace = qualifier.left(lastDotIndex).toString(); qualifier = qualifier.mid(lastDotIndex+1); } - compiledData->importCache->add(qualifier, scriptIndex, enclosingNamespace); + compiledData->importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace); QQmlScriptData *scriptData = script.script->scriptData(); scriptData->addref(); compiledData->scripts << scriptData; @@ -624,7 +624,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob QString path = compiler->url().path(); int lastSlash = path.lastIndexOf(QLatin1Char('/')); if (lastSlash > -1) { - QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5); + const QStringRef nameBase = path.midRef(lastSlash + 1, path.length() - lastSlash - 5); if (!nameBase.isEmpty() && nameBase.at(0).isUpper()) newClassName = nameBase.toUtf8() + "_QMLTYPE_" + QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1)); @@ -1163,10 +1163,10 @@ struct StaticQtMetaObject : public QObject { return &staticQtMetaObject; } }; -bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QString &enumName, int enumValue, bool isQtObject) +bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QStringRef &enumName, int enumValue, bool isQtObject) { if (enumName.length() > 0 && enumName[0].isLower() && !isQtObject) { - COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName)); + COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName.toString())); } binding->type = QV4::CompiledData::Binding::Type_Number; binding->value.d = (double)enumValue; @@ -1197,7 +1197,7 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, QHashedStringRef typeName(string.constData(), dot); const bool isQtObject = (typeName == QLatin1String("Qt")); - QString enumValue = string.mid(dot+1); + const QStringRef enumValue = string.midRef(dot + 1); if (isIntProp) { // Allow enum assignment to ints. diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 240f591f91..273ba01a88 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -196,7 +196,11 @@ public: bool resolveEnumBindings(); private: - bool assignEnumToBinding(QmlIR::Binding *binding, const QString &enumName, int enumValue, bool isQtObject); + bool assignEnumToBinding(QmlIR::Binding *binding, const QStringRef &enumName, int enumValue, bool isQtObject); + bool assignEnumToBinding(QmlIR::Binding *binding, const QString &enumName, int enumValue, bool isQtObject) + { + return assignEnumToBinding(binding, QStringRef(&enumName), enumValue, isQtObject); + } bool tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *prop, QmlIR::Binding *binding); diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 4d0361302e..a63f35152a 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -221,8 +221,8 @@ QString Binding::valueAsString(const Unit *unit) const // This code must match that in the qsTr() implementation const QString &path = unit->stringAt(unit->sourceFileIndex); int lastSlash = path.lastIndexOf(QLatin1Char('/')); - QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) : - QString(); + QStringRef context = (lastSlash > -1) ? path.midRef(lastSlash + 1, path.length() - lastSlash - 5) + : QStringRef(); QByteArray contextUtf8 = context.toUtf8(); QByteArray comment = unit->stringAt(value.translationData.commentIndex).toUtf8(); QByteArray text = unit->stringAt(stringIndex).toUtf8(); diff --git a/src/qml/debugger/qqmlprofiler.cpp b/src/qml/debugger/qqmlprofiler.cpp index 8d60325a19..629d5cb7b8 100644 --- a/src/qml/debugger/qqmlprofiler.cpp +++ b/src/qml/debugger/qqmlprofiler.cpp @@ -45,7 +45,9 @@ QT_BEGIN_NAMESPACE QQmlProfiler::QQmlProfiler() : featuresEnabled(0) { static int metatype = qRegisterMetaType<QVector<QQmlProfilerData> >(); + static int metatype2 = qRegisterMetaType<QQmlProfiler::LocationHash> (); Q_UNUSED(metatype); + Q_UNUSED(metatype2); m_timer.start(); } @@ -62,8 +64,18 @@ void QQmlProfiler::stopProfiling() void QQmlProfiler::reportData() { - emit dataReady(m_data); - m_data.clear(); + LocationHash resolved; + resolved.reserve(m_locations.size()); + for (auto it = m_locations.constBegin(), end = m_locations.constEnd(); it != end; ++it) + resolved.insert(it.key(), it.value()); + + // This unrefs all the objects. We have to make sure we do this in the GUI thread. Also, it's + // a good idea to release the memory before creating the packets to be sent. + m_locations.clear(); + + QVector<QQmlProfilerData> data; + data.swap(m_data); + emit dataReady(data, resolved); } QT_END_NAMESPACE diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h index 24001159f3..1380599fb7 100644 --- a/src/qml/debugger/qqmlprofiler_p.h +++ b/src/qml/debugger/qqmlprofiler_p.h @@ -54,6 +54,8 @@ #include <private/qv4function_p.h> #include <private/qqmlboundsignal_p.h> #include <private/qfinitestack_p.h> +#include <private/qqmlbinding_p.h> +#include <private/qqmlcompiler_p.h> #include "qqmlprofilerdefinitions_p.h" #include "qqmlabstractprofileradapter_p.h" @@ -77,40 +79,18 @@ QT_BEGIN_NAMESPACE // independently when converting to QByteArrays. Thus you can only pack // messages if their data doesn't overlap. It's up to you to figure that // out. -struct Q_AUTOTEST_EXPORT QQmlProfilerData +struct Q_AUTOTEST_EXPORT QQmlProfilerData : public QQmlProfilerDefinitions { - QQmlProfilerData() {} - - QQmlProfilerData(qint64 time, int messageType, int detailType, const QUrl &url, - int x = 0, int y = 0) : - time(time), messageType(messageType), detailType(detailType), detailUrl(url), - x(x), y(y) {} - - QQmlProfilerData(qint64 time, int messageType, int detailType, const QString &str, - int x = 0, int y = 0) : - time(time), messageType(messageType), detailType(detailType),detailString(str), - x(x), y(y) {} - - QQmlProfilerData(qint64 time, int messageType, int detailType, const QString &str, - const QUrl &url, int x = 0, int y = 0) : - time(time), messageType(messageType), detailType(detailType), detailString(str), - detailUrl(url), x(x), y(y) {} - - - QQmlProfilerData(qint64 time, int messageType, int detailType) : - time(time), messageType(messageType), detailType(detailType) {} - + QQmlProfilerData(qint64 time = -1, int messageType = -1, + RangeType detailType = MaximumRangeType, quintptr locationId = 0) : + time(time), locationId(locationId), messageType(messageType), detailType(detailType) + {} qint64 time; - int messageType; //bit field of QQmlProfilerService::Message - int detailType; + quintptr locationId; - // RangeData prefers detailString; RangeLocation prefers detailUrl. - QString detailString; //used by RangeData and possibly by RangeLocation - QUrl detailUrl; //used by RangeLocation and possibly by RangeData - - int x; //used by RangeLocation - int y; //used by RangeLocation + int messageType; //bit field of QQmlProfilerService::Message + RangeType detailType; }; Q_DECLARE_TYPEINFO(QQmlProfilerData, Q_MOVABLE_TYPE); @@ -118,58 +98,166 @@ Q_DECLARE_TYPEINFO(QQmlProfilerData, Q_MOVABLE_TYPE); class QQmlProfiler : public QObject, public QQmlProfilerDefinitions { Q_OBJECT public: - void startBinding(const QQmlSourceLocation &location) + + class BindingRefCount : public QQmlRefCount { + public: + BindingRefCount(QQmlBinding *binding): + m_binding(binding) + { + m_binding->ref.ref(); + } + + BindingRefCount(const BindingRefCount &other) : + QQmlRefCount(other), m_binding(other.m_binding) + { + m_binding->ref.ref(); + } + + BindingRefCount &operator=(const BindingRefCount &other) + { + if (this != &other) { + QQmlRefCount::operator=(other); + other.m_binding->ref.ref(); + if (!m_binding->ref.deref()) + delete m_binding; + m_binding = other.m_binding; + } + return *this; + } + + ~BindingRefCount() + { + if (!m_binding->ref.deref()) + delete m_binding; + } + + private: + QQmlBinding *m_binding; + }; + + struct Location { + Location(const QQmlSourceLocation &location = QQmlSourceLocation(), + const QUrl &url = QUrl()) : + location(location), url(url) {} + QQmlSourceLocation location; + QUrl url; + }; + + // Unfortunately we have to resolve the locations right away because the QML context might not + // be available anymore when we send the data. + struct RefLocation : public Location { + RefLocation() : Location(), locationType(MaximumRangeType), ref(nullptr) + {} + + RefLocation(QQmlBinding *binding, QV4::FunctionObject *function) : + Location(function->sourceLocation()), locationType(Binding), + ref(new BindingRefCount(binding), QQmlRefPointer<QQmlRefCount>::Adopt) + {} + + RefLocation(QQmlCompiledData *ref, const QUrl &url, const QV4::CompiledData::Object *obj, + const QString &type) : + Location(QQmlSourceLocation(type, obj->location.line, obj->location.column), url), + locationType(Creating), ref(ref) + {} + + RefLocation(QQmlBoundSignalExpression *ref) : + Location(ref->sourceLocation()), locationType(HandlingSignal), ref(ref) + {} + + RefLocation(QQmlDataBlob *ref) : + Location(QQmlSourceLocation(), ref->url()), locationType(Compiling), ref(ref) + {} + + bool isValid() const + { + return locationType != MaximumRangeType; + } + + RangeType locationType; + QQmlRefPointer<QQmlRefCount> ref; + }; + + typedef QHash<quintptr, Location> LocationHash; + + void startBinding(QQmlBinding *binding, QV4::FunctionObject *function) { + quintptr locationId(id(binding)); m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), - (1 << RangeStart | 1 << RangeLocation), 1 << Binding, - location.sourceFile, qmlSourceCoordinate(location.line), qmlSourceCoordinate(location.column))); + (1 << RangeStart | 1 << RangeLocation), Binding, + locationId)); + + RefLocation &location = m_locations[locationId]; + if (!location.isValid()) + location = RefLocation(binding, function); } // Have toByteArrays() construct another RangeData event from the same QString later. // This is somewhat pointless but important for backwards compatibility. - void startCompiling(const QUrl &url) + void startCompiling(QQmlDataBlob *blob) { + quintptr locationId(id(blob)); m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), (1 << RangeStart | 1 << RangeLocation | 1 << RangeData), - 1 << Compiling, url, 1, 1)); + Compiling, locationId)); + + RefLocation &location = m_locations[locationId]; + if (!location.isValid()) + location = RefLocation(blob); } - void startHandlingSignal(const QQmlSourceLocation &location) + void startHandlingSignal(QQmlBoundSignalExpression *expression) { + quintptr locationId(id(expression)); m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), - (1 << RangeStart | 1 << RangeLocation), 1 << HandlingSignal, - location.sourceFile, location.line, location.column)); + (1 << RangeStart | 1 << RangeLocation), HandlingSignal, + locationId)); + + RefLocation &location = m_locations[locationId]; + if (!location.isValid()) + location = RefLocation(expression); } void startCreating() { - m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeStart, 1 << Creating)); + m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeStart, Creating)); } - void startCreating(const QString &typeName, const QUrl &fileName, int line, int column) + void startCreating(const QV4::CompiledData::Object *obj) { m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), (1 << RangeStart | 1 << RangeLocation | 1 << RangeData), - 1 << Creating, typeName, fileName, line, column)); + Creating, id(obj))); } - void updateCreating(const QString &typeName, const QUrl &fileName, int line, int column) + void updateCreating(const QV4::CompiledData::Object *obj, QQmlCompiledData *ref, + const QUrl &url, const QString &type) { + quintptr locationId(id(obj)); m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), (1 << RangeLocation | 1 << RangeData), - 1 << Creating, typeName, fileName, line, column)); + Creating, locationId)); + + RefLocation &location = m_locations[locationId]; + if (!location.isValid()) + location = RefLocation(ref, url, obj, type); } template<RangeType Range> void endRange() { - m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeEnd, 1 << Range)); + m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeEnd, Range)); } QQmlProfiler(); quint64 featuresEnabled; + template<typename Object> + static quintptr id(const Object *pointer) + { + return reinterpret_cast<quintptr>(pointer); + } + public slots: void startProfiling(quint64 features); void stopProfiling(); @@ -177,10 +265,11 @@ public slots: void setTimer(const QElapsedTimer &timer) { m_timer = timer; } signals: - void dataReady(const QVector<QQmlProfilerData> &); + void dataReady(const QVector<QQmlProfilerData> &, const QQmlProfiler::LocationHash &); protected: QElapsedTimer m_timer; + QHash<quintptr, RefLocation> m_locations; QVector<QQmlProfilerData> m_data; }; @@ -194,11 +283,12 @@ struct QQmlProfilerHelper : public QQmlProfilerDefinitions { }; struct QQmlBindingProfiler : public QQmlProfilerHelper { - QQmlBindingProfiler(QQmlProfiler *profiler, const QV4::FunctionObject *function) : + QQmlBindingProfiler(QQmlProfiler *profiler, QQmlBinding *binding, + QV4::FunctionObject *function) : QQmlProfilerHelper(profiler) { Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileBinding, profiler, - startBinding(function->sourceLocation())); + startBinding(binding, function)); } ~QQmlBindingProfiler() @@ -213,7 +303,7 @@ struct QQmlHandlingSignalProfiler : public QQmlProfilerHelper { QQmlProfilerHelper(profiler) { Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileHandlingSignal, profiler, - startHandlingSignal(expression->sourceLocation())); + startHandlingSignal(expression)); } ~QQmlHandlingSignalProfiler() @@ -224,10 +314,10 @@ struct QQmlHandlingSignalProfiler : public QQmlProfilerHelper { }; struct QQmlCompilingProfiler : public QQmlProfilerHelper { - QQmlCompilingProfiler(QQmlProfiler *profiler, const QUrl &url) : + QQmlCompilingProfiler(QQmlProfiler *profiler, QQmlDataBlob *blob) : QQmlProfilerHelper(profiler) { - Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCompiling, profiler, startCompiling(url)); + Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCompiling, profiler, startCompiling(blob)); } ~QQmlCompilingProfiler() @@ -239,14 +329,6 @@ struct QQmlCompilingProfiler : public QQmlProfilerHelper { struct QQmlVmeProfiler : public QQmlProfilerDefinitions { public: - struct Data { - Data() : m_line(0), m_column(0) {} - QUrl m_url; - int m_line; - int m_column; - QString m_typeName; - }; - QQmlVmeProfiler() : profiler(0) {} void init(QQmlProfiler *p, int maxDepth) @@ -255,30 +337,30 @@ public: ranges.allocate(maxDepth); } - Data pop() + const QV4::CompiledData::Object *pop() { if (ranges.count() > 0) return ranges.pop(); else - return Data(); + return nullptr; } - void push(const Data &data) + void push(const QV4::CompiledData::Object *object) { if (ranges.capacity() > ranges.count()) - ranges.push(data); + ranges.push(object); } QQmlProfiler *profiler; private: - QFiniteStack<Data> ranges; + QFiniteStack<const QV4::CompiledData::Object *> ranges; }; #define Q_QML_OC_PROFILE(member, Code)\ Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, member.profiler, Code) -class QQmlObjectCreationProfiler : public QQmlVmeProfiler::Data { +class QQmlObjectCreationProfiler { public: QQmlObjectCreationProfiler(QQmlProfiler *profiler) : profiler(profiler) @@ -291,13 +373,10 @@ public: Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, endRange<QQmlProfilerDefinitions::Creating>()); } - void update(const QString &typeName, const QUrl &url, int line, int column) + void update(QQmlCompiledData *ref, const QV4::CompiledData::Object *obj, + const QString &typeName, const QUrl &url) { - profiler->updateCreating(typeName, url, line, column); - m_typeName = typeName; - m_url = url; - m_line = line; - m_column = column; + profiler->updateCreating(obj, ref, url, typeName); } private: @@ -310,8 +389,7 @@ public: profiler(parent->profiler) { Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler, { - QQmlVmeProfiler::Data data = parent->pop(); - profiler->startCreating(data.m_typeName, data.m_url, data.m_line, data.m_column); + profiler->startCreating(parent->pop()); }); } @@ -326,5 +404,6 @@ private: QT_END_NAMESPACE Q_DECLARE_METATYPE(QVector<QQmlProfilerData>) +Q_DECLARE_METATYPE(QQmlProfiler::LocationHash) #endif // QQMLPROFILER_P_H diff --git a/src/qml/doc/src/cppintegration/data.qdoc b/src/qml/doc/src/cppintegration/data.qdoc index e153ca3d8b..0d875bd10f 100644 --- a/src/qml/doc/src/cppintegration/data.qdoc +++ b/src/qml/doc/src/cppintegration/data.qdoc @@ -112,7 +112,7 @@ when passed from C++ to QML and vice-versa: \li QVector2D, QVector3D, QVector4D \li \l vector2d, \l vector3d, \l vector4d \row - \li Enums declared with Q_ENUMS() + \li Enums declared with Q_ENUM() or Q_ENUMS() \li \l enumeration \endtable @@ -261,6 +261,9 @@ In particular, QML currently supports: \li \c {QList<bool>} \li \c {QList<QString>} and \c{QStringList} \li \c {QList<QUrl>} + \li \c {QVector<int>} + \li \c {QVector<qreal>} + \li \c {QVector<bool>} \endlist These sequence types are implemented directly in terms of the underlying C++ @@ -303,6 +306,9 @@ The default-constructed values for each sequence type are as follows: \row \li QList<bool> \li boolean value \c {false} \row \li QList<QString> and QStringList \li empty QString \row \li QList<QUrl> \li empty QUrl +\row \li QVector<int> \li integer value 0 +\row \li QVector<qreal> \li real value 0.0 +\row \li QVector<bool> \li boolean value \c {false} \endtable If you wish to remove elements from a sequence rather than simply replace @@ -341,7 +347,7 @@ properties: \section1 Enumeration Types To use a custom enumeration as a data type, its class must be registered and -the enumeration must also be declared with Q_ENUMS() to register it with Qt's +the enumeration must also be declared with Q_ENUM() to register it with Qt's meta object system. For example, the \c Message class below has a \c Status enum: @@ -349,7 +355,6 @@ enum: class Message : public QObject { Q_OBJECT - Q_ENUMS(Status) Q_PROPERTY(Status status READ status NOTIFY statusChanged) public: enum Status { @@ -357,6 +362,7 @@ enum: Loading, Error }; + Q_ENUM(Status) Status status() const; signals: void statusChanged(); diff --git a/src/qml/doc/src/cppintegration/extending-tutorial.qdoc b/src/qml/doc/src/cppintegration/extending-tutorial.qdoc index d862b50fcb..c0cfc3e1aa 100644 --- a/src/qml/doc/src/cppintegration/extending-tutorial.qdoc +++ b/src/qml/doc/src/cppintegration/extending-tutorial.qdoc @@ -386,12 +386,26 @@ directory. \quotefile tutorials/extending-qml/chapter6-plugins/import/import.pro -In this example, the \c Charts directory is located at the same level as the application -that uses our new import module. This way, the QML engine will find our module -as the default search path for QML imports includes the directory of the application -executable. Alternatively, we could control what directories the \l {QML Import Path} -{QML import path} contains, useful if there are multiple QML applications using the -same QML imports. +When building this example on Windows or Linux, the \c Charts directory will be +located at the same level as the application that uses our new import module. +This way, the QML engine will find our module as the default search path for QML +imports includes the directory of the application executable. On OS X, the +plugin binary is copied to \c Contents/PlugIns in the the application bundle; +this path is set in \l {tutorials/extending-qml/chapter6-plugins/app.pro} +{chapter6-plugins/app.pro}: + +\quotefromfile tutorials/extending-qml/chapter6-plugins/app.pro +\skipto osx +\printuntil } + +To account for this, we also need to add this location as a +\l {QML Import Path}{QML import path} in \c main.cpp: + +\snippet tutorials/extending-qml/chapter6-plugins/main.cpp 0 +\dots + +Defining custom import paths is useful also when there are multiple +applications using the same QML imports. The \c .pro file also contains additional magic to ensure that the \l {Module Definition qmldir Files}{module definition qmldir file} is always copied diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc index 04d769e4dc..04d0d0ed2e 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc @@ -508,7 +508,7 @@ built-in \l {Rectangle::color} property: Any object that use this type and refer to its \c color property will be referring to the alias rather than the ordinary \l {Rectangle::color} property. -Internally, however, the red can correctly set its \c color +Internally, however, the rectangle can correctly set its \c color property and refer to the actual defined property rather than the alias. diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index 424d5548a1..257dd357fd 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -247,6 +247,11 @@ Q_DECLARE_METATYPE(QList<int>) QT_BEGIN_NAMESPACE +static void checkForApplicationInstance() +{ + if (!QCoreApplication::instance()) + qFatal("QJSEngine: Must construct a QCoreApplication before a QJSEngine"); +} /*! Constructs a QJSEngine object. @@ -270,6 +275,8 @@ QJSEngine::QJSEngine(QObject *parent) : QObject(*new QJSEnginePrivate, parent) , d(new QV8Engine(this)) { + checkForApplicationInstance(); + QJSEnginePrivate::addToDebugServer(this); } @@ -280,6 +287,7 @@ QJSEngine::QJSEngine(QJSEnginePrivate &dd, QObject *parent) : QObject(dd, parent) , d(new QV8Engine(this)) { + checkForApplicationInstance(); } /*! diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp index 73aa7047b8..4c4639c94f 100644 --- a/src/qml/jsruntime/qv4arraydata.cpp +++ b/src/qml/jsruntime/qv4arraydata.cpp @@ -287,7 +287,13 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n) Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Simple); dd = o->d()->arrayData.cast<Heap::SimpleArrayData>(); } - dd->offset = (dd->offset - n) % dd->alloc; + if (n <= dd->offset) { + dd->offset -= n; // there is enough space left in front + } else { + // we need to wrap around, so: + dd->offset = dd->alloc - // start at the back, but subtract: + (n - dd->offset); // the number of items we can put in the free space at the start of the allocated array + } dd->len += n; for (uint i = 0; i < n; ++i) dd->data(i) = values[i].asReturnedValue(); diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 5783e8fa2b..0cd72d6811 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -338,7 +338,7 @@ static inline double currentTime() static inline double TimeClip(double t) { - if (! qIsFinite(t) || fabs(t) > 8.64e15) + if (! qt_is_finite(t) || fabs(t) > 8.64e15) return qt_qnan(); return Primitive::toInteger(t); } diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp index c0a4129d9d..a59190b846 100644 --- a/src/qml/jsruntime/qv4profiling.cpp +++ b/src/qml/jsruntime/qv4profiling.cpp @@ -46,26 +46,35 @@ QT_BEGIN_NAMESPACE namespace QV4 { namespace Profiling { -FunctionCallProperties FunctionCall::resolve() const +FunctionLocation FunctionCall::resolveLocation() const { - FunctionCallProperties props = { - m_start, - m_end, + FunctionLocation location = { m_function->name()->toQString(), m_function->compilationUnit->fileName(), m_function->compiledFunction->location.line, m_function->compiledFunction->location.column }; - return props; + return location; } +FunctionCallProperties FunctionCall::properties() const +{ + FunctionCallProperties props = { + m_start, + m_end, + reinterpret_cast<quintptr>(m_function) + }; + return props; +} Profiler::Profiler(QV4::ExecutionEngine *engine) : featuresEnabled(0), m_engine(engine) { - static int meta = qRegisterMetaType<QVector<QV4::Profiling::FunctionCallProperties> >(); - static int meta2 = qRegisterMetaType<QVector<QV4::Profiling::MemoryAllocationProperties> >(); - Q_UNUSED(meta); - Q_UNUSED(meta2); + static const int metatypes[] = { + qRegisterMetaType<QVector<QV4::Profiling::FunctionCallProperties> >(), + qRegisterMetaType<QVector<QV4::Profiling::MemoryAllocationProperties> >(), + qRegisterMetaType<FunctionLocationHash>() + }; + Q_UNUSED(metatypes); m_timer.start(); } @@ -85,13 +94,16 @@ bool operator<(const FunctionCall &call1, const FunctionCall &call2) void Profiler::reportData() { std::sort(m_data.begin(), m_data.end()); - QVector<FunctionCallProperties> resolved; - resolved.reserve(m_data.size()); + QVector<FunctionCallProperties> properties; + QHash<qint64, FunctionLocation> locations; + properties.reserve(m_data.size()); - foreach (const FunctionCall &call, m_data) - resolved.append(call.resolve()); + foreach (const FunctionCall &call, m_data) { + properties.append(call.properties()); + locations[properties.constLast().id] = call.resolveLocation(); + } - emit dataReady(resolved, m_memory_data); + emit dataReady(locations, properties, m_memory_data); m_data.clear(); m_memory_data.clear(); } diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index 25ef8223bf..0b4193204f 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -77,12 +77,18 @@ enum MemoryType { struct FunctionCallProperties { qint64 start; qint64 end; + quintptr id; +}; + +struct FunctionLocation { QString name; QString file; int line; int column; }; +typedef QHash<qint64, QV4::Profiling::FunctionLocation> FunctionLocationHash; + struct MemoryAllocationProperties { qint64 timestamp; qint64 size; @@ -118,7 +124,8 @@ public: return *this; } - FunctionCallProperties resolve() const; + FunctionLocation resolveLocation() const; + FunctionCallProperties properties() const; private: friend bool operator<(const FunctionCall &call1, const FunctionCall &call2); @@ -173,7 +180,8 @@ public slots: void setTimer(const QElapsedTimer &timer) { m_timer = timer; } signals: - void dataReady(const QVector<QV4::Profiling::FunctionCallProperties> &, + void dataReady(const QV4::Profiling::FunctionLocationHash &, + const QVector<QV4::Profiling::FunctionCallProperties> &, const QVector<QV4::Profiling::MemoryAllocationProperties> &); private: @@ -218,8 +226,10 @@ public: Q_DECLARE_TYPEINFO(QV4::Profiling::MemoryAllocationProperties, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCallProperties, Q_MOVABLE_TYPE); Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCall, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionLocation, Q_MOVABLE_TYPE); QT_END_NAMESPACE +Q_DECLARE_METATYPE(QV4::Profiling::FunctionLocationHash) Q_DECLARE_METATYPE(QVector<QV4::Profiling::FunctionCallProperties>) Q_DECLARE_METATYPE(QVector<QV4::Profiling::MemoryAllocationProperties>) diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index df58ab5060..35fcd00eb7 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -1285,6 +1285,8 @@ static int MatchScore(const QV4::Value &actual, int conversionType) return 10; } else if (conversionType == QMetaType::QJsonObject) { return 5; + } else if (conversionType == qMetaTypeId<QJSValue>()) { + return 0; } else { return 10; } diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index dfac2d9bd9..b7543692d5 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -984,10 +984,9 @@ ReturnedValue Runtime::method_callQmlScopeObjectProperty(ExecutionEngine *engine Scope scope(engine); ScopedFunctionObject o(scope, method_getQmlScopeObjectProperty(engine, callData->thisObject, propertyIndex)); if (!o) { - QString error = QStringLiteral("Property '%1' of object %2 is not a function").arg(propertyIndex).arg(callData->thisObject.toQStringNoThrow()); + QString error = QStringLiteral("Property '%1' of scope object is not a function").arg(propertyIndex); return engine->throwTypeError(error); } - return o->call(callData); } @@ -996,7 +995,7 @@ ReturnedValue Runtime::method_callQmlContextObjectProperty(ExecutionEngine *engi Scope scope(engine); ScopedFunctionObject o(scope, method_getQmlContextObjectProperty(engine, callData->thisObject, propertyIndex)); if (!o) { - QString error = QStringLiteral("Property '%1' of object %2 is not a function").arg(propertyIndex).arg(callData->thisObject.toQStringNoThrow()); + QString error = QStringLiteral("Property '%1' of context object is not a function").arg(propertyIndex); return engine->throwTypeError(error); } diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index b97310c5b9..fa2409a85c 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -75,6 +75,9 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description // F(elementType, elementTypeName, sequenceType, defaultValue) #define FOREACH_QML_SEQUENCE_TYPE(F) \ + F(int, IntVector, QVector<int>, 0) \ + F(qreal, RealVector, QVector<qreal>, 0.0) \ + F(bool, BoolVector, QVector<bool>, false) \ F(int, Int, QList<int>, 0) \ F(qreal, Real, QList<qreal>, 0.0) \ F(bool, Bool, QList<bool>, false) \ @@ -578,6 +581,15 @@ Heap::QQmlSequence<Container>::QQmlSequence(QObject *object, int propertyIndex) namespace QV4 { +typedef QQmlSequence<QVector<int> > QQmlIntVectorList; +template<> +DEFINE_OBJECT_VTABLE(QQmlIntVectorList); +typedef QQmlSequence<QVector<qreal> > QQmlRealVectorList; +template<> +DEFINE_OBJECT_VTABLE(QQmlRealVectorList); +typedef QQmlSequence<QVector<bool> > QQmlBoolVectorList; +template<> +DEFINE_OBJECT_VTABLE(QQmlBoolVectorList); typedef QQmlSequence<QStringList> QQmlQStringList; template<> DEFINE_OBJECT_VTABLE(QQmlQStringList); diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index e8ddfecbe3..1249e1b6c8 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -168,7 +168,7 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) return; } - QQmlBindingProfiler prof(ep->profiler, f); + QQmlBindingProfiler prof(ep->profiler, this, f); setUpdatingFlag(true); QQmlJavaScriptExpression::DeleteWatcher watcher(this); diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 440840d3c9..18bee387dd 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -293,7 +293,7 @@ inline void QQmlEnginePrivate::dereferenceScarceResources() // if the refcount is zero, then evaluation of the "top level" // expression must have completed. We can safely release the // scarce resources. - if (scarceResourcesRefCount == 0) { + if (Q_LIKELY(scarceResourcesRefCount == 0)) { QV4::ExecutionEngine *engine = QV8Engine::getV4(v8engine()); if (Q_UNLIKELY(!engine->scarceResources.isEmpty())) { cleanupScarceResources(); diff --git a/src/qml/qml/qqmlerror.cpp b/src/qml/qml/qqmlerror.cpp index 47c85c907c..74ceeabeb4 100644 --- a/src/qml/qml/qqmlerror.cpp +++ b/src/qml/qml/qqmlerror.cpp @@ -43,6 +43,7 @@ #include <QtCore/qdebug.h> #include <QtCore/qfile.h> #include <QtCore/qstringlist.h> +#include <QtCore/qvector.h> #include <private/qv4errorobject_p.h> @@ -288,11 +289,11 @@ QDebug operator<<(QDebug debug, const QQmlError &error) stream.setCodec("UTF-8"); #endif const QString code = stream.readAll(); - const QStringList lines = code.split(QLatin1Char('\n')); + const auto lines = code.splitRef(QLatin1Char('\n')); if (lines.count() >= error.line()) { - const QString &line = lines.at(error.line() - 1); - debug << "\n " << qPrintable(line); + const QStringRef &line = lines.at(error.line() - 1); + debug << "\n " << line.toLocal8Bit().constData(); if(error.column() > 0) { int column = qMax(0, error.column() - 1); diff --git a/src/qml/qml/qqmlextensioninterface.h b/src/qml/qml/qqmlextensioninterface.h index 73e41a3b80..ef56d5e312 100644 --- a/src/qml/qml/qqmlextensioninterface.h +++ b/src/qml/qml/qqmlextensioninterface.h @@ -66,7 +66,7 @@ public: Q_DECLARE_INTERFACE(QQmlTypesExtensionInterface, "org.qt-project.Qt.QQmlTypesExtensionInterface/1.0") -#define QQmlExtensionInterface_iid "org.qt-project.Qt.QQmlExtensionInterface" +#define QQmlExtensionInterface_iid "org.qt-project.Qt.QQmlExtensionInterface/1.0" Q_DECLARE_INTERFACE(QQmlExtensionInterface, QQmlExtensionInterface_iid) diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp index 7a441dd9ff..4769402855 100644 --- a/src/qml/qml/qqmlfile.cpp +++ b/src/qml/qml/qqmlfile.cpp @@ -605,7 +605,7 @@ QString QQmlFile::urlToLocalFileOrQrc(const QString& url) { if (url.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive)) { if (url.length() > 4) - return QLatin1Char(':') + url.mid(4); + return QLatin1Char(':') + url.midRef(4); return QString(); } diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 5ce3942be2..69adce3da2 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -85,12 +85,11 @@ QString resolveLocalUrl(const QString &url, const QString &relative) } else if (relative.at(0) == Slash || !url.contains(Slash)) { return relative; } else { - QString base(url.left(url.lastIndexOf(Slash) + 1)); - + const QStringRef baseRef = url.leftRef(url.lastIndexOf(Slash) + 1); if (relative == QLatin1String(".")) - return base; + return baseRef.toString(); - base.append(relative); + QString base = baseRef + relative; // Remove any relative directory elements in the path int length = base.length(); @@ -483,20 +482,58 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const return scripts; } +static QString joinStringRefs(const QVector<QStringRef> &refs, const QChar &sep) +{ + QString str; + for (auto it = refs.cbegin(); it != refs.cend(); ++it) { + if (it != refs.cbegin()) + str += sep; + str += *it; + } + return str; +} + /*! - Form a complete path to a qmldir file, from a base URL, a module URI and version specification. + Forms complete paths to a qmldir file, from a base URL, a module URI and version specification. + + For example, QtQml.Models 2.0: + - base/QtQml/Models.2.0/qmldir + - base/QtQml.2.0/Models/qmldir + - base/QtQml/Models.2/qmldir + - base/QtQml.2/Models/qmldir + - base/QtQml/Models/qmldir */ -QString QQmlImports::completeQmldirPath(const QString &uri, const QString &base, int vmaj, int vmin, - ImportVersion version) +QStringList QQmlImports::completeQmldirPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin) { - QString url = uri; - url.replace(Dot, Slash); + const QVector<QStringRef> parts = uri.splitRef(Dot, QString::SkipEmptyParts); + + QStringList qmlDirPathsPaths; + // fully & partially versioned parts + 1 unversioned for each base path + qmlDirPathsPaths.reserve(basePaths.count() * (2 * parts.count() + 1)); + + for (int version = FullyVersioned; version <= Unversioned; ++version) { + const QString ver = versionString(vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version)); + + for (const QString &path : basePaths) { + QString dir = path; + if (!dir.endsWith(Slash) && !dir.endsWith(Backslash)) + dir += Slash; + + // append to the end + qmlDirPathsPaths += dir + joinStringRefs(parts, Slash) + ver + Slash_qmldir; - QString dir = base; - if (!dir.endsWith(Slash) && !dir.endsWith(Backslash)) - dir += Slash; + if (version != Unversioned) { + // insert in the middle + for (int index = parts.count() - 2; index >= 0; --index) { + qmlDirPathsPaths += dir + joinStringRefs(parts.mid(0, index + 1), Slash) + + ver + Slash + + joinStringRefs(parts.mid(index + 1), Slash) + Slash_qmldir; + } + } + } + } - return dir + url + versionString(vmaj, vmin, version) + Slash_qmldir; + return qmlDirPathsPaths; } QString QQmlImports::versionString(int vmaj, int vmin, ImportVersion version) @@ -777,11 +814,11 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS QString u1 = import->url; QString u2 = import2->url; if (base) { - QString b = *base; + QStringRef b(base); int dot = b.lastIndexOf(Dot); if (dot >= 0) { b = b.left(dot+1); - QString l = b.left(dot); + QStringRef l = b.left(dot); if (u1.startsWith(b)) u1 = u1.mid(b.count()); else if (u1 == l) @@ -857,7 +894,7 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res // the list the first time called to only contain QML plugins: foreach (const QStaticPlugin &plugin, QPluginLoader::staticPlugins()) { if (qobject_cast<QQmlExtensionPlugin *>(plugin.instance())) - plugins.append(plugin); + plugins.append(plugin); } } @@ -1130,32 +1167,29 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQ QStringList localImportPaths = database->importPathList(QQmlImportDatabase::Local); // Search local import paths for a matching version - for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned; ++version) { - foreach (const QString &path, localImportPaths) { - QString qmldirPath = QQmlImports::completeQmldirPath(uri, path, vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version)); - - QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirPath); - if (!absoluteFilePath.isEmpty()) { - QString url; - QString absolutePath = absoluteFilePath.left(absoluteFilePath.lastIndexOf(Slash)+1); - if (absolutePath.at(0) == Colon) - url = QLatin1String("qrc://") + absolutePath.mid(1); - else - url = QUrl::fromLocalFile(absolutePath).toString(); + const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(uri, localImportPaths, vmaj, vmin); + for (const QString &qmldirPath : qmlDirPaths) { + QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirPath); + if (!absoluteFilePath.isEmpty()) { + QString url; + const QStringRef absolutePath = absoluteFilePath.leftRef(absoluteFilePath.lastIndexOf(Slash) + 1); + if (absolutePath.at(0) == Colon) + url = QLatin1String("qrc://") + absolutePath.mid(1); + else + url = QUrl::fromLocalFile(absolutePath.toString()).toString(); - QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache; - cache->versionMajor = vmaj; - cache->versionMinor = vmin; - cache->qmldirFilePath = absoluteFilePath; - cache->qmldirPathUrl = url; - cache->next = cacheHead; - database->qmldirCache.insert(uri, cache); + QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache; + cache->versionMajor = vmaj; + cache->versionMinor = vmin; + cache->qmldirFilePath = absoluteFilePath; + cache->qmldirPathUrl = url; + cache->next = cacheHead; + database->qmldirCache.insert(uri, cache); - *outQmldirFilePath = absoluteFilePath; - *outQmldirPathUrl = url; + *outQmldirFilePath = absoluteFilePath; + *outQmldirPathUrl = url; - return true; - } + return true; } } diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index 628564ae34..0e7848730f 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -130,8 +130,7 @@ public: QList<CompositeSingletonReference> resolvedCompositeSingletons() const; - static QString completeQmldirPath(const QString &uri, const QString &base, int vmaj, int vmin, - QQmlImports::ImportVersion version); + static QStringList completeQmldirPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin); static QString versionString(int vmaj, int vmin, ImportVersion version); static bool isLocal(const QString &url); diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 29fff04325..cfe1c86eba 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -1037,8 +1037,8 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo if (compiledData->isComponent(index)) { isComponent = true; QQmlComponent *component = new QQmlComponent(engine, compiledData, index, parent); - Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(QStringLiteral("<component>"), - context->url(), obj->location.line, obj->location.column)); + Q_QML_OC_PROFILE(sharedState->profiler, profiler.update( + compiledData, obj, QStringLiteral("<component>"), context->url())); QQmlComponentPrivate::get(component)->creationContext = context; instance = component; ddata = QQmlData::get(instance, /*create*/true); @@ -1048,8 +1048,8 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo installPropertyCache = !typeRef->isFullyDynamicType; QQmlType *type = typeRef->type; if (type) { - Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(type->qmlTypeName(), - context->url(), obj->location.line, obj->location.column)); + Q_QML_OC_PROFILE(sharedState->profiler, profiler.update( + compiledData, 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))); @@ -1071,8 +1071,9 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo sharedState->allCreatedObjects.push(instance); } else { Q_ASSERT(typeRef->component); - Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(typeRef->component->fileName(), - context->url(), obj->location.line, obj->location.column)); + Q_QML_OC_PROFILE(sharedState->profiler, profiler.update( + compiledData, obj, typeRef->component->fileName(), + context->url())); if (typeRef->component->compilationUnit->data->isSingleton()) { recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex))); @@ -1115,7 +1116,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo parserStatus->classBegin(); // push() the profiler state here, together with the parserStatus, as we'll pop() them // together, too. - Q_QML_OC_PROFILE(sharedState->profiler, sharedState->profiler.push(profiler)); + Q_QML_OC_PROFILE(sharedState->profiler, sharedState->profiler.push(obj)); sharedState->allParserStatusCallbacks.push(parserStatus); parserStatus->d = &sharedState->allParserStatusCallbacks.top(); } diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index 22de5e1ae9..df2ff05de1 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -58,6 +58,7 @@ #include <private/qv4functionobject_p.h> #include <QStringList> +#include <QVector> #include <private/qmetaobject_p.h> #include <private/qqmlvaluetypewrapper_p.h> #include <QtCore/qdebug.h> @@ -240,14 +241,14 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) QQmlTypeNameCache *typeNameCache = context?context->imports:0; - QStringList path = name.split(QLatin1Char('.')); + const auto path = name.splitRef(QLatin1Char('.')); if (path.isEmpty()) return; QObject *currentObject = obj; // Everything up to the last property must be an "object type" property for (int ii = 0; ii < path.count() - 1; ++ii) { - const QString &pathName = path.at(ii); + const QStringRef &pathName = path.at(ii); if (typeNameCache) { QQmlTypeNameCache::Result r = typeNameCache->query(pathName); @@ -284,7 +285,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) QQmlPropertyData local; QQmlPropertyData *property = - QQmlPropertyCache::property(engine, currentObject, pathName, context, local); + QQmlPropertyCache::property(engine, currentObject, pathName.toString(), context, local); if (!property) return; // Not a property if (property->isFunction()) @@ -324,14 +325,14 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) } - const QString &terminal = path.last(); + const QStringRef &terminal = path.last(); if (terminal.count() >= 3 && terminal.at(0) == QLatin1Char('o') && terminal.at(1) == QLatin1Char('n') && terminal.at(2).isUpper()) { - QString signalName = terminal.mid(2); + QString signalName = terminal.mid(2).toString(); signalName[0] = signalName.at(0).toLower(); // XXX - this code treats methods as signals @@ -376,13 +377,14 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name) } // Property + const QString terminalString = terminal.toString(); QQmlPropertyData local; QQmlPropertyData *property = - QQmlPropertyCache::property(engine, currentObject, terminal, context, local); + QQmlPropertyCache::property(engine, currentObject, terminalString, context, local); if (property && !property->isFunction()) { object = currentObject; core = *property; - nameCache = terminal; + nameCache = terminalString; isNameCached = true; } } diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 15e8d62efc..c6299a1720 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -661,7 +661,7 @@ void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob) Q_ASSERT(m_waitingFor.contains(blob)); Q_ASSERT(blob->status() == Error || blob->status() == Complete); QQmlCompilingProfiler prof(QQmlEnginePrivate::get(typeLoader()->engine())->profiler, - blob->url()); + blob); m_inCallback = true; @@ -1121,6 +1121,7 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob) } #define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16 +#define TYPELOADER_MINIMUM_TRIM_THRESHOLD 64 #ifndef QT_NO_NETWORK void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply) @@ -1225,7 +1226,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, QQmlFile *file) void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d) { QML_MEMORY_SCOPE_URL(blob->url()); - QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob->url()); + QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob); blob->m_inCallback = true; @@ -1245,7 +1246,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d) void QQmlTypeLoader::setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit) { QML_MEMORY_SCOPE_URL(blob->url()); - QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob->url()); + QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob); blob->m_inCallback = true; @@ -1398,13 +1399,10 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL // Probe for all possible locations int priority = 0; - for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned; ++version) { - foreach (const QString &path, remotePathList) { - QString qmldirUrl = QQmlImports::completeQmldirPath(importUri, path, import->majorVersion, import->minorVersion, - static_cast<QQmlImports::ImportVersion>(version)); - if (!fetchQmldir(QUrl(qmldirUrl), import, ++priority, errors)) - return false; - } + const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(importUri, remotePathList, import->majorVersion, import->minorVersion); + for (const QString &qmldirPath : qmlDirPaths) { + if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors)) + return false; } } } @@ -1602,7 +1600,8 @@ bool QQmlTypeLoader::QmldirContent::designerSupported() const Constructs a new type loader that uses the given \a engine. */ QQmlTypeLoader::QQmlTypeLoader(QQmlEngine *engine) - : m_engine(engine), m_thread(new QQmlTypeLoaderThread(this)) + : m_engine(engine), m_thread(new QQmlTypeLoaderThread(this)), + m_typeCacheTrimThreshold(TYPELOADER_MINIMUM_TRIM_THRESHOLD) { } @@ -1639,6 +1638,10 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode) QQmlTypeData *typeData = m_typeCache.value(url); if (!typeData) { + // Trim before adding the new type, so that we don't immediately trim it away + if (m_typeCache.size() >= m_typeCacheTrimThreshold) + trimCache(); + typeData = new QQmlTypeData(url, this); // TODO: if (compiledData == 0), is it safe to omit this insertion? m_typeCache.insert(url, typeData); @@ -1943,12 +1946,22 @@ void QQmlTypeLoader::clearCache() qDeleteAll(m_importQmlDirCache); m_typeCache.clear(); + m_typeCacheTrimThreshold = TYPELOADER_MINIMUM_TRIM_THRESHOLD; m_scriptCache.clear(); m_qmldirCache.clear(); m_importDirCache.clear(); m_importQmlDirCache.clear(); } +void QQmlTypeLoader::updateTypeCacheTrimThreshold() +{ + int size = m_typeCache.size(); + if (size > m_typeCacheTrimThreshold) + m_typeCacheTrimThreshold = size * 2; + if (size < m_typeCacheTrimThreshold / 2) + m_typeCacheTrimThreshold = qMax(size * 2, TYPELOADER_MINIMUM_TRIM_THRESHOLD); +} + void QQmlTypeLoader::trimCache() { while (true) { @@ -1973,6 +1986,8 @@ void QQmlTypeLoader::trimCache() } } + updateTypeCacheTrimThreshold(); + // TODO: release any scripts which are no longer referenced by any types } diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 49a4ac716a..12ab98e425 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -374,6 +374,7 @@ private: NetworkReplies m_networkReplies; #endif TypeCache m_typeCache; + int m_typeCacheTrimThreshold; ScriptCache m_scriptCache; QmldirCache m_qmldirCache; ImportDirCache m_importDirCache; @@ -381,6 +382,7 @@ private: template<typename Loader> void doLoad(const Loader &loader, QQmlDataBlob *blob, Mode mode); + void updateTypeCacheTrimThreshold(); friend struct PlainLoader; friend struct CachedLoader; diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h index a59d8e2aec..ac9db5c046 100644 --- a/src/qml/qml/qqmlvme_p.h +++ b/src/qml/qml/qqmlvme_p.h @@ -64,8 +64,6 @@ #include <private/qqmlengine_p.h> #include <private/qfinitestack_p.h> -#include <private/qqmlprofiler_p.h> - QT_BEGIN_NAMESPACE class QObject; diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index ac40b627d9..d4ffd2747d 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -96,9 +96,9 @@ Heap::QtObject::QtObject(QQmlEngine *qmlEngine) const QMetaObject *qtMetaObject = StaticQtMetaObject::get(); ScopedString str(scope); ScopedValue v(scope); - for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) { + for (int ii = 0, eii = qtMetaObject->enumeratorCount(); ii < eii; ++ii) { QMetaEnum enumerator = qtMetaObject->enumerator(ii); - for (int jj = 0; jj < enumerator.keyCount(); ++jj) { + for (int jj = 0, ejj = enumerator.keyCount(); jj < ejj; ++jj) { o->put((str = scope.engine->newString(QString::fromUtf8(enumerator.key(jj)))), (v = QV4::Primitive::fromInt32(enumerator.value(jj)))); } } diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 73128f6344..d8b0ef79f8 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -156,8 +156,7 @@ QV8Engine::QV8Engine(QJSEngine* qq) QV8Engine::~QV8Engine() { - for (int ii = 0; ii < m_extensionData.count(); ++ii) - delete m_extensionData[ii]; + qDeleteAll(m_extensionData); m_extensionData.clear(); #if !defined(QT_NO_XMLSTREAMREADER) && defined(QT_NO_NETWORK) diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 6e5fa516db..aee9fcd0a2 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -1040,7 +1040,7 @@ QString QQmlDelegateModelPrivate::stringValue(Compositor::Group group, int index return QString(); int from = dot+1; dot = name.indexOf(QLatin1Char('.'), from); - value = obj->property(name.mid(from, dot-from).toUtf8()); + value = obj->property(name.midRef(from, dot - from).toUtf8()); } return value.toString(); } @@ -1557,29 +1557,6 @@ bool QQmlDelegateModel::isDescendantOf(const QPersistentModelIndex& desc, const return false; } -void QQmlDelegateModel::_q_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint) -{ - Q_D(QQmlDelegateModel); - if (!d->m_complete) - return; - - if (hint == QAbstractItemModel::VerticalSortHint) { - d->m_storedPersistentIndexes.clear(); - if (!parents.isEmpty() && d->m_adaptorModel.rootIndex.isValid() && !isDescendantOf(d->m_adaptorModel.rootIndex, parents)) { - return; - } - - for (int i = 0; i < d->m_count; ++i) { - const QModelIndex index = d->m_adaptorModel.aim()->index(i, 0, d->m_adaptorModel.rootIndex); - d->m_storedPersistentIndexes.append(index); - } - } else if (hint == QAbstractItemModel::HorizontalSortHint) { - // Ignored - } else { - // Triggers model reset, no preparations for that are needed - } -} - void QQmlDelegateModel::_q_layoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint) { Q_D(QQmlDelegateModel); @@ -1591,19 +1568,7 @@ void QQmlDelegateModel::_q_layoutChanged(const QList<QPersistentModelIndex> &par return; } - for (int i = 0, c = d->m_storedPersistentIndexes.count(); i < c; ++i) { - const QPersistentModelIndex &index = d->m_storedPersistentIndexes.at(i); - if (i == index.row()) - continue; - - _q_itemsMoved(i, index.row(), 1); - } - - d->m_storedPersistentIndexes.clear(); - - // layoutUpdate does not necessarily have any move changes, but it can - // also mean data changes. We can't detect what exactly has changed, so - // just emit it for all items + // mark all items as changed _q_itemsChanged(0, d->m_count, QVector<int>()); } else if (hint == QAbstractItemModel::HorizontalSortHint) { diff --git a/src/qml/types/qqmldelegatemodel_p.h b/src/qml/types/qqmldelegatemodel_p.h index aea474de67..2986ec7ce5 100644 --- a/src/qml/types/qqmldelegatemodel_p.h +++ b/src/qml/types/qqmldelegatemodel_p.h @@ -146,7 +146,6 @@ private Q_SLOTS: void _q_rowsRemoved(const QModelIndex &,int,int); void _q_rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int); void _q_dataChanged(const QModelIndex&,const QModelIndex&,const QVector<int> &); - void _q_layoutAboutToBeChanged(const QList<QPersistentModelIndex>&, QAbstractItemModel::LayoutChangeHint); void _q_layoutChanged(const QList<QPersistentModelIndex>&, QAbstractItemModel::LayoutChangeHint); private: diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h index 8e2d1c1cb3..76e55f718d 100644 --- a/src/qml/types/qqmldelegatemodel_p_p.h +++ b/src/qml/types/qqmldelegatemodel_p_p.h @@ -337,8 +337,6 @@ public: }; QQmlDelegateModelGroup *m_groups[Compositor::MaximumGroupCount]; }; - - QList<QPersistentModelIndex> m_storedPersistentIndexes; }; class QQmlPartsModel : public QQmlInstanceModel, public QQmlDelegateModelGroupEmitter diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp index 15c547b5df..5fc2444b7c 100644 --- a/src/qml/util/qqmladaptormodel.cpp +++ b/src/qml/util/qqmladaptormodel.cpp @@ -470,8 +470,6 @@ public: vdm, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int))); QObject::disconnect(aim, SIGNAL(modelReset()), vdm, SLOT(_q_modelReset())); - QObject::disconnect(aim, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), - vdm, SLOT(_q_layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint))); QObject::disconnect(aim, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), vdm, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint))); } @@ -928,8 +926,6 @@ void QQmlAdaptorModel::setModel(const QVariant &variant, QQmlDelegateModel *vdm, vdm, QQmlDelegateModel, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int))); qmlobject_connect(model, QAbstractItemModel, SIGNAL(modelReset()), vdm, QQmlDelegateModel, SLOT(_q_modelReset())); - qmlobject_connect(model, QAbstractItemModel, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), - vdm, QQmlDelegateModel, SLOT(_q_layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint))); qmlobject_connect(model, QAbstractItemModel, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)), vdm, QQmlDelegateModel, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint))); } else { |