summaryrefslogtreecommitdiff
path: root/src/qmlcompiler/qqmljscompiler.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2021-11-18 14:26:29 +0100
committerUlf Hermann <ulf.hermann@qt.io>2021-11-29 23:12:45 +0100
commite551331f380696ddae511447908b7536761babe0 (patch)
tree2493d3023d9a00a0ea5347e575b2519976b770c5 /src/qmlcompiler/qqmljscompiler.cpp
parentadc490936b66873b072835b315c4d0741230b8b2 (diff)
downloadqtdeclarative-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.cpp186
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