diff options
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4compileddata_p.h | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 24 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4script.cpp | 18 | ||||
-rw-r--r-- | src/qml/qml/qqmldirparser.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 19 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine_p.h | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader.cpp | 146 | ||||
-rw-r--r-- | src/qml/qml/qqmltypeloader_p.h | 1 |
10 files changed, 147 insertions, 72 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index ed3b55c2c6..624e3c42e7 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -619,7 +619,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node) if (!node->fileName.isNull()) { uri = node->fileName.toString(); - if (uri.endsWith(QLatin1String(".js"))) { + if (uri.endsWith(QLatin1String(".js")) || uri.endsWith(QLatin1String(".mjs"))) { import->type = QV4::CompiledData::Import::ImportScript; } else { import->type = QV4::CompiledData::Import::ImportFile; diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index f0043cc6af..4e71bd5c27 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -822,7 +822,8 @@ struct Unit StaticData = 0x2, // Unit data persistent in memory? IsSingleton = 0x4, IsSharedLibrary = 0x8, // .pragma shared? - PendingTypeCompilation = 0x10 // the QML data structures present are incomplete and require type compilation + IsESModule = 0x10, + PendingTypeCompilation = 0x20 // the QML data structures present are incomplete and require type compilation }; quint32_le flags; quint32_le stringTableSize; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 90c75b204d..14bc5f084e 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1682,6 +1682,7 @@ QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::compileModule(boo using namespace QV4::Compiler; Compiler::Module compilerModule(debugMode); + compilerModule.unitFlags |= CompiledData::Unit::IsESModule; JSUnitGenerator jsGenerator(&compilerModule); Codegen cg(&jsGenerator, /*strictMode*/true); cg.generateFromModule(url.fileName(), url.toString(), sourceCode, moduleNode, &compilerModule); @@ -1697,22 +1698,43 @@ QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::compileModule(boo void ExecutionEngine::injectModule(const QQmlRefPointer<CompiledData::CompilationUnit> &moduleUnit) { + // Injection can happen from the QML type loader thread for example, but instantiation and + // evaluation must be limited to the ExecutionEngine's thread. + QMutexLocker moduleGuard(&moduleMutex); modules.insert(moduleUnit->finalUrl(), moduleUnit); } +QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::moduleForUrl(const QUrl &_url, const CompiledData::CompilationUnit *referrer) const +{ + QUrl url = QQmlTypeLoader::normalize(_url); + if (referrer) + url = referrer->finalUrl().resolved(url); + + QMutexLocker moduleGuard(&moduleMutex); + auto existingModule = modules.find(url); + if (existingModule == modules.end()) + return nullptr; + return *existingModule; +} + QQmlRefPointer<CompiledData::CompilationUnit> ExecutionEngine::loadModule(const QUrl &_url, const CompiledData::CompilationUnit *referrer) { QUrl url = QQmlTypeLoader::normalize(_url); if (referrer) url = referrer->finalUrl().resolved(url); + QMutexLocker moduleGuard(&moduleMutex); auto existingModule = modules.find(url); if (existingModule != modules.end()) return *existingModule; + moduleGuard.unlock(); + auto newModule = compileModule(url); - if (newModule) + if (newModule) { + moduleGuard.relock(); modules.insert(url, newModule); + } return newModule; } diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 4cd7e40013..8312adee48 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -580,8 +580,10 @@ public: QQmlRefPointer<CompiledData::CompilationUnit> compileModule(const QUrl &url, const QString &sourceCode); static QQmlRefPointer<CompiledData::CompilationUnit> compileModule(bool debugMode, const QUrl &url, const QString &sourceCode, QList<QQmlJS::DiagnosticMessage> *diagnostics); + mutable QMutex moduleMutex; QHash<QUrl, QQmlRefPointer<CompiledData::CompilationUnit>> modules; void injectModule(const QQmlRefPointer<CompiledData::CompilationUnit> &moduleUnit); + QQmlRefPointer<CompiledData::CompilationUnit> moduleForUrl(const QUrl &_url, const CompiledData::CompilationUnit *referrer = nullptr) const; QQmlRefPointer<CompiledData::CompilationUnit> loadModule(const QUrl &_url, const CompiledData::CompilationUnit *referrer = nullptr); #endif diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 37c4f27ca9..070c048c8f 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -185,23 +185,7 @@ QQmlRefPointer<QV4::CompiledData::CompilationUnit> Script::precompile(QV4::Compi parser.parseProgram(); - QList<QQmlError> errors; - - const auto diagnosticMessages = parser.diagnosticMessages(); - for (const DiagnosticMessage &m : diagnosticMessages) { - if (m.isWarning()) { - qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message)); - continue; - } - - QQmlError error; - error.setUrl(QUrl(fileName)); - error.setDescription(m.message); - error.setLine(m.loc.startLine); - error.setColumn(m.loc.startColumn); - errors << error; - } - + QList<QQmlError> errors = QQmlEnginePrivate::qmlErrorFromDiagnostics(fileName, parser.diagnosticMessages()); if (!errors.isEmpty()) { if (reportedErrors) *reportedErrors << errors; diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp index 8c89cf0e61..d87bf433b8 100644 --- a/src/qml/qml/qqmldirparser.cpp +++ b/src/qml/qml/qqmldirparser.cpp @@ -272,7 +272,7 @@ bool QQmlDirParser::parse(const QString &source) if (parseVersion(sections[1], &major, &minor)) { const QString &fileName = sections[2]; - if (fileName.endsWith(QLatin1String(".js"))) { + if (fileName.endsWith(QLatin1String(".js")) || fileName.endsWith(QLatin1String(".mjs"))) { // A 'js' extension indicates a namespaced script import const Script entry(sections[0], fileName, major, minor); _scripts.append(entry); diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 119120572c..e487aec4ab 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -2106,6 +2106,25 @@ void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QList<QQmlError dumpwarning(error); } +QList<QQmlError> QQmlEnginePrivate::qmlErrorFromDiagnostics(const QString &fileName, const QList<DiagnosticMessage> &diagnosticMessages) +{ + QList<QQmlError> errors; + for (const DiagnosticMessage &m : diagnosticMessages) { + if (m.isWarning()) { + qWarning("%s:%d : %s", qPrintable(fileName), m.loc.startLine, qPrintable(m.message)); + continue; + } + + QQmlError error; + error.setUrl(QUrl(fileName)); + error.setDescription(m.message); + error.setLine(m.loc.startLine); + error.setColumn(m.loc.startColumn); + errors << error; + } + return errors; +} + void QQmlEnginePrivate::cleanupScarceResources() { // iterate through the list and release them all. diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index da52e01793..f606896953 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -245,6 +245,8 @@ public: inline static QQmlEngine *get(QQmlEnginePrivate *p); inline static QQmlEnginePrivate *get(QV4::ExecutionEngine *e); + static QList<QQmlError> qmlErrorFromDiagnostics(const QString &fileName, const QList<QQmlJS::DiagnosticMessage> &diagnosticMessages); + static void registerBaseTypes(const char *uri, int versionMajor, int versionMinor); static void registerQtQuick2Types(const char *uri, int versionMajor, int versionMinor); static void defineQtQuick2Module(); diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 2aa64f350a..daa4604dca 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -51,6 +51,7 @@ #include <private/qqmltypecompiler_p.h> #include <private/qqmlpropertyvalidator_p.h> #include <private/qqmlpropertycachecreator_p.h> +#include <private/qv4module_p.h> #include <QtCore/qdir.h> #include <QtCore/qfile.h> @@ -2855,8 +2856,19 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent return m_value.value(); Q_ASSERT(parentCtxt && parentCtxt->engine); - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(parentCtxt->engine); QV4::ExecutionEngine *v4 = parentCtxt->engine->handle(); + + if (m_precompiledScript->unitData()->flags & QV4::CompiledData::Unit::IsESModule) { + m_loaded = true; + + m_value.set(v4, m_precompiledScript->instantiate(v4)); + if (!m_value.isNullOrUndefined()) + m_precompiledScript->evaluate(); + + return m_value.value(); + } + + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(parentCtxt->engine); QV4::Scope scope(v4); bool shared = m_precompiledScript->unitData()->flags & QV4::CompiledData::Unit::IsSharedLibrary; @@ -2945,7 +2957,8 @@ void QQmlScriptData::clear() } QQmlScriptBlob::QQmlScriptBlob(const QUrl &url, QQmlTypeLoader *loader) -: QQmlTypeLoader::Blob(url, JavaScriptFile, loader) + : QQmlTypeLoader::Blob(url, JavaScriptFile, loader) + , m_isModule(url.path().endsWith(QLatin1String(".mjs"))) { } @@ -2979,9 +2992,6 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) return; } - QmlIR::Document irUnit(isDebugging()); - - irUnit.jsModule.sourceTimeStamp = data.sourceTimeStamp(); QString error; QString source = data.readAll(&error); if (!error.isEmpty()) { @@ -2989,31 +2999,47 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) return; } - QmlIR::ScriptDirectivesCollector collector(&irUnit); - irUnit.jsParserEngine.setDirectives(&collector); + QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit; - QList<QQmlError> errors; - QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Script::precompile( - &irUnit.jsModule, &irUnit.jsParserEngine, &irUnit.jsGenerator, urlString(), finalUrlString(), - source, &errors); - // No need to addref on unit, it's initial refcount is 1 - source.clear(); - if (!errors.isEmpty()) { - setError(errors); - return; - } - if (!unit) { - unit.adopt(new QV4::CompiledData::CompilationUnit); - } - irUnit.javaScriptCompilationUnit = unit; + if (m_isModule) { + QList<QQmlJS::DiagnosticMessage> diagnostics; + unit = QV4::ExecutionEngine::compileModule(isDebugging(), url(), source, &diagnostics); + QList<QQmlError> errors = QQmlEnginePrivate::qmlErrorFromDiagnostics(urlString(), diagnostics); + if (!errors.isEmpty()) { + setError(errors); + return; + } + } else { + QmlIR::Document irUnit(isDebugging()); - QmlIR::QmlUnitGenerator qmlGenerator; - qmlGenerator.generate(irUnit); + irUnit.jsModule.sourceTimeStamp = data.sourceTimeStamp(); - if ((!disableDiskCache() || forceDiskCache()) && !isDebugging()) { - QString errorString; - if (!unit->saveToDisk(url(), &errorString)) { - qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" << unit->fileName() << "to disk:" << errorString; + QmlIR::ScriptDirectivesCollector collector(&irUnit); + irUnit.jsParserEngine.setDirectives(&collector); + + QList<QQmlError> errors; + unit = QV4::Script::precompile( + &irUnit.jsModule, &irUnit.jsParserEngine, &irUnit.jsGenerator, urlString(), finalUrlString(), + source, &errors); + // No need to addref on unit, it's initial refcount is 1 + source.clear(); + if (!errors.isEmpty()) { + setError(errors); + return; + } + if (!unit) { + unit.adopt(new QV4::CompiledData::CompilationUnit); + } + irUnit.javaScriptCompilationUnit = unit; + + QmlIR::QmlUnitGenerator qmlGenerator; + qmlGenerator.generate(irUnit); + + if ((!disableDiskCache() || forceDiskCache()) && !isDebugging()) { + QString errorString; + if (!unit->saveToDisk(url(), &errorString)) { + qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" << unit->fileName() << "to disk:" << errorString; + } } } @@ -3049,26 +3075,28 @@ void QQmlScriptBlob::done() } } - m_scriptData->typeNameCache = new QQmlTypeNameCache(m_importCache); + if (!m_isModule) { + m_scriptData->typeNameCache = new QQmlTypeNameCache(m_importCache); - QSet<QString> ns; + QSet<QString> ns; - for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) { - const ScriptReference &script = m_scripts.at(scriptIndex); + for (int scriptIndex = 0; scriptIndex < m_scripts.count(); ++scriptIndex) { + const ScriptReference &script = m_scripts.at(scriptIndex); - m_scriptData->scripts.append(script.script); + m_scriptData->scripts.append(script.script); - if (!script.nameSpace.isNull()) { - if (!ns.contains(script.nameSpace)) { - ns.insert(script.nameSpace); - m_scriptData->typeNameCache->add(script.nameSpace); + if (!script.nameSpace.isNull()) { + if (!ns.contains(script.nameSpace)) { + ns.insert(script.nameSpace); + m_scriptData->typeNameCache->add(script.nameSpace); + } } + m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace); } - m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace); + + m_importCache.populateCache(m_scriptData->typeNameCache); } m_scripts.clear(); - - m_importCache.populateCache(m_scriptData->typeNameCache); } QString QQmlScriptBlob::stringAt(int index) const @@ -3099,20 +3127,36 @@ void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer<QV4::Com QQmlRefPointer<QV4::CompiledData::CompilationUnit> script = m_scriptData->m_precompiledScript; - QList<QQmlError> errors; - for (quint32 i = 0, count = script->importCount(); i < count; ++i) { - const QV4::CompiledData::Import *import = script->importAt(i); - 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; + if (!m_isModule) { + QList<QQmlError> errors; + for (quint32 i = 0, count = script->importCount(); i < count; ++i) { + const QV4::CompiledData::Import *import = script->importAt(i); + 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; + } } } + + auto *v4 = QQmlEnginePrivate::getV4Engine(typeLoader()->engine()); + + v4->injectModule(unit); + + for (const QString &request: unit->moduleRequests()) { + if (v4->moduleForUrl(QUrl(request), unit.data())) + continue; + + const QUrl absoluteRequest = unit->finalUrl().resolved(QUrl(request)); + QQmlRefPointer<QQmlScriptBlob> blob = typeLoader()->getScript(absoluteRequest); + addDependency(blob.data()); + scriptImported(blob, /* ### */QV4::CompiledData::Location(), /*qualifier*/QString(), /*namespace*/QString()); + } } QQmlQmldirData::QQmlQmldirData(const QUrl &url, QQmlTypeLoader *loader) diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 98ac4b1bc1..26090c6af7 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -589,6 +589,7 @@ private: QList<ScriptReference> m_scripts; QQmlRefPointer<QQmlScriptData> m_scriptData; + const bool m_isModule; }; class Q_AUTOTEST_EXPORT QQmlQmldirData : public QQmlTypeLoader::Blob |