diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2024-04-19 11:19:01 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2024-04-24 16:49:06 +0200 |
commit | b7f4779ccbf39f063ff38f72aecaeaa8b58bc759 (patch) | |
tree | 550d7c1d10edec33a31876bc414690f926fbca02 /src | |
parent | 5fdd8793c2adc7c2c93f5d02ef33044dc784afa4 (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.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmlprivate.h | 2 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljscodegenerator.cpp | 118 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljscodegenerator_p.h | 2 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljscompiler.cpp | 28 |
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(); |