summaryrefslogtreecommitdiff
path: root/src/qmlcompiler/qqmljscompiler.cpp
diff options
context:
space:
mode:
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