diff options
author | Liang Qi <liang.qi@qt.io> | 2016-10-22 21:21:39 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2016-10-22 21:21:39 +0200 |
commit | 2ff13bdf697adff8574c5cea716627c78fb6b5b3 (patch) | |
tree | f4eac21b3b54f62d9f79714f40d5c9f4804dfc0c /src/qml | |
parent | 9d487cd6bf8ad75de19a4c05eb3d2641ce4a5289 (diff) | |
parent | e13eece273195a9f39d29712a233a8dd00ddf71b (diff) |
Merge remote-tracking branch 'origin/5.8' into dev
Change-Id: I171c7dbb6a74fe743c2eec63e86e9c0bef7c7dfd
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/compiler/compiler.pri | 1 | ||||
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 2 | ||||
-rw-r--r-- | src/qml/compiler/qqmltypecompiler_p.h | 3 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata.cpp | 75 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 8 | ||||
-rw-r--r-- | src/qml/compiler/qv4compiler.cpp | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4lookup.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4persistent.cpp | 26 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4persistent_p.h | 25 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper.cpp | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4qobjectwrapper_p.h | 9 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4sequenceobject.cpp | 9 | ||||
-rw-r--r-- | src/qml/qml/qqmldata_p.h | 15 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 18 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertycache.cpp | 6 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 1 |
16 files changed, 156 insertions, 56 deletions
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri index a63de67b4c..1de5dfa6fa 100644 --- a/src/qml/compiler/compiler.pri +++ b/src/qml/compiler/compiler.pri @@ -49,4 +49,5 @@ qtConfig(qml-interpreter) { } +qtConfig(private_tests): LIBS_PRIVATE += $$QMAKE_LIBS_DYNLOAD } diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 89fa86c857..e66e8ccbff 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1533,6 +1533,8 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output, QQmlEngine output.jsGenerator.stringTable.serialize(qmlUnit); + qmlUnit->generateChecksum(); + return qmlUnit; } diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 6ad6ad8557..de6abb4ced 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -285,7 +285,8 @@ protected: // indices of the objects that are actually Component {} QVector<quint32> componentRoots; - QHash<int, int> _idToObjectIndex; + // Deliberate choice of map over hash here to ensure stable generated output. + QMap<int, int> _idToObjectIndex; QVector<int> _objectsWithAliases; QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypes; diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 35f61b4f69..e815c41a86 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -65,6 +65,12 @@ #include <algorithm> +#if defined(QT_BUILD_INTERNAL) +#if defined(Q_OS_UNIX) && !defined(QT_NO_DYNAMIC_CAST) +#include <dlfcn.h> +#endif +#endif + QT_BEGIN_NAMESPACE namespace QV4 { @@ -571,6 +577,17 @@ QQmlPropertyCache *ResolvedTypeReference::createPropertyCache(QQmlEngine *engine } } +bool ResolvedTypeReference::addToHash(QCryptographicHash *hash, QQmlEngine *engine) +{ + if (type) { + bool ok = false; + hash->addData(createPropertyCache(engine)->checksum(&ok)); + return ok; + } + hash->addData(compilationUnit->data->md5Checksum, sizeof(compilationUnit->data->md5Checksum)); + return true; +} + template <typename T> bool qtTypeInherits(const QMetaObject *mo) { while (mo) { @@ -593,20 +610,70 @@ void ResolvedTypeReference::doDynamicTypeCheck() isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo); } +#if defined(QT_BUILD_INTERNAL) + +static QByteArray ownLibraryChecksum() +{ + static QByteArray libraryChecksum; + static bool checksumInitialized = false; + if (checksumInitialized) + return libraryChecksum; + checksumInitialized = true; +#if defined(Q_OS_UNIX) && !defined(QT_NO_DYNAMIC_CAST) + Dl_info libInfo; + if (dladdr(reinterpret_cast<const void *>(&ownLibraryChecksum), &libInfo) != 0) { + QFile library(QFile::decodeName(libInfo.dli_fname)); + if (library.open(QIODevice::ReadOnly)) { + QCryptographicHash hash(QCryptographicHash::Sha1); + hash.addData(&library); + libraryChecksum = hash.result(); + } + } +#else + // Not implemented. +#endif + return libraryChecksum; +} + +#endif + bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *engine) const { for (auto it = constBegin(), end = constEnd(); it != end; ++it) { - QQmlPropertyCache *pc = it.value()->createPropertyCache(engine); - bool ok = false; - hash->addData(pc->checksum(&ok)); - if (!ok) + if (!it.value()->addToHash(hash, engine)) return false; } + + // This is a bit of a hack to make development easier. When hacking on the code generator + // the cache files may end up being re-used. To avoid that we also add the checksum of + // the QtQml library. +#if defined(QT_BUILD_INTERNAL) + hash->addData(ownLibraryChecksum()); +#endif + return true; } #endif +void Unit::generateChecksum() +{ +#ifndef V4_BOOTSTRAP + QCryptographicHash hash(QCryptographicHash::Md5); + + const int checksummableDataOffset = qOffsetOf(QV4::CompiledData::Unit, md5Checksum) + sizeof(md5Checksum); + + const char *dataPtr = reinterpret_cast<const char *>(this) + checksummableDataOffset; + hash.addData(dataPtr, unitSize - checksummableDataOffset); + + QByteArray checksum = hash.result(); + Q_ASSERT(checksum.size() == sizeof(md5Checksum)); + memcpy(md5Checksum, checksum.constData(), sizeof(md5Checksum)); +#else + memset(md5Checksum, 0, sizeof(md5Checksum)); +#endif +} + } } diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index fe18024070..8f68131ced 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -71,7 +71,7 @@ QT_BEGIN_NAMESPACE // Bump this whenever the compiler data structures change in an incompatible way. -#define QV4_DATA_STRUCTURE_VERSION 0x05 +#define QV4_DATA_STRUCTURE_VERSION 0x06 class QIODevice; class QQmlPropertyCache; @@ -612,6 +612,9 @@ struct Unit LEUInt32 unitSize; // Size of the Unit and any depending data. // END DO NOT CHANGE THESE FIELDS EVER + char md5Checksum[16]; // checksum of all bytes following this field. + void generateChecksum(); + LEUInt32 architectureIndex; // string index to QSysInfo::buildAbi() LEUInt32 codeGeneratorIndex; char dependencyMD5Checksum[16]; @@ -727,7 +730,7 @@ struct TypeReference bool errorWhenNotFound: 1; }; -// map from name index to location of first use +// Map from name index to location of first use. struct TypeReferenceMap : QHash<int, TypeReference> { TypeReference &add(int nameIndex, const Location &loc) { @@ -791,6 +794,7 @@ struct ResolvedTypeReference QQmlPropertyCache *propertyCache() const; QQmlPropertyCache *createPropertyCache(QQmlEngine *); + bool addToHash(QCryptographicHash *hash, QQmlEngine *engine); void doDynamicTypeCheck(); }; diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 729c56540d..cd822a2614 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -44,6 +44,7 @@ #include <private/qv4value_p.h> #include <private/qv4alloca_p.h> #include <wtf/MathExtras.h> +#include <QCryptographicHash> QV4::Compiler::StringTableGenerator::StringTableGenerator() { @@ -227,6 +228,7 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO { QV4::CompiledData::Unit tempHeader = generateHeader(option, functionOffsets, &jsClassDataOffset); dataPtr = reinterpret_cast<char *>(malloc(tempHeader.unitSize)); + memset(dataPtr, 0, tempHeader.unitSize); memcpy(&unit, &dataPtr, sizeof(CompiledData::Unit*)); memcpy(unit, &tempHeader, sizeof(tempHeader)); } @@ -270,6 +272,8 @@ QV4::CompiledData::Unit *QV4::Compiler::JSUnitGenerator::generateUnit(GeneratorO if (option == GenerateWithStringTable) stringTable.serialize(unit); + unit->generateChecksum(); + return unit; } @@ -363,11 +367,13 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::IR::Function *i QV4::CompiledData::Unit QV4::Compiler::JSUnitGenerator::generateHeader(QV4::Compiler::JSUnitGenerator::GeneratorOption option, QJsonPrivate::q_littleendian<quint32> *functionOffsets, uint *jsClassDataOffset) { CompiledData::Unit unit; + memset(&unit, 0, sizeof(unit)); memcpy(unit.magic, CompiledData::magic_str, sizeof(unit.magic)); unit.flags = QV4::CompiledData::Unit::IsJavascript; unit.flags |= irModule->unitFlags; unit.version = QV4_DATA_STRUCTURE_VERSION; unit.qtVersion = QT_VERSION; + memset(unit.md5Checksum, 0, sizeof(unit.md5Checksum)); unit.architectureIndex = registerString(QSysInfo::buildAbi()); unit.codeGeneratorIndex = registerString(codeGeneratorName); memset(unit.dependencyMD5Checksum, 0, sizeof(unit.dependencyMD5Checksum)); diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index 42e561bc7c..84755a6402 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -306,7 +306,7 @@ ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const ReturnedValue v = o->getLookup(l); Lookup l2 = *l; - if (l2.getter == Lookup::getter0 || l2.getter == Lookup::getter1) { + if (l->index != UINT_MAX && (l2.getter == Lookup::getter0 || l2.getter == Lookup::getter1)) { // if we have a getter0, make sure it comes first if (l2.getter == Lookup::getter0) qSwap(l1, l2); diff --git a/src/qml/jsruntime/qv4persistent.cpp b/src/qml/jsruntime/qv4persistent.cpp index a892194df3..987c322e47 100644 --- a/src/qml/jsruntime/qv4persistent.cpp +++ b/src/qml/jsruntime/qv4persistent.cpp @@ -358,14 +358,14 @@ WeakValue::WeakValue(const WeakValue &other) : val(0) { if (other.val) { - val = other.engine()->memoryManager->m_weakValues->allocate(); + allocVal(other.engine()); *val = *other.val; } } WeakValue::WeakValue(ExecutionEngine *engine, const Value &value) { - val = engine->memoryManager->m_weakValues->allocate(); + allocVal(engine); *val = value; } @@ -374,7 +374,7 @@ WeakValue &WeakValue::operator=(const WeakValue &other) if (!val) { if (!other.val) return *this; - val = other.engine()->memoryManager->m_weakValues->allocate(); + allocVal(other.engine()); } Q_ASSERT(engine() == other.engine()); @@ -388,25 +388,9 @@ WeakValue::~WeakValue() free(); } -void WeakValue::set(ExecutionEngine *engine, const Value &value) -{ - if (!val) - val = engine->memoryManager->m_weakValues->allocate(); - *val = value; -} - -void WeakValue::set(ExecutionEngine *engine, ReturnedValue value) -{ - if (!val) - val = engine->memoryManager->m_weakValues->allocate(); - *val = value; -} - -void WeakValue::set(ExecutionEngine *engine, Heap::Base *obj) +void WeakValue::allocVal(ExecutionEngine *engine) { - if (!val) - val = engine->memoryManager->m_weakValues->allocate(); - *val = obj; + val = engine->memoryManager->m_weakValues->allocate(); } void WeakValue::markOnce(ExecutionEngine *e) diff --git a/src/qml/jsruntime/qv4persistent_p.h b/src/qml/jsruntime/qv4persistent_p.h index a0ade2068f..c1cd1f34df 100644 --- a/src/qml/jsruntime/qv4persistent_p.h +++ b/src/qml/jsruntime/qv4persistent_p.h @@ -154,9 +154,26 @@ public: WeakValue &operator=(const WeakValue &other); ~WeakValue(); - void set(ExecutionEngine *engine, const Value &value); - void set(ExecutionEngine *engine, ReturnedValue value); - void set(ExecutionEngine *engine, Heap::Base *obj); + void set(ExecutionEngine *engine, const Value &value) + { + if (!val) + allocVal(engine); + *val = value; + } + + void set(ExecutionEngine *engine, ReturnedValue value) + { + if (!val) + allocVal(engine); + *val = value; + } + + void set(ExecutionEngine *engine, Heap::Base *obj) + { + if (!val) + allocVal(engine); + *val = obj; + } ReturnedValue value() const { return (val ? val->asReturnedValue() : Encode::undefined()); @@ -192,6 +209,8 @@ private: Value *val; private: + Q_NEVER_INLINE void allocVal(ExecutionEngine *engine); + void free(); }; diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 295b3413da..6b87f282cf 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -195,12 +195,6 @@ static QV4::ReturnedValue loadProperty(QV4::ExecutionEngine *v4, QObject *object } } -void Heap::QObjectWrapper::init(QObject *object) -{ - Object::init(); - qObj.init(object); -} - void QObjectWrapper::initializeBindings(ExecutionEngine *engine) { engine->functionPrototype()->defineDefaultProperty(QStringLiteral("connect"), method_connect); diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 8b2fd506e8..504f6a69b8 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -78,7 +78,12 @@ namespace Heap { struct QQmlValueTypeWrapper; struct Q_QML_EXPORT QObjectWrapper : Object { - void init(QObject *object); + void init(QObject *object) + { + Object::init(); + qObj.init(object); + } + void destroy() { qObj.destroy(); Object::destroy(); @@ -196,7 +201,7 @@ protected: static ReturnedValue method_disconnect(CallContext *ctx); private: - static ReturnedValue wrap_slowPath(ExecutionEngine *engine, QObject *object); + Q_NEVER_INLINE static ReturnedValue wrap_slowPath(ExecutionEngine *engine, QObject *object); }; inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object) diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 3eb7772db7..58da7b9f68 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -592,14 +592,11 @@ void Heap::QQmlSequence<Container>::init(QObject *object, int propertyIndex) namespace QV4 { typedef QQmlSequence<QVector<int> > QQmlIntVectorList; -template<> -DEFINE_OBJECT_VTABLE(QQmlIntVectorList); +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlIntVectorList); typedef QQmlSequence<QVector<qreal> > QQmlRealVectorList; -template<> -DEFINE_OBJECT_VTABLE(QQmlRealVectorList); +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlRealVectorList); typedef QQmlSequence<QVector<bool> > QQmlBoolVectorList; -template<> -DEFINE_OBJECT_VTABLE(QQmlBoolVectorList); +DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlBoolVectorList); typedef QQmlSequence<QStringList> QQmlQStringList; DEFINE_OBJECT_TEMPLATE_VTABLE(QQmlQStringList); typedef QQmlSequence<QList<QString> > QQmlStringList; diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index dce75c51aa..e271598c2d 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -207,8 +207,7 @@ public: } else if (priv->declarativeData) { return static_cast<QQmlData *>(priv->declarativeData); } else if (create) { - priv->declarativeData = new QQmlData; - return static_cast<QQmlData *>(priv->declarativeData); + return createQQmlData(priv); } else { return 0; } @@ -231,12 +230,22 @@ public: static inline void flushPendingBinding(QObject *, QQmlPropertyIndex propertyIndex); - static QQmlPropertyCache *ensurePropertyCache(QJSEngine *engine, QObject *object); + static QQmlPropertyCache *ensurePropertyCache(QJSEngine *engine, QObject *object) + { + Q_ASSERT(engine); + QQmlData *ddata = QQmlData::get(object, /*create*/true); + if (Q_LIKELY(ddata->propertyCache)) + return ddata->propertyCache; + return createPropertyCache(engine, object); + } private: // For attachedProperties mutable QQmlDataExtended *extendedData; + Q_NEVER_INLINE static QQmlData *createQQmlData(QObjectPrivate *priv); + Q_NEVER_INLINE static QQmlPropertyCache *createPropertyCache(QJSEngine *engine, QObject *object); + void flushPendingBindingImpl(QQmlPropertyIndex index); Q_ALWAYS_INLINE bool hasBitSet(int bit) const diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index d0c899af12..3fa5838e10 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1879,15 +1879,19 @@ void QQmlData::setPendingBindingBit(QObject *obj, int coreIndex) QQmlData_setBit(this, obj, coreIndex * 2 + 1); } -QQmlPropertyCache *QQmlData::ensurePropertyCache(QJSEngine *engine, QObject *object) +QQmlData *QQmlData::createQQmlData(QObjectPrivate *priv) +{ + Q_ASSERT(priv); + priv->declarativeData = new QQmlData; + return static_cast<QQmlData *>(priv->declarativeData); +} + +QQmlPropertyCache *QQmlData::createPropertyCache(QJSEngine *engine, QObject *object) { - Q_ASSERT(engine); QQmlData *ddata = QQmlData::get(object, /*create*/true); - if (!ddata->propertyCache) { - ddata->propertyCache = QJSEnginePrivate::get(engine)->cache(object); - if (ddata->propertyCache) - ddata->propertyCache->addref(); - } + ddata->propertyCache = QJSEnginePrivate::get(engine)->cache(object); + if (ddata->propertyCache) + ddata->propertyCache->addref(); return ddata->propertyCache; } diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 672b36ea75..bf220a905c 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -1429,6 +1429,12 @@ QByteArray QQmlPropertyCache::checksum(bool *ok) return _checksum; } + // Generate a checksum on the meta-object data only on C++ types. + if (!_metaObject || _ownMetaObject) { + *ok = false; + return _checksum; + } + QCryptographicHash hash(QCryptographicHash::Md5); if (_parent) { diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 3e599aed6c..a74ba141be 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2232,6 +2232,7 @@ void QQmlTypeData::done() // verify if any dependencies changed if we're using a cache if (m_document.isNull() && !m_compiledData->verifyChecksum(engine, resolvedTypeCache)) { + qCDebug(DBG_DISK_CACHE) << "Checksum mismatch for cached version of" << m_compiledData->url().toString(); if (!loadFromSource()) return; m_backupSourceCode.clear(); |