From 4b2b1fc12137450d34e8324c0dbe2af1e90b9e6a Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Thu, 16 Aug 2018 13:06:22 +0200 Subject: Add support for compiling ES modules ahead of time This is also pretty straight-forward by adding .mjs as supported extension in the qmake and cmake support. This also tweaks qv4engine.cpp to share the same module compilation function across all code paths. Change-Id: Ia0e23c78a794f2330ecf8f991ee6ea948f4ac89d Reviewed-by: Qt CI Bot Reviewed-by: Lars Knoll --- src/qml/compiler/qv4compileddata.cpp | 4 +- src/qml/compiler/qv4compileddata_p.h | 2 +- src/qml/jsruntime/jsruntime.pri | 2 +- src/qml/jsruntime/qv4engine.cpp | 53 ++++---- src/qml/jsruntime/qv4engine_p.h | 4 +- src/qml/qml/qqmltypeloader.cpp | 4 +- .../qml/ecmascripttests/qjstest/test262runner.cpp | 2 +- tests/auto/qml/qmlcachegen/jsmoduleimport.qml | 6 + tests/auto/qml/qmlcachegen/qmlcachegen.pro | 2 + tests/auto/qml/qmlcachegen/script.mjs | 4 + tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp | 31 +++++ tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in | 3 +- tools/qmlcachegen/qmlcachegen.cpp | 149 +++++++++++---------- tools/qmlcachegen/qtquickcompiler.prf | 5 +- tools/qmlcachegen/resourcefilemapper.cpp | 2 +- tools/qmlcachegen/resourcefilter.cpp | 4 +- 16 files changed, 167 insertions(+), 110 deletions(-) create mode 100644 tests/auto/qml/qmlcachegen/jsmoduleimport.qml create mode 100644 tests/auto/qml/qmlcachegen/script.mjs diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index a4e49377a8..98aa6bb180 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -91,9 +91,9 @@ static_assert(sizeof(Unit::libraryVersionHash) >= QML_COMPILE_HASH_LENGTH + 1, " #endif -CompilationUnit::CompilationUnit(const Unit *unitData) +CompilationUnit::CompilationUnit(const Unit *unitData, const QString &fileName, const QString &finalUrlString) { - setUnitData(unitData); + setUnitData(unitData, nullptr, fileName, finalUrlString); } #ifndef V4_BOOTSTRAP diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 4e71bd5c27..dca38eae54 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -1048,7 +1048,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit final : public CompilationUnitBase const Unit *data = nullptr; const QmlUnit *qmlData = nullptr; public: - CompilationUnit(const Unit *unitData = nullptr); + CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(), const QString &finalUrlString = QString()); #ifdef V4_BOOTSTRAP ~CompilationUnit() {} #else diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index c42c2d48c8..97819438cb 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -3,7 +3,6 @@ INCLUDEPATH += $$OUT_PWD !qmldevtools_build { SOURCES += \ - $$PWD/qv4engine.cpp \ $$PWD/qv4context.cpp \ $$PWD/qv4persistent.cpp \ $$PWD/qv4lookup.cpp \ @@ -147,6 +146,7 @@ HEADERS += \ $$PWD/qv4value_p.h SOURCES += \ + $$PWD/qv4engine.cpp \ $$PWD/qv4runtime.cpp \ $$PWD/qv4string.cpp \ $$PWD/qv4value.cpp \ diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index c5eec33d18..ea17f3423c 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -37,6 +37,22 @@ ** ****************************************************************************/ #include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef V4_BOOTSTRAP + #include #include #include @@ -75,10 +91,6 @@ #include "qv4reflect_p.h" #include "qv4proxy_p.h" #include "qv4stackframe_p.h" -#include -#include -#include -#include #if QT_CONFIG(qml_sequence_object) #include "qv4sequenceobject_p.h" @@ -102,11 +114,6 @@ #endif #include -#include -#include -#include -#include - #if USE(PTHREADS) # include #if !defined(Q_OS_INTEGRITY) @@ -121,10 +128,14 @@ #include #endif +#endif // #ifndef V4_BOOTSTRAP + QT_BEGIN_NAMESPACE using namespace QV4; +#ifndef V4_BOOTSTRAP + static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1); ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const QV4::Value *, int) @@ -132,19 +143,6 @@ ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const return b->engine()->throwTypeError(); } - -#ifdef V4_BOOTSTRAP -QJSEngine *ExecutionEngine::jsEngine() const -{ - return publicEngine; -} - -QQmlEngine *ExecutionEngine::qmlEngine() const -{ - return v8Engine->engine(); -} -#endif // V4_BOOTSTRAP - qint32 ExecutionEngine::maxCallDepth = -1; ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) @@ -1645,7 +1643,7 @@ QQmlRefPointer ExecutionEngine::compileModule(con QQmlRefPointer ExecutionEngine::compileModule(const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp) { QList diagnostics; - auto unit = compileModule(/*debugMode*/debugger() != nullptr, url, sourceCode, sourceTimeStamp, &diagnostics); + auto unit = compileModule(/*debugMode*/debugger() != nullptr, url.toString(), sourceCode, sourceTimeStamp, &diagnostics); for (const QQmlJS::DiagnosticMessage &m : diagnostics) { if (m.isError()) { throwSyntaxError(m.message, url.toString(), m.loc.startLine, m.loc.startColumn); @@ -1658,7 +1656,9 @@ QQmlRefPointer ExecutionEngine::compileModule(con return unit; } -QQmlRefPointer ExecutionEngine::compileModule(bool debugMode, const QUrl &url, const QString &sourceCode, +#endif // ifndef V4_BOOTSTRAP + +QQmlRefPointer ExecutionEngine::compileModule(bool debugMode, const QString &url, const QString &sourceCode, const QDateTime &sourceTimeStamp, QList *diagnostics) { QQmlJS::Engine ee; @@ -1689,7 +1689,7 @@ QQmlRefPointer ExecutionEngine::compileModule(boo compilerModule.sourceTimeStamp = sourceTimeStamp; JSUnitGenerator jsGenerator(&compilerModule); Codegen cg(&jsGenerator, /*strictMode*/true); - cg.generateFromModule(url.toString(), url.toString(), sourceCode, moduleNode, &compilerModule); + cg.generateFromModule(url, url, sourceCode, moduleNode, &compilerModule); auto errors = cg.errors(); if (diagnostics) *diagnostics << errors; @@ -1700,6 +1700,8 @@ QQmlRefPointer ExecutionEngine::compileModule(boo return cg.generateCompilationUnit(); } +#ifndef V4_BOOTSTRAP + void ExecutionEngine::injectModule(const QQmlRefPointer &moduleUnit) { // Injection can happen from the QML type loader thread for example, but instantiation and @@ -1982,5 +1984,6 @@ static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &v return wrapper->object(); } +#endif // ifndef V4_BOOTSTRAP QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index c8f8efaebf..7608c04800 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -55,6 +55,8 @@ #include "qv4context_p.h" #include #include "qv4enginebase_p.h" +#include +#include #ifndef V4_BOOTSTRAP # include "qv4function_p.h" @@ -575,10 +577,10 @@ public: double localTZA = 0.0; // local timezone, initialized at startup + static QQmlRefPointer compileModule(bool debugMode, const QString &url, const QString &sourceCode, const QDateTime &sourceTimeStamp, QList *diagnostics); #ifndef V4_BOOTSTRAP QQmlRefPointer compileModule(const QUrl &url); QQmlRefPointer compileModule(const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp); - static QQmlRefPointer compileModule(bool debugMode, const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp, QList *diagnostics); mutable QMutex moduleMutex; QHash> modules; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 209a32b8cc..739280bbfe 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -3003,7 +3003,7 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) if (m_isModule) { QList diagnostics; - unit = QV4::ExecutionEngine::compileModule(isDebugging(), url(), source, data.sourceTimeStamp(), &diagnostics); + unit = QV4::ExecutionEngine::compileModule(isDebugging(), urlString(), source, data.sourceTimeStamp(), &diagnostics); QList errors = QQmlEnginePrivate::qmlErrorFromDiagnostics(urlString(), diagnostics); if (!errors.isEmpty()) { setError(errors); @@ -3054,7 +3054,7 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) void QQmlScriptBlob::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) { QQmlRefPointer compilationUnit; - compilationUnit.adopt(new QV4::CompiledData::CompilationUnit(unit)); + compilationUnit.adopt(new QV4::CompiledData::CompilationUnit(unit, urlString(), finalUrlString())); initializeFromCompilationUnit(compilationUnit); } diff --git a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp index 98a99e6673..55c8f23dbd 100644 --- a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp +++ b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp @@ -462,7 +462,7 @@ static bool executeTest(const QByteArray &data, bool runAsModule = false, const QFile f(url.toLocalFile()); if (f.open(QIODevice::ReadOnly)) { QByteArray content = harnessForModules + f.readAll(); - module = vm.compileModule(url, QString::fromUtf8(content), QFileInfo(f).lastModified()); + module = vm.compileModule(url.toString(), QString::fromUtf8(content), QFileInfo(f).lastModified()); if (vm.hasException) break; vm.injectModule(module); diff --git a/tests/auto/qml/qmlcachegen/jsmoduleimport.qml b/tests/auto/qml/qmlcachegen/jsmoduleimport.qml new file mode 100644 index 0000000000..c1fad7fee2 --- /dev/null +++ b/tests/auto/qml/qmlcachegen/jsmoduleimport.qml @@ -0,0 +1,6 @@ +import QtQml 2.0 +import "script.mjs" as Script + +QtObject { + property bool ok: Script.ok() +} diff --git a/tests/auto/qml/qmlcachegen/qmlcachegen.pro b/tests/auto/qml/qmlcachegen/qmlcachegen.pro index 6dee2a0454..7f7b3128cf 100644 --- a/tests/auto/qml/qmlcachegen/qmlcachegen.pro +++ b/tests/auto/qml/qmlcachegen/qmlcachegen.pro @@ -19,4 +19,6 @@ RESOURCES += Enums.qml # QTBUG-46375 !win32: RESOURCES += trickypaths_umlaut.qrc +RESOURCES += jsmoduleimport.qml script.mjs + QT += core-private qml-private testlib diff --git a/tests/auto/qml/qmlcachegen/script.mjs b/tests/auto/qml/qmlcachegen/script.mjs new file mode 100644 index 0000000000..459c336125 --- /dev/null +++ b/tests/auto/qml/qmlcachegen/script.mjs @@ -0,0 +1,4 @@ + +export function ok() { + return true +} diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp index 17c12b87e8..6c399f6874 100644 --- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp +++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp @@ -59,6 +59,7 @@ private slots: void qrcScriptImport(); void fsScriptImport(); + void moduleScriptImport(); void enums(); @@ -538,6 +539,36 @@ void tst_qmlcachegen::fsScriptImport() QCOMPARE(obj->property("value").toInt(), 42); } +void tst_qmlcachegen::moduleScriptImport() +{ + QQmlEngine engine; + CleanlyLoadingComponent component(&engine, QUrl("qrc:///jsmoduleimport.qml")); + QVERIFY2(!component.isError(), qPrintable(component.errorString())); + QScopedPointer obj(component.create()); + QVERIFY(!obj.isNull()); + QTRY_VERIFY(obj->property("ok").toBool()); + + QVERIFY(QFile::exists(":/script.mjs")); + QCOMPARE(QFileInfo(":/script.mjs").size(), 0); + + { + auto componentPrivate = QQmlComponentPrivate::get(&component); + QVERIFY(componentPrivate); + auto compilationUnit = componentPrivate->compilationUnit->dependentScripts.first()->compilationUnit(); + QVERIFY(compilationUnit); + auto unitData = compilationUnit->unitData(); + QVERIFY(unitData); + QVERIFY(unitData->flags & QV4::CompiledData::Unit::StaticData); + QVERIFY(unitData->flags & QV4::CompiledData::Unit::IsESModule); + + QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError; + const QV4::CompiledData::Unit *unitFromResources = QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/script.mjs"), &error); + QVERIFY(unitFromResources); + + QCOMPARE(unitFromResources, compilationUnit->unitData()); + } +} + void tst_qmlcachegen::enums() { QQmlEngine engine; diff --git a/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in b/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in index e4963c3a33..a5c531fb0d 100644 --- a/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in +++ b/tools/qmlcachegen/Qt5QuickCompilerConfig.cmake.in @@ -4,6 +4,7 @@ function(QTQUICK_COMPILER_DETERMINE_OUTPUT_FILENAME outvariable filename) file(RELATIVE_PATH relpath ${CMAKE_CURRENT_SOURCE_DIR} ${filename}) string(REPLACE \".qml\" \"_qml\" relpath ${relpath}) string(REPLACE \".js\" \"_js\" relpath ${relpath}) + string(REPLACE \".mjs\" \"_mjs\" relpath ${relpath}) string(REPLACE \"/\" \"_\" relpath ${relpath}) set(${outvariable} ${CMAKE_CURRENT_BINARY_DIR}/${relpath}.cpp PARENT_SCOPE) endfunction() @@ -63,7 +64,7 @@ but not all the files it references. string(REGEX REPLACE \"[\r\n]+\" \";\" rcc_contents ${rcc_contents}) foreach(it ${rcc_contents}) get_filename_component(extension ${it} EXT) - if(extension STREQUAL \".qml\" OR extension STREQUAL \".js\" OR extension STREQUAL \".ui.qml\") + if(extension STREQUAL \".qml\" OR extension STREQUAL \".js\" OR extension STREQUAL \".ui.qml\" OR extension STREQUAL \".mjs\") qtquick_compiler_determine_output_filename(output_file ${it}) add_custom_command(OUTPUT ${output_file} COMMAND ${compiler_path} ARGS --resource=${input_resource} ${it} -o ${output_file} DEPENDS ${it}) list(APPEND compiler_output ${output_file}) diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp index 4dddab18b2..762f6e7221 100644 --- a/tools/qmlcachegen/qmlcachegen.cpp +++ b/tools/qmlcachegen/qmlcachegen.cpp @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include @@ -67,6 +69,7 @@ struct Error QString message; void print(); Error augment(const QString &contextErrorMessage) const; + void appendDiagnostics(const QString &inputFileName, const QList &diagnostics); }; void Error::print() @@ -96,6 +99,15 @@ QString diagnosticErrorMessage(const QString &fileName, const QQmlJS::Diagnostic return message; } +void Error::appendDiagnostics(const QString &inputFileName, const QList &diagnostics) +{ + for (const QQmlJS::DiagnosticMessage &parseError: diagnostics) { + if (!message.isEmpty()) + message += QLatin1Char('\n'); + message += diagnosticErrorMessage(inputFileName, parseError); + } +} + // Ensure that ListElement objects keep all property assignments in their string form static void annotateListElements(QmlIR::Document *document) { @@ -185,11 +197,7 @@ static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFuncti { QmlIR::IRBuilder irBuilder(illegalNames); if (!irBuilder.generateFromQml(sourceCode, inputFileName, &irDocument)) { - for (const QQmlJS::DiagnosticMessage &parseError: qAsConst(irBuilder.errors)) { - if (!error->message.isEmpty()) - error->message += QLatin1Char('\n'); - error->message += diagnosticErrorMessage(inputFileName, parseError); - } + error->appendDiagnostics(inputFileName, irBuilder.errors); return false; } } @@ -213,11 +221,7 @@ static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFuncti const QVector runtimeFunctionIndices = v4CodeGen.generateJSCodeForFunctionsAndBindings(functionsToCompile); QList jsErrors = v4CodeGen.errors(); if (!jsErrors.isEmpty()) { - for (const QQmlJS::DiagnosticMessage &e: qAsConst(jsErrors)) { - if (!error->message.isEmpty()) - error->message += QLatin1Char('\n'); - error->message += diagnosticErrorMessage(inputFileName, e); - } + error->appendDiagnostics(inputFileName, jsErrors); return false; } @@ -247,7 +251,8 @@ static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFuncti static bool compileJSFile(const QString &inputFileName, const QString &inputFileUrl, SaveFunction saveFunction, Error *error) { - QmlIR::Document irDocument(/*debugMode*/false); + QQmlRefPointer unit; + QScopedPointer unitDataToFree; QString sourceCode; { @@ -263,79 +268,79 @@ static bool compileJSFile(const QString &inputFileName, const QString &inputFile } } - QQmlJS::Engine *engine = &irDocument.jsParserEngine; - QmlIR::ScriptDirectivesCollector directivesCollector(&irDocument); - QQmlJS::Directives *oldDirs = engine->directives(); - engine->setDirectives(&directivesCollector); + const bool isModule = inputFileName.endsWith(QLatin1String(".mjs")); + if (isModule) { + QList diagnostics; + // Precompiled files are relocatable and the final location will be set when loading. + QString url; + unit = QV4::ExecutionEngine::compileModule(/*debugMode*/false, url, sourceCode, QDateTime(), &diagnostics); + error->appendDiagnostics(inputFileName, diagnostics); + if (!unit) + return false; + } else { + QmlIR::Document irDocument(/*debugMode*/false); - QQmlJS::AST::Program *program = nullptr; + QQmlJS::Engine *engine = &irDocument.jsParserEngine; + QmlIR::ScriptDirectivesCollector directivesCollector(&irDocument); + QQmlJS::Directives *oldDirs = engine->directives(); + engine->setDirectives(&directivesCollector); + auto directivesGuard = qScopeGuard([engine, oldDirs]{ + engine->setDirectives(oldDirs); + }); - { - QQmlJS::Lexer lexer(engine); - lexer.setCode(sourceCode, /*line*/1, /*parseAsBinding*/false); - QQmlJS::Parser parser(engine); + QQmlJS::AST::Program *program = nullptr; - bool parsed = parser.parseProgram(); + { + QQmlJS::Lexer lexer(engine); + lexer.setCode(sourceCode, /*line*/1, /*parseAsBinding*/false); + QQmlJS::Parser parser(engine); - for (const QQmlJS::DiagnosticMessage &parseError: parser.diagnosticMessages()) { - if (!error->message.isEmpty()) - error->message += QLatin1Char('\n'); - error->message += diagnosticErrorMessage(inputFileName, parseError); - } + bool parsed = parser.parseProgram(); - if (!parsed) { - engine->setDirectives(oldDirs); - return false; - } + error->appendDiagnostics(inputFileName, parser.diagnosticMessages()); - program = QQmlJS::AST::cast(parser.rootNode()); - if (!program) { - lexer.setCode(QStringLiteral("undefined;"), 1, false); - parsed = parser.parseProgram(); - Q_ASSERT(parsed); - program = QQmlJS::AST::cast(parser.rootNode()); - Q_ASSERT(program); - } - } + if (!parsed) + return false; - { - QmlIR::JSCodeGen v4CodeGen(irDocument.code, &irDocument.jsGenerator, - &irDocument.jsModule, &irDocument.jsParserEngine, - irDocument.program, /*import cache*/nullptr, - &irDocument.jsGenerator.stringTable, illegalNames); - v4CodeGen.setUseFastLookups(false); // Disable lookups in non-standalone (aka QML) mode - v4CodeGen.generateFromProgram(inputFileName, inputFileUrl, sourceCode, program, - &irDocument.jsModule, QV4::Compiler::ContextType::Global); - QList jsErrors = v4CodeGen.errors(); - if (!jsErrors.isEmpty()) { - for (const QQmlJS::DiagnosticMessage &e: qAsConst(jsErrors)) { - if (!error->message.isEmpty()) - error->message += QLatin1Char('\n'); - error->message += diagnosticErrorMessage(inputFileName, e); + program = QQmlJS::AST::cast(parser.rootNode()); + if (!program) { + lexer.setCode(QStringLiteral("undefined;"), 1, false); + parsed = parser.parseProgram(); + Q_ASSERT(parsed); + program = QQmlJS::AST::cast(parser.rootNode()); + Q_ASSERT(program); } - engine->setDirectives(oldDirs); - return false; } - // Precompiled files are relocatable and the final location will be set when loading. - irDocument.jsModule.fileName.clear(); - irDocument.jsModule.finalUrl.clear(); - - irDocument.javaScriptCompilationUnit = v4CodeGen.generateCompilationUnit(/*generate unit*/false); - QmlIR::QmlUnitGenerator generator; - generator.generate(irDocument); - QV4::CompiledData::Unit *unit = const_cast(irDocument.javaScriptCompilationUnit->data); - unit->flags |= QV4::CompiledData::Unit::StaticData; + { + QmlIR::JSCodeGen v4CodeGen(irDocument.code, &irDocument.jsGenerator, + &irDocument.jsModule, &irDocument.jsParserEngine, + irDocument.program, /*import cache*/nullptr, + &irDocument.jsGenerator.stringTable, illegalNames); + v4CodeGen.setUseFastLookups(false); // Disable lookups in non-standalone (aka QML) mode + v4CodeGen.generateFromProgram(inputFileName, inputFileUrl, sourceCode, program, + &irDocument.jsModule, QV4::Compiler::ContextType::Global); + QList jsErrors = v4CodeGen.errors(); + if (!jsErrors.isEmpty()) { + error->appendDiagnostics(inputFileName, jsErrors); + return false; + } - if (!saveFunction(irDocument.javaScriptCompilationUnit, &error->message)) { - engine->setDirectives(oldDirs); - return false; + // Precompiled files are relocatable and the final location will be set when loading. + irDocument.jsModule.fileName.clear(); + irDocument.jsModule.finalUrl.clear(); + + irDocument.javaScriptCompilationUnit = v4CodeGen.generateCompilationUnit(/*generate unit*/false); + QmlIR::QmlUnitGenerator generator; + generator.generate(irDocument); + QV4::CompiledData::Unit *unitData = const_cast(irDocument.javaScriptCompilationUnit->data); + unitData->flags |= QV4::CompiledData::Unit::StaticData; + unitDataToFree.reset(unitData); + unit = irDocument.javaScriptCompilationUnit; } - - free(unit); } - engine->setDirectives(oldDirs); - return true; + + return saveFunction(unit, &error->message); } static bool saveUnitAsCpp(const QString &inputFileName, const QString &outputFileName, @@ -546,7 +551,7 @@ int main(int argc, char **argv) error.augment(QLatin1String("Error compiling qml file: ")).print(); return EXIT_FAILURE; } - } else if (inputFile.endsWith(QLatin1String(".js"))) { + } else if (inputFile.endsWith(QLatin1String(".js")) || inputFile.endsWith(QLatin1String(".mjs"))) { Error error; if (!compileJSFile(inputFile, inputFileUrl, saveFunction, &error)) { error.augment(QLatin1String("Error compiling js file: ")).print(); diff --git a/tools/qmlcachegen/qtquickcompiler.prf b/tools/qmlcachegen/qtquickcompiler.prf index d05908560d..7d8a857847 100644 --- a/tools/qmlcachegen/qtquickcompiler.prf +++ b/tools/qmlcachegen/qtquickcompiler.prf @@ -35,7 +35,7 @@ for(res, RESOURCES) { absRes = $$absolute_path($$res, $$_PRO_FILE_PWD_) rccContents = $$system($$QMAKE_RCC_DEP -list $$system_quote($$absRes),lines) - contains(rccContents,.*\\.js$)|contains(rccContents,.*\\.qml$) { + contains(rccContents,.*\\.js$)|contains(rccContents,.*\\.qml$)|contains(rccContents,.*\\.mjs$) { new_resource = $$qmlCacheResourceFileOutputName($$res) mkpath($$dirname(new_resource)) remaining_files = $$system($$QML_CACHEGEN_FILTER -filter-resource-file -o $$system_quote($$new_resource) $$system_quote($$absRes),lines) @@ -49,7 +49,7 @@ for(res, RESOURCES) { QMLCACHE_RESOURCE_FILES += $$absRes for(candidate, rccContents) { - contains(candidate,.*\\.js$)|contains(candidate,.*\\.qml$) { + contains(candidate,.*\\.js$)|contains(candidate,.*\\.qml$)|contains(candidate,.*\\.mjs$) { QMLCACHE_FILES += $$candidate } } @@ -70,6 +70,7 @@ defineReplace(qmlCacheOutputName) { name = $$relative_path($$name, $$_PRO_FILE_PWD_) name = $$replace(name, \\.qml$, _qml) name = $$replace(name, \\.js$, _js) + name = $$replace(name, \\.mjs$, _mjs) name = $$replace(name,/,_) name = $$QMLCACHE_DIR/$${name} return($${name}) diff --git a/tools/qmlcachegen/resourcefilemapper.cpp b/tools/qmlcachegen/resourcefilemapper.cpp index c2fd057541..6a00b39f2e 100644 --- a/tools/qmlcachegen/resourcefilemapper.cpp +++ b/tools/qmlcachegen/resourcefilemapper.cpp @@ -67,7 +67,7 @@ QStringList ResourceFileMapper::qmlCompilerFiles() const it != end; ++it) { const QString &qrcPath = it.key(); const QString suffix = QFileInfo(qrcPath).suffix(); - if (suffix != QStringLiteral("qml") && suffix != QStringLiteral("js")) + if (suffix != QStringLiteral("qml") && suffix != QStringLiteral("js") && suffix != QStringLiteral("mjs")) continue; files << qrcPath; } diff --git a/tools/qmlcachegen/resourcefilter.cpp b/tools/qmlcachegen/resourcefilter.cpp index 196dbd4a75..3ad6e9ca0d 100644 --- a/tools/qmlcachegen/resourcefilter.cpp +++ b/tools/qmlcachegen/resourcefilter.cpp @@ -139,7 +139,9 @@ int filterResourceFile(const QString &input, const QString &output) if (currentFileName.isEmpty()) continue; - if (!currentFileName.endsWith(QStringLiteral(".qml")) && !currentFileName.endsWith(QStringLiteral(".js"))) { + if (!currentFileName.endsWith(QStringLiteral(".qml")) + && !currentFileName.endsWith(QStringLiteral(".js")) + && !currentFileName.endsWith(QStringLiteral(".mjs"))) { writer.writeStartElement(QStringLiteral("file")); if (!fileAttributes.hasAttribute(QStringLiteral("alias"))) -- cgit v1.2.3