diff options
| author | Ulf Hermann <ulf.hermann@qt.io> | 2021-11-18 14:26:29 +0100 |
|---|---|---|
| committer | Ulf Hermann <ulf.hermann@qt.io> | 2021-11-29 23:12:45 +0100 |
| commit | e551331f380696ddae511447908b7536761babe0 (patch) | |
| tree | 2493d3023d9a00a0ea5347e575b2519976b770c5 /src/qmlcompiler/qqmljscompiler.cpp | |
| parent | adc490936b66873b072835b315c4d0741230b8b2 (diff) | |
| download | qtdeclarative-e551331f380696ddae511447908b7536761babe0.tar.gz | |
Add a default implementation for QQmlJSAotCompiler
The default AOT compiler compiles QML code in indirect, dynamic mode. It
uses the logger's Log_Compiler category to determine the verbosity of
its output. In addition you can use the qt.qml.compiler.aot category for
even more verbosity. In preparation for using QQmlJSAotCompiler with
qmlcachegen, the default level of that category is increased to
QtFatalMsg. The highest level we actually output is QtDebugMsg, so it
doesn't make a difference yet.
If the logger's Log_Compiler category is set to produce errors, it will
qFatal() on "pragma Strict" violations.
Change-Id: Ieb74bfa7cd51cfa8616792ab467c32f6ba0e0702
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qmlcompiler/qqmljscompiler.cpp')
| -rw-r--r-- | src/qmlcompiler/qqmljscompiler.cpp | 186 |
1 files changed, 183 insertions, 3 deletions
diff --git a/src/qmlcompiler/qqmljscompiler.cpp b/src/qmlcompiler/qqmljscompiler.cpp index 73faaaa6fc..f35351b357 100644 --- a/src/qmlcompiler/qqmljscompiler.cpp +++ b/src/qmlcompiler/qqmljscompiler.cpp @@ -29,18 +29,25 @@ #include "qqmljscompiler_p.h" #include <private/qqmlirbuilder_p.h> +#include <private/qqmljscodegenerator_p.h> +#include <private/qqmljsfunctioninitializer_p.h> +#include <private/qqmljsimportvisitor_p.h> #include <private/qqmljslexer_p.h> -#include <private/qqmljsparser_p.h> #include <private/qqmljsloadergenerator_p.h> +#include <private/qqmljsparser_p.h> +#include <private/qqmljsshadowcheck_p.h> +#include <private/qqmljsstoragegeneralizer_p.h> +#include <private/qqmljstypepropagator_p.h> #include <QtCore/qfile.h> +#include <QtCore/qfileinfo.h> #include <QtCore/qloggingcategory.h> #include <limits> QT_BEGIN_NAMESPACE -Q_LOGGING_CATEGORY(lcAotCompiler, "qt.qml.compiler.aot", QtWarningMsg); +Q_LOGGING_CATEGORY(lcAotCompiler, "qt.qml.compiler.aot", QtFatalMsg); static const int FileScopeCodeIndex = -1; @@ -330,7 +337,7 @@ bool qCompileQmlFile(QmlIR::Document &irDocument, const QString &inputFileName, qCDebug(lcAotCompiler) << "Compilation failed:" << diagnosticErrorMessage(inputFileName, *error); } else if (auto *func = std::get_if<QQmlJSAotFunction>(&result)) { - qCInfo(lcAotCompiler) << "Generated code:" << func->code; + qCDebug(lcAotCompiler) << "Generated code:" << func->code; aotFunctionsByIndex[runtimeFunctionIndices[bindingOrFunction.index()]] = *func; } }); @@ -601,4 +608,177 @@ bool qSaveQmlJSUnitAsCpp(const QString &inputFileName, const QString &outputFile return true; } +QQmlJSAotCompiler::QQmlJSAotCompiler( + QQmlJSImporter *importer, const QString &resourcePath, const QStringList &qmltypesFiles, + QQmlJSLogger *logger) + : m_typeResolver(importer) + , m_resourcePath(resourcePath) + , m_qmltypesFiles(qmltypesFiles) + , m_importer(importer) + , m_logger(logger) +{ +} + +void QQmlJSAotCompiler::setDocument( + const QmlIR::JSCodeGen *codegen, const QmlIR::Document *irDocument) +{ + Q_UNUSED(codegen); + m_document = irDocument; + const QFileInfo resourcePathInfo(m_resourcePath); + m_logger->setFileName(resourcePathInfo.fileName()); + m_logger->setCode(irDocument->code); + m_unitGenerator = &irDocument->jsGenerator; + m_entireSourceCodeLines = irDocument->code.split(u'\n'); + QQmlJSImportVisitor visitor(m_importer, m_logger, + resourcePathInfo.canonicalPath() + u'/', + m_qmltypesFiles); + m_typeResolver.init(&visitor, irDocument->program); +} + +void QQmlJSAotCompiler::setScope(const QmlIR::Object *object, const QmlIR::Object *scope) +{ + m_currentObject = object; + m_currentScope = scope; +} + +static bool isStrict(const QmlIR::Document *doc) +{ + for (const QmlIR::Pragma *pragma : doc->pragmas) { + if (pragma->type == QmlIR::Pragma::Strict) + return true; + } + return false; +} + +QQmlJS::DiagnosticMessage QQmlJSAotCompiler::diagnose( + const QString &message, QtMsgType type, const QQmlJS::SourceLocation &location) const +{ + if (isStrict(m_document) + && (type == QtWarningMsg || type == QtCriticalMsg || type == QtFatalMsg) + && m_logger->isCategoryError(Log_Compiler)) { + qFatal("%s:%d: (strict mode) %s", + qPrintable(QFileInfo(m_resourcePath).fileName()), + location.startLine, qPrintable(message)); + } + + switch (type) { + case QtDebugMsg: + case QtInfoMsg: + m_logger->logInfo(message, Log_Compiler, location); + break; + case QtWarningMsg: + m_logger->logWarning(message, Log_Compiler, location); + break; + case QtCriticalMsg: + case QtFatalMsg: + m_logger->logCritical(message, Log_Compiler, location); + break; + } + + return QQmlJS::DiagnosticMessage { + message, + type, + location + }; +} + +std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> QQmlJSAotCompiler::compileBinding( + const QV4::Compiler::Context *context, const QmlIR::Binding &irBinding) +{ + QQmlJSFunctionInitializer initializer(&m_typeResolver, m_currentObject, m_currentScope); + QQmlJS::DiagnosticMessage error; + const QString name = m_document->stringAt(irBinding.propertyNameIndex); + QQmlJSCompilePass::Function function = initializer.run(context, name, irBinding, &error); + const QQmlJSAotFunction aotFunction = doCompile(context, &function, &error); + + if (error.isValid()) { + // If it's a signal and the function just returns a closure, it's harmless. + // Otherwise promote the message to warning level. + return diagnose(error.message, + (function.isSignalHandler && error.type == QtDebugMsg) + ? QtDebugMsg + : QtWarningMsg, + error.loc); + } + + qCDebug(lcAotCompiler()) << "includes:" << aotFunction.includes; + qCDebug(lcAotCompiler()) << "binding code:" << aotFunction.code; + return aotFunction; +} + +std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> QQmlJSAotCompiler::compileFunction( + const QV4::Compiler::Context *context, const QmlIR::Function &irFunction) +{ + QQmlJSFunctionInitializer initializer(&m_typeResolver, m_currentObject, m_currentScope); + QQmlJS::DiagnosticMessage error; + const QString name = m_document->stringAt(irFunction.nameIndex); + QQmlJSCompilePass::Function function = initializer.run(context, name, irFunction, &error); + const QQmlJSAotFunction aotFunction = doCompile(context, &function, &error); + + if (error.isValid()) + return diagnose(error.message, QtWarningMsg, error.loc); + + qCDebug(lcAotCompiler()) << "includes:" << aotFunction.includes; + qCDebug(lcAotCompiler()) << "binding code:" << aotFunction.code; + return aotFunction; +} + +QQmlJSAotFunction QQmlJSAotCompiler::globalCode() const +{ + QQmlJSAotFunction global; + global.includes = { + u"QtQml/qjsengine.h"_qs, + u"QtQml/qjsprimitivevalue.h"_qs, + u"QtQml/qjsvalue.h"_qs, + u"QtQml/qqmlcomponent.h"_qs, + u"QtQml/qqmlcontext.h"_qs, + u"QtQml/qqmlengine.h"_qs, + + u"QtCore/qdatetime.h"_qs, + u"QtCore/qobject.h"_qs, + u"QtCore/qstring.h"_qs, + u"QtCore/qstringlist.h"_qs, + u"QtCore/qurl.h"_qs, + u"QtCore/qvariant.h"_qs, + + u"type_traits"_qs + }; + return global; +} + + +QQmlJSAotFunction QQmlJSAotCompiler::doCompile( + const QV4::Compiler::Context *context, QQmlJSCompilePass::Function *function, + QQmlJS::DiagnosticMessage *error) +{ + const auto compileError = [&]() { + Q_ASSERT(error->isValid()); + error->type = context->returnsClosure ? QtDebugMsg : QtWarningMsg; + return QQmlJSAotFunction(); + }; + + QQmlJSTypePropagator propagator(m_unitGenerator, &m_typeResolver, m_logger); + auto typePropagationResult = propagator.run(function, error); + if (error->isValid()) + return compileError(); + + QQmlJSShadowCheck shadowCheck(m_unitGenerator, &m_typeResolver, m_logger); + shadowCheck.run(&typePropagationResult, function, error); + if (error->isValid()) + return compileError(); + + // Generalize all arguments, registers, and the return type. + QQmlJSStorageGeneralizer generalizer( + m_unitGenerator, &m_typeResolver, m_logger); + typePropagationResult = generalizer.run(typePropagationResult, function, error); + if (error->isValid()) + return compileError(); + + QQmlJSCodeGenerator codegen( + context, m_unitGenerator, &m_typeResolver, m_logger, + m_entireSourceCodeLines); + QQmlJSAotFunction result = codegen.run(function, &typePropagationResult, error); + return error->isValid() ? compileError() : result; +} + QT_END_NAMESPACE |
