aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmltypeloader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqmltypeloader.cpp')
-rw-r--r--src/qml/qml/qqmltypeloader.cpp154
1 files changed, 103 insertions, 51 deletions
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index a30d25c30a..a74397bd93 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -46,6 +46,9 @@ namespace {
};
}
+Q_TRACE_POINT(qtqml, QQmlCompiling_entry, const QUrl &url)
+Q_TRACE_POINT(qtqml, QQmlCompiling_exit)
+
/*!
\class QQmlTypeLoader
\brief The QQmlTypeLoader class abstracts loading files and their dependencies over the network.
@@ -452,7 +455,7 @@ QQmlTypeLoader::Blob::PendingImport::PendingImport(
QQmlTypeLoader::Blob::Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader)
: QQmlDataBlob(url, type, loader)
- , m_importCache(new QQmlImports(loader), QQmlRefPointer<QQmlImports>::Adopt)
+ , m_importCache(new QQmlImports(), QQmlRefPointer<QQmlImports>::Adopt)
{
}
@@ -527,8 +530,7 @@ bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &da
typeLoader()->setQmldirContent(qmldirIdentifier, data->content());
const QTypeRevision version = m_importCache->updateQmldirContent(
- typeLoader()->importDatabase(), import->uri, import->qualifier, qmldirIdentifier,
- qmldirUrl, errors);
+ typeLoader(), import->uri, import->qualifier, qmldirIdentifier, qmldirUrl, errors);
if (!version.isValid())
return false;
@@ -551,15 +553,12 @@ bool QQmlTypeLoader::Blob::updateQmldir(const QQmlRefPointer<QQmlQmldirData> &da
bool QQmlTypeLoader::Blob::addScriptImport(const QQmlTypeLoader::Blob::PendingImportPtr &import)
{
const QUrl url(import->uri);
- const auto module = m_typeLoader->engine()->handle()->moduleForUrl(url);
- QQmlRefPointer<QQmlScriptBlob> blob;
- if (module.native) {
- blob.adopt(new QQmlScriptBlob(url, m_typeLoader));
- blob->initializeFromNative(*module.native);
- blob->tryDone();
- } else {
- blob = typeLoader()->getScript(finalUrl().resolved(url));
- }
+ QQmlTypeLoader *loader = typeLoader();
+ QQmlRefPointer<QQmlScriptBlob> blob = loader->injectedScript(url);
+ if (!blob)
+ blob = loader->getScript(finalUrl().resolved(url));
+ else
+ Q_ASSERT(blob->status() == QQmlDataBlob::Status::Complete);
addDependency(blob.data());
scriptImported(blob, import->location, import->qualifier, QString());
return true;
@@ -567,7 +566,6 @@ bool QQmlTypeLoader::Blob::addScriptImport(const QQmlTypeLoader::Blob::PendingIm
bool QQmlTypeLoader::Blob::addFileImport(const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
{
- QQmlImportDatabase *importDatabase = typeLoader()->importDatabase();
QQmlImports::ImportFlags flags;
QUrl importUrl(import->uri);
@@ -581,8 +579,8 @@ bool QQmlTypeLoader::Blob::addFileImport(const QQmlTypeLoader::Blob::PendingImpo
}
const QTypeRevision version = m_importCache->addFileImport(
- importDatabase, import->uri, import->qualifier, import->version, flags,
- import->precedence, nullptr, errors);
+ typeLoader(), import->uri, import->qualifier, import->version, flags,
+ import->precedence, nullptr, errors);
if (!version.isValid())
return false;
@@ -604,6 +602,28 @@ bool QQmlTypeLoader::Blob::addFileImport(const QQmlTypeLoader::Blob::PendingImpo
return true;
}
+static void addDependencyImportError(
+ const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
+{
+ QQmlError error;
+ QString reason = errors->front().description();
+ if (reason.size() > 512)
+ reason = reason.first(252) + QLatin1String("... ...") + reason.last(252);
+ if (import->version.hasMajorVersion()) {
+ error.setDescription(QQmlImportDatabase::tr(
+ "module \"%1\" version %2.%3 cannot be imported because:\n%4")
+ .arg(import->uri).arg(import->version.majorVersion())
+ .arg(import->version.hasMinorVersion()
+ ? QString::number(import->version.minorVersion())
+ : QLatin1String("x"))
+ .arg(reason));
+ } else {
+ error.setDescription(QQmlImportDatabase::tr("module \"%1\" cannot be imported because:\n%2")
+ .arg(import->uri, reason));
+ }
+ errors->prepend(error);
+}
+
bool QQmlTypeLoader::Blob::addLibraryImport(const QQmlTypeLoader::Blob::PendingImportPtr &import, QList<QQmlError> *errors)
{
QQmlImportDatabase *importDatabase = typeLoader()->importDatabase();
@@ -619,9 +639,8 @@ bool QQmlTypeLoader::Blob::addLibraryImport(const QQmlTypeLoader::Blob::PendingI
[&](const QString &qmldirFilePath, const QString &qmldirUrl) {
// This is a local library import
const QTypeRevision actualVersion = m_importCache->addLibraryImport(
- importDatabase, import->uri, import->qualifier,
- import->version, qmldirFilePath, qmldirUrl, import->flags, import->precedence,
- errors);
+ typeLoader(), import->uri, import->qualifier, import->version, qmldirFilePath,
+ qmldirUrl, import->flags, import->precedence, errors);
if (!actualVersion.isValid())
return false;
@@ -630,20 +649,7 @@ bool QQmlTypeLoader::Blob::addLibraryImport(const QQmlTypeLoader::Blob::PendingI
import->version = actualVersion;
if (!loadImportDependencies(import, qmldirFilePath, import->flags, errors)) {
- QQmlError error;
- if (import->version.hasMajorVersion()) {
- error.setDescription(QQmlImportDatabase::tr(
- "module \"%1\" version %2.%3 cannot be imported because\n%4")
- .arg(import->uri).arg(import->version.majorVersion())
- .arg(import->version.hasMinorVersion()
- ? QString::number(import->version.minorVersion())
- : QLatin1String("x"))
- .arg(errors->front().description()));
- } else {
- error.setDescription(QQmlImportDatabase::tr("module \"%1\" cannot be imported because\n%2")
- .arg(import->uri, errors->front().description()));
- }
- errors->prepend(error);
+ addDependencyImportError(import, errors);
return false;
}
@@ -654,7 +660,13 @@ bool QQmlTypeLoader::Blob::addLibraryImport(const QQmlTypeLoader::Blob::PendingI
switch (qmldirResult) {
case QQmlImportDatabase::QmldirFound:
return true;
- case QQmlImportDatabase::QmldirNotFound:
+ case QQmlImportDatabase::QmldirNotFound: {
+ if (!loadImportDependencies(import, QString(), import->flags, errors)) {
+ addDependencyImportError(import, errors);
+ return false;
+ }
+ break;
+ }
case QQmlImportDatabase::QmldirInterceptedToRemote:
break;
case QQmlImportDatabase::QmldirRejected:
@@ -676,8 +688,8 @@ bool QQmlTypeLoader::Blob::addLibraryImport(const QQmlTypeLoader::Blob::PendingI
|| QQmlMetaType::latestModuleVersion(import->uri).isValid())) {
if (!m_importCache->addLibraryImport(
- importDatabase, import->uri, import->qualifier, import->version,
- QString(), QString(), import->flags, import->precedence, errors).isValid()) {
+ typeLoader(), import->uri, import->qualifier, import->version, QString(),
+ QString(), import->flags, import->precedence, errors).isValid()) {
return false;
}
} else {
@@ -696,9 +708,9 @@ bool QQmlTypeLoader::Blob::addLibraryImport(const QQmlTypeLoader::Blob::PendingI
if (!remotePathList.isEmpty()) {
// Add this library and request the possible locations for it
const QTypeRevision version = m_importCache->addLibraryImport(
- importDatabase, import->uri, import->qualifier, import->version,
- QString(), QString(), import->flags | QQmlImports::ImportIncomplete,
- import->precedence, errors);
+ typeLoader(), import->uri, import->qualifier, import->version, QString(),
+ QString(), import->flags | QQmlImports::ImportIncomplete, import->precedence,
+ errors);
if (!version.isValid())
return false;
@@ -815,10 +827,10 @@ bool QQmlTypeLoader::Blob::loadImportDependencies(
const QQmlTypeLoader::Blob::PendingImportPtr &currentImport, const QString &qmldirUri,
QQmlImports::ImportFlags flags, QList<QQmlError> *errors)
{
- const QQmlTypeLoaderQmldirContent qmldir = typeLoader()->qmldirContent(qmldirUri);
- const QList<QQmlDirParser::Import> implicitImports
- = QQmlMetaType::moduleImports(currentImport->uri, currentImport->version)
- + qmldir.imports();
+ QList<QQmlDirParser::Import> implicitImports
+ = QQmlMetaType::moduleImports(currentImport->uri, currentImport->version);
+ if (!qmldirUri.isEmpty())
+ implicitImports += typeLoader()->qmldirContent(qmldirUri).imports();
// Prevent overflow from one category of import into the other.
switch (currentImport->precedence) {
@@ -826,7 +838,7 @@ bool QQmlTypeLoader::Blob::loadImportDependencies(
case QQmlImportInstance::Lowest: {
QQmlError error;
error.setDescription(
- QString::fromLatin1("Too many dependent imports")
+ QString::fromLatin1("Too many dependent imports for %1 %2.%3")
.arg(currentImport->uri)
.arg(currentImport->version.majorVersion())
.arg(currentImport->version.minorVersion()));
@@ -965,6 +977,7 @@ QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(const QUrl &unNormalizedUrl
// this was started Asynchronous, but we need to force Synchronous
// completion now (if at all possible with this type of URL).
+#if QT_CONFIG(thread)
if (!m_thread->isThisThread()) {
// this only works when called directly from the UI thread, but not
// when recursively called on the QML thread via resolveTypes()
@@ -973,6 +986,7 @@ QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(const QUrl &unNormalizedUrl
m_thread->waitForNextMessage();
}
}
+#endif
}
return typeData;
@@ -992,6 +1006,26 @@ QQmlRefPointer<QQmlTypeData> QQmlTypeLoader::getType(const QByteArray &data, con
return QQmlRefPointer<QQmlTypeData>(typeData, QQmlRefPointer<QQmlTypeData>::Adopt);
}
+void QQmlTypeLoader::injectScript(const QUrl &relativeUrl, const QV4::Value &value)
+{
+ LockHolder<QQmlTypeLoader> holder(this);
+
+ QQmlScriptBlob *blob = new QQmlScriptBlob(relativeUrl, this);
+ blob->initializeFromNative(value);
+ blob->m_isDone = true;
+ blob->m_data.setStatus(QQmlDataBlob::Complete);
+ m_scriptCache.insert(relativeUrl, blob);
+}
+
+QQmlRefPointer<QQmlScriptBlob> QQmlTypeLoader::injectedScript(const QUrl &relativeUrl)
+{
+ LockHolder<QQmlTypeLoader> holder(this);
+ const auto it = m_scriptCache.constFind(relativeUrl);
+ return (it != m_scriptCache.constEnd() && (*it)->isNative())
+ ? *it
+ : QQmlRefPointer<QQmlScriptBlob>();
+}
+
/*!
Return a QQmlScriptBlob for \a url. The QQmlScriptData may be cached.
*/
@@ -1294,6 +1328,11 @@ and qmldir information.
*/
void QQmlTypeLoader::clearCache()
{
+ // Pending messages typically hold references to the blobs they want to be delivered to.
+ // We don't want them anymore.
+ if (m_thread)
+ m_thread->discardMessages();
+
for (TypeCache::Iterator iter = m_typeCache.begin(), end = m_typeCache.end(); iter != end; ++iter)
(*iter)->release();
for (ScriptCache::Iterator iter = m_scriptCache.begin(), end = m_scriptCache.end(); iter != end; ++iter)
@@ -1310,7 +1349,6 @@ void QQmlTypeLoader::clearCache()
m_importDirCache.clear();
m_importQmlDirCache.clear();
m_checksumCache.clear();
- QQmlMetaType::freeUnusedTypesAndCaches();
}
void QQmlTypeLoader::updateTypeCacheTrimThreshold()
@@ -1332,15 +1370,29 @@ void QQmlTypeLoader::trimCache()
// 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->count() == 1 && (typeData->isError() || typeData->isComplete())
- && (!typeData->m_compiledData || typeData->m_compiledData->count() == 1)) {
- // There are no live objects of this type
- iter.value()->release();
- iter = m_typeCache.erase(iter);
- deletedOneType = true;
- } else {
+ if (typeData->count() != 1 || (!typeData->isError() && !typeData->isComplete())) {
++iter;
+ continue;
}
+
+ const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit
+ = typeData->m_compiledData;
+ if (compilationUnit) {
+ if (compilationUnit->count()
+ > QQmlMetaType::countInternalCompositeTypeSelfReferences(
+ compilationUnit) + 1) {
+ ++iter;
+ continue;
+ }
+
+ QQmlMetaType::unregisterInternalCompositeType(compilationUnit);
+ Q_ASSERT(compilationUnit->count() == 1);
+ }
+
+ // There are no live objects of this type
+ iter.value()->release();
+ iter = m_typeCache.erase(iter);
+ deletedOneType = true;
}
if (!deletedOneType)