aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2024-04-19 11:19:01 +0200
committerUlf Hermann <ulf.hermann@qt.io>2024-04-24 16:49:06 +0200
commitb7f4779ccbf39f063ff38f72aecaeaa8b58bc759 (patch)
tree550d7c1d10edec33a31876bc414690f926fbca02 /src
parent5fdd8793c2adc7c2c93f5d02ef33044dc784afa4 (diff)
QmlCompiler: Perform return value assignment inside generated code
This is in preparation for using exact types and actually enforcing them. We shouldn't wrap the return value into a QVariant in order to then painstakingly unwrap it again. The generated code can already do the right thing. Task-number: QTBUG-119885 Change-Id: I13e517967ee982be717024a9abb74d5e02a185d6 Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/common/qv4compileddata_p.h2
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp2
-rw-r--r--src/qml/qml/qqmlprivate.h2
-rw-r--r--src/qmlcompiler/qqmljscodegenerator.cpp118
-rw-r--r--src/qmlcompiler/qqmljscodegenerator_p.h2
-rw-r--r--src/qmlcompiler/qqmljscompiler.cpp28
6 files changed, 76 insertions, 78 deletions
diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
index 784e3e5444..caedd8928e 100644
--- a/src/qml/common/qv4compileddata_p.h
+++ b/src/qml/common/qv4compileddata_p.h
@@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE
// Also change the comment behind the number to describe the latest change. This has the added
// benefit that if another patch changes the version too, it will result in a merge conflict, and
// not get removed silently.
-#define QV4_DATA_STRUCTURE_VERSION 0x40 // Switch the "sticky" and "unicode" regexp flags
+#define QV4_DATA_STRUCTURE_VERSION 0x41 // Change signature of AOT compiled functions
class QIODevice;
class QQmlTypeNameCache;
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 696368fa3f..db17a7141c 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -443,7 +443,7 @@ void VME::exec(MetaTypesStackFrame *frame, ExecutionEngine *engine)
aotContext.engine = engine->jsEngine();
aotContext.compilationUnit = function->executableCompilationUnit();
- function->aotCompiledFunction->functionPtr(&aotContext, argv[0], argv + 1);
+ function->aotCompiledFunction->functionPtr(&aotContext, argv);
});
}
diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h
index f5e1feb4f2..25dc36d33d 100644
--- a/src/qml/qml/qqmlprivate.h
+++ b/src/qml/qml/qqmlprivate.h
@@ -743,7 +743,7 @@ namespace QQmlPrivate
qintptr extraData;
QMetaType returnType;
QList<QMetaType> argumentTypes;
- void (*functionPtr)(const AOTCompiledContext *context, void *resultPtr, void **arguments);
+ void (*functionPtr)(const AOTCompiledContext *context, void **argv);
};
#if QT_DEPRECATED_SINCE(6, 6)
diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp
index 0e5fbdea12..65387e3681 100644
--- a/src/qmlcompiler/qqmljscodegenerator.cpp
+++ b/src/qmlcompiler/qqmljscodegenerator.cpp
@@ -209,7 +209,7 @@ QT_WARNING_POP
const QString originalValue
= u"(*static_cast<"_s + castTargetName(original.storedType())
- + u"*>(argumentsPtr["_s + QString::number(argumentIndex) + u"]))"_s;
+ + u"*>(argv["_s + QString::number(argumentIndex + 1) + u"]))"_s;
if (needsConversion)
result.code += conversion(original, argument, originalValue);
@@ -244,55 +244,71 @@ QT_WARNING_POP
return result;
}
-QString QQmlJSCodeGenerator::errorReturnValue()
+void QQmlJSCodeGenerator::generateReturnError()
{
- if (auto ret = m_function->returnType) {
- return ret->accessSemantics() == QQmlJSScope::AccessSemantics::Reference
- ? convertStored(m_typeResolver->nullType(), ret, QString())
- : ret->internalName() + u"()"_s;
- }
- return QString();
+ const auto finalizeReturn = qScopeGuard([this]() { m_body += u"return;\n"_s; });
+
+ m_body += u"aotContext->setReturnValueUndefined();\n"_s;
+ const auto ret = m_function->returnType;
+ if (!ret || m_typeResolver->equals(m_function->returnType, m_typeResolver->voidType()))
+ return;
+
+ const QString value = ret->accessSemantics() == QQmlJSScope::AccessSemantics::Reference
+ ? convertStored(m_typeResolver->nullType(), ret, QString())
+ : ret->internalName() + u"()"_s;
+
+ m_body += u"if (argv[0]) {\n"_s;
+ m_body += u" *static_cast<"_s + m_function->returnType->augmentedInternalName()
+ + u" *>(argv[0]) = "_s + value + u";\n"_s;
+ m_body += u"}\n"_s;
}
void QQmlJSCodeGenerator::generate_Ret()
{
INJECT_TRACE_INFO(generate_Ret);
- if (m_function->returnType) {
- const QString signalUndefined = u"aotContext->setReturnValueUndefined();\n"_s;
- if (!m_state.accumulatorVariableIn.isEmpty()) {
- const QString in = m_state.accumulatorVariableIn;
- if (m_typeResolver->registerIsStoredIn(
- m_state.accumulatorIn(), m_typeResolver->varType())) {
- m_body += u"if (!"_s + in + u".isValid())\n"_s;
- m_body += u" "_s + signalUndefined;
- } else if (m_typeResolver->registerIsStoredIn(
- m_state.accumulatorIn(), m_typeResolver->jsPrimitiveType())) {
- m_body += u"if ("_s + in
- + u".type() == QJSPrimitiveValue::Undefined)\n"_s;
- m_body += u" "_s + signalUndefined;
- } else if (m_typeResolver->registerIsStoredIn(
- m_state.accumulatorIn(), m_typeResolver->jsValueType())) {
- m_body += u"if ("_s + in + u".isUndefined())\n"_s;
- m_body += u" "_s + signalUndefined;
- }
- m_body += u"return "_s
- + convertStored(m_state.accumulatorIn().storedType(), m_function->returnType, in);
- } else {
- if (m_typeResolver->equals(m_state.accumulatorIn().storedType(),
- m_typeResolver->voidType())) {
- m_body += signalUndefined;
- }
- m_body += u"return "_s + convertStored(
- m_state.accumulatorIn().storedType(), m_function->returnType, QString());
+ const auto finalizeReturn = qScopeGuard([this]() {
+ m_body += u"return;\n"_s;
+ m_skipUntilNextLabel = true;
+ resetState();
+ });
+
+ if (!m_function->returnType)
+ return;
+
+ m_body += u"if (argv[0]) {\n"_s;
+
+ const QString signalUndefined = u"aotContext->setReturnValueUndefined();\n"_s;
+ const QString in = m_state.accumulatorVariableIn;
+
+ if (in.isEmpty()) {
+ if (m_typeResolver->equals(m_state.accumulatorIn().storedType(),
+ m_typeResolver->voidType())) {
+ m_body += signalUndefined;
+
}
- } else {
- m_body += u"return"_s;
+ } else if (m_typeResolver->registerIsStoredIn(
+ m_state.accumulatorIn(), m_typeResolver->varType())) {
+ m_body += u" if (!"_s + in + u".isValid())\n"_s;
+ m_body += u" "_s + signalUndefined;
+ } else if (m_typeResolver->registerIsStoredIn(
+ m_state.accumulatorIn(), m_typeResolver->jsPrimitiveType())) {
+ m_body += u" if ("_s + in + u".type() == QJSPrimitiveValue::Undefined)\n"_s;
+ m_body += u" "_s + signalUndefined;
+ } else if (m_typeResolver->registerIsStoredIn(
+ m_state.accumulatorIn(), m_typeResolver->jsValueType())) {
+ m_body += u" if ("_s + in + u".isUndefined())\n"_s;
+ m_body += u" "_s + signalUndefined;
+ }
+
+ if (!m_typeResolver->equals(m_function->returnType, m_typeResolver->voidType())) {
+ m_body += u" *static_cast<"_s + m_function->returnType->augmentedInternalName()
+ +u" *>(argv[0]) = "_s + convertStored(
+ m_state.accumulatorIn().storedType(), m_function->returnType, in)
+ + u";\n"_s;
}
- m_body += u";\n"_s;
- m_skipUntilNextLabel = true;
- resetState();
+ m_body += u"}\n"_s;
}
void QQmlJSCodeGenerator::generate_Debug()
@@ -1208,7 +1224,7 @@ bool QQmlJSCodeGenerator::generateContentPointerCheck(
generateSetInstructionPointer();
m_body += u" aotContext->engine->throwError(QJSValue::TypeError, "_s;
m_body += u"QLatin1String(\"%1\"));\n"_s.arg(processedErrorMessage);
- m_body += u" return "_s + errorReturnValue() + u";\n"_s;
+ generateReturnError();
m_body += u"}\n"_s;
return needsVarContentConversion;
}
@@ -2302,20 +2318,21 @@ void QQmlJSCodeGenerator::generate_Construct(int func, int argc, int argv)
addInclude(u"QtQml/qjslist.h"_s);
const QString error = u" aotContext->engine->throwError(QJSValue::RangeError, "_s
- + u"QLatin1String(\"Invalid array length\"));\n"_s
- + u" return "_s + errorReturnValue() + u";\n"_s;
+ + u"QLatin1String(\"Invalid array length\"));\n"_s;
const QString indexName = registerVariable(argv);
const auto indexType = registerType(argv);
if (!m_typeResolver->isIntegral(indexType)) {
m_body += u"if (!QJSNumberCoercion::isArrayIndex("_s + indexName + u")) {\n"_s
- + error
- + u"}\n"_s;
+ + error;
+ generateReturnError();
+ m_body += u"}\n"_s;
} else if (!m_typeResolver->isUnsignedInteger(
m_typeResolver->containedType(indexType))) {
m_body += u"if ("_s + indexName + u" < 0) {\n"_s
- + error
- + u"}\n"_s;
+ + error;
+ generateReturnError();
+ m_body += u"}\n"_s;
}
m_body += m_state.accumulatorVariableOut + u" = "_s
@@ -2378,7 +2395,7 @@ void QQmlJSCodeGenerator::generate_ThrowException()
+ conversion(m_state.accumulatorIn(), m_typeResolver->globalType(
m_typeResolver->jsValueType()),
m_state.accumulatorVariableIn) + u");\n"_s;
- m_body += u"return "_s + errorReturnValue() + u";\n"_s;
+ generateReturnError();
m_skipUntilNextLabel = true;
resetState();
}
@@ -3282,8 +3299,9 @@ void QQmlJSCodeGenerator::generateSetInstructionPointer()
void QQmlJSCodeGenerator::generateExceptionCheck()
{
- m_body += u"if (aotContext->engine->hasError())\n"_s;
- m_body += u" return "_s + errorReturnValue() + u";\n"_s;
+ m_body += u"if (aotContext->engine->hasError()) {\n"_s;
+ generateReturnError();
+ m_body += u"}\n"_s;
}
void QQmlJSCodeGenerator::generateEqualityOperation(
diff --git a/src/qmlcompiler/qqmljscodegenerator_p.h b/src/qmlcompiler/qqmljscodegenerator_p.h
index 7ed0d08048..33589c13a3 100644
--- a/src/qmlcompiler/qqmljscodegenerator_p.h
+++ b/src/qmlcompiler/qqmljscodegenerator_p.h
@@ -242,7 +242,7 @@ protected:
const QQmlJSRegisterContent &to,
const QString &variable);
- QString errorReturnValue();
+ void generateReturnError();
void reject(const QString &thing);
QString metaTypeFromType(const QQmlJSScope::ConstPtr &type) const;
diff --git a/src/qmlcompiler/qqmljscompiler.cpp b/src/qmlcompiler/qqmljscompiler.cpp
index 2cc32fc63d..cca05380c9 100644
--- a/src/qmlcompiler/qqmljscompiler.cpp
+++ b/src/qmlcompiler/qqmljscompiler.cpp
@@ -460,29 +460,10 @@ bool qCompileJSFile(const QString &inputFileName, const QString &inputFileUrl, Q
QV4::CompiledData::SaveableUnitPointer(unit->unitData()), empty, &error->message);
}
-static const char *wrapCallCode = R"(
-template <typename Binding>
-void wrapCall(const QQmlPrivate::AOTCompiledContext *aotContext, void *dataPtr, void **argumentsPtr, Binding &&binding)
-{
- using return_type = std::invoke_result_t<Binding, const QQmlPrivate::AOTCompiledContext *, void **>;
- if constexpr (std::is_same_v<return_type, void>) {
- Q_UNUSED(dataPtr)
- binding(aotContext, argumentsPtr);
- } else {
- if (dataPtr) {
- *static_cast<return_type *>(dataPtr) = binding(aotContext, argumentsPtr);
- } else {
- binding(aotContext, argumentsPtr);
- }
- }
-}
-)";
-
static const char *funcHeaderCode = R"(
- [](const QQmlPrivate::AOTCompiledContext *context, void *data, void **argv) {
- wrapCall(context, data, argv, [](const QQmlPrivate::AOTCompiledContext *aotContext, void **argumentsPtr) {
+ [](const QQmlPrivate::AOTCompiledContext *aotContext, void **argv) {
Q_UNUSED(aotContext)
-Q_UNUSED(argumentsPtr)
+Q_UNUSED(argv)
)";
bool qSaveQmlJSUnitAsCpp(const QString &inputFileName, const QString &outputFileName, const QV4::CompiledData::SaveableUnitPointer &unit, const QQmlJSAotFunctionMap &aotFunctions, QString *errorString)
@@ -579,13 +560,12 @@ bool qSaveQmlJSUnitAsCpp(const QString &inputFileName, const QString &outputFile
if (aotFunctions.size() <= 1) {
// FileScopeCodeIndex is always there, but it may be the only one.
writeStr("extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[];\n"
- "extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[] = { { 0, QMetaType::fromType<void>(), {}, nullptr } };");
+ "extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[] = { { 0, QMetaType::fromType<void>(), {}, nullptr } };\n");
} else {
- writeStr(wrapCallCode);
writeStr("extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[];\n"
"extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[] = {\n");
- QString footer = QStringLiteral("});}\n");
+ QString footer = QStringLiteral("}\n");
for (QQmlJSAotFunctionMap::ConstIterator func = aotFunctions.constBegin(),
end = aotFunctions.constEnd();