diff options
author | Simon Hausmann <simon.hausmann@qt.io> | 2016-06-06 16:19:47 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2016-07-19 14:50:02 +0000 |
commit | e0e50532d29d02c8bcbab01dbfb72377102eaf8f (patch) | |
tree | 93e320ee4db05727dffd3de51dd4a77019afe480 /src/qml/qml | |
parent | fa06494d888727d229cd47efbe7265d61c7f7c25 (diff) |
Added basic loading of compilation units from disk
This remains hidden behind the QML_DISK_CACHE flag until all backends
support it and the verification code is in place.
Change-Id: Ic77c64e20a2dc4c43473c47640e09f8070237e85
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/qml/qml')
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 126 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader_p.h | 2 |
2 files changed, 122 insertions, 6 deletions
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 190ac29e33..8deb41c505 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -50,6 +50,7 @@ #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> @@ -99,6 +100,7 @@ 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 @@ -1953,7 +1955,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); @@ -2038,6 +2042,106 @@ 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(), &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() { // Check all script dependencies for errors @@ -2062,7 +2166,7 @@ void QQmlTypeData::done() 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; @@ -2093,9 +2197,14 @@ void QQmlTypeData::done() } } - // Compile component - if (!isError()) - compile(); + if (!isError()) { + if (!m_document.isNull()) { + // Compile component + compile(); + } else { + rebuildTypeAndPropertyCaches(); + } + } if (!isError()) { QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine()); @@ -2193,6 +2302,9 @@ bool QQmlTypeData::loadImplicitImport() void QQmlTypeData::dataReceived(const Data &data) { + if (tryLoadFromDiskCache()) + return; + QString error; QString code = QString::fromUtf8(data.readAll(&error)); if (!error.isEmpty()) { @@ -2315,6 +2427,8 @@ 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); } @@ -2336,7 +2450,7 @@ void QQmlTypeData::compile() setError(compiler.compilationErrors()); return; } - if (diskCache()) { + if (diskCache() || forceDiskCacheRefresh()) { QString errorString; if (!m_compiledData->saveToDisk(&errorString)) { qDebug() << "Error saving cached version of" << m_compiledData->url().toString() << "to disk:" << errorString; diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 2030dbf427..3e815878f8 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -441,10 +441,12 @@ protected: virtual QString stringAt(int index) const; private: + bool tryLoadFromDiskCache(); void continueLoadFromIR(); void resolveTypes(); QQmlCompileError buildTypeResolutionCaches(QQmlRefPointer<QQmlTypeNameCache> *importCache, QV4::CompiledData::CompilationUnit::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); |