Add a checksum to QQmlPropertyCache

By running an md5 hash over the meta-object data and string tables this will
allow us to detect changes to meta-objects and invalidate QML disk caches.

Change-Id: I15b92de4cdf0cb525281b86e1c7b8ba0b11347a0
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
Simon Hausmann 2016-07-28 17:40:21 +02:00
parent 897eb7f129
commit 143f22babb
3 changed files with 85 additions and 0 deletions

View File

@ -1413,6 +1413,48 @@ bool QQmlPropertyCache::determineMetaObjectSizes(const QMetaObject &mo, int *fie
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().

View File

@ -65,6 +65,7 @@
QT_BEGIN_NAMESPACE
class QCryptographicHash;
class QMetaProperty;
class QQmlEngine;
class QJSEngine;
@ -367,6 +368,9 @@ 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();
@ -437,6 +441,7 @@ private:
QByteArray _dynamicStringData;
QString _defaultPropertyName;
QQmlPropertyCacheMethodArguments *argumentsCache;
QByteArray _checksum;
};
// QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache.

View File

@ -31,6 +31,7 @@
#include <QtQml/qqmlengine.h>
#include <private/qv8engine_p.h>
#include <private/qmetaobjectbuilder_p.h>
#include <QCryptographicHash>
#include "../../shared/util.h"
class tst_qqmlpropertycache : public QObject
@ -48,6 +49,7 @@ private slots:
void signalHandlersDerived();
void metaObjectSize_data();
void metaObjectSize();
void metaObjectChecksum();
private:
QQmlEngine engine;
@ -361,4 +363,40 @@ void tst_qqmlpropertycache::metaObjectSize()
QCOMPARE(stringDataSize, expectedStringCount);
}
void tst_qqmlpropertycache::metaObjectChecksum()
{
QMetaObjectBuilder builder;
builder.setClassName("Test");
builder.addClassInfo("foo", "bar");
QCryptographicHash hash(QCryptographicHash::Md5);
QScopedPointer<QMetaObject, QScopedPointerPodDeleter> mo(builder.toMetaObject());
QVERIFY(!mo.isNull());
QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data()));
QByteArray initialHash = hash.result();
QVERIFY(!initialHash.isEmpty());
hash.reset();
{
QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data()));
QByteArray nextHash = hash.result();
QVERIFY(!nextHash.isEmpty());
hash.reset();
QCOMPARE(initialHash, nextHash);
}
builder.addProperty("testProperty", "int", -1);
mo.reset(builder.toMetaObject());
{
QVERIFY(QQmlPropertyCache::addToHash(hash, *mo.data()));
QByteArray nextHash = hash.result();
QVERIFY(!nextHash.isEmpty());
hash.reset();
QVERIFY(initialHash != nextHash);
}
}
QTEST_MAIN(tst_qqmlpropertycache)