diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2020-11-17 13:41:36 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2020-11-20 10:36:06 +0100 |
commit | 744b277733a03e0fb5a0c25640be0f73cf3eb6c9 (patch) | |
tree | e4faf101e397dca324349223b330f92f708b673f /src | |
parent | fe2d3a839775f64f7aad8610ea241c8760be4646 (diff) |
V4: Allow passing arguments to AOT-compiled functions
Change-Id: I2340f4413ae9a44c71000e840a79e904b6a0fec9
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 37 | ||||
-rw-r--r-- | src/qml/qml/qqmlprivate.h | 4 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertybinding.cpp | 2 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljscompiler.cpp | 35 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljscompiler_p.h | 1 |
5 files changed, 52 insertions, 27 deletions
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 55c7759716..ebc018a595 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -42,6 +42,7 @@ #include <QtCore/qjsondocument.h> #include <QtCore/qjsonobject.h> +#include <private/qv4alloca_p.h> #include <private/qv4instr_moth_p.h> #include <private/qv4value_p.h> #include <private/qv4debugging_p.h> @@ -460,21 +461,33 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine) if (function->jittedCode != nullptr && debugger == nullptr) { result = function->jittedCode(frame, engine); } else if (function->aotFunction) { + const qsizetype numFunctionArguments = function->aotFunction->argumentTypes.size(); + Q_ALLOCA_VAR(void *, argumentPtrs, numFunctionArguments * sizeof(void *)); + + for (qsizetype i = 0; i < numFunctionArguments; ++i) { + const QMetaType argumentType = function->aotFunction->argumentTypes[i]; + Q_ALLOCA_VAR(void, argument, argumentType.sizeOf()); + if (i < frame->originalArgumentsCount) + engine->metaTypeFromJS(frame->originalArguments[i], argumentType.id(), argument); + else + argumentType.construct(argument); + argumentPtrs[i] = argument; + } + + const QMetaType returnType = function->aotFunction->returnType; + Q_ALLOCA_VAR(void, returnValue, returnType.sizeOf()); + Scope scope(engine); Scoped<QmlContext> qmlContext(scope, engine->qmlContext()); + function->aotFunction->functionPtr( + qmlContext->qmlContext()->asQQmlContext(), qmlContext->qmlScope(), + returnValue, const_cast<const void **>(argumentPtrs)); // We're adding const here - QVariant resultVariant; - if (function->aotFunction->returnType.id() == QMetaType::QVariant) { - function->aotFunction->functionPtr( - qmlContext->qmlContext()->asQQmlContext(), qmlContext->qmlScope(), - &resultVariant); - } else { - resultVariant = QVariant(function->aotFunction->returnType, nullptr); - function->aotFunction->functionPtr( - qmlContext->qmlContext()->asQQmlContext(), qmlContext->qmlScope(), - resultVariant.data()); - } - result = engine->fromVariant(resultVariant); + result = engine->metaTypeToJS(returnType.id(), returnValue); + + returnType.destruct(returnValue); + for (qsizetype i = 0; i < numFunctionArguments; ++i) + function->aotFunction->argumentTypes[i].destruct(argumentPtrs[i]); } else { // interpreter result = interpret(frame, engine, function->codeData); diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index feee3f8686..654ae35c57 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -592,7 +592,9 @@ namespace QQmlPrivate struct AOTCompiledFunction { int index; QMetaType returnType; - void (*functionPtr)(QQmlContext *context, QObject *scopeObject, void *resultPtr); + QList<QMetaType> argumentTypes; + void (*functionPtr)(QQmlContext *context, QObject *scopeObject, void *resultPtr, + const void **arguments); }; struct CachedQmlUnit { diff --git a/src/qml/qml/qqmlpropertybinding.cpp b/src/qml/qml/qqmlpropertybinding.cpp index 656e2788c4..e950de5d48 100644 --- a/src/qml/qml/qqmlpropertybinding.cpp +++ b/src/qml/qml/qqmlpropertybinding.cpp @@ -55,7 +55,7 @@ QUntypedPropertyBinding QQmlPropertyBinding::create(const QQmlPropertyData *pd, context = ctxt ](const QMetaType &, void *dataPtr) -> bool { Q_UNUSED(unit); // to keep refcount - aotFunction->functionPtr(context->asQQmlContext(), scopeObject.data(), dataPtr); + aotFunction->functionPtr(context->asQQmlContext(), scopeObject.data(), dataPtr, nullptr); // ### Fixme: The aotFunction should do the check whether old and new value are the same and // return false in that case return true; diff --git a/src/qmlcompiler/qqmljscompiler.cpp b/src/qmlcompiler/qqmljscompiler.cpp index 7d780b21a1..d69eacaa29 100644 --- a/src/qmlcompiler/qqmljscompiler.cpp +++ b/src/qmlcompiler/qqmljscompiler.cpp @@ -451,25 +451,24 @@ bool qSaveQmlJSUnitAsCpp(const QString &inputFileName, const QString &outputFile writeStr(aotFunctions[FileScopeCodeIndex].code.toUtf8().constData()); if (aotFunctions.size() <= 1) { // FileScopeCodeIndex is always there, but it may be the only one. - writeStr("extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[] = { { 0, QMetaType::fromType<void>(), nullptr } };"); + writeStr("extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[] = { { 0, QMetaType::fromType<void>(), {}, nullptr } };"); } else { writeStr(R"(template <typename Binding> - void wrapCall(QQmlContext *context, QObject *scopeObject, void *dataPtr, Binding &&binding) { - using return_type = std::invoke_result_t<Binding, QQmlContext*, QObject*>; + void wrapCall(QQmlContext *context, QObject *scopeObject, void *dataPtr, const void **argumentsPtr, Binding &&binding) { + using return_type = std::invoke_result_t<Binding, QQmlContext*, QObject*, const void **>; if constexpr (std::is_same_v<return_type, void>) { - Q_UNUSED(dataPtr); - binding(context, scopeObject); + Q_UNUSED(dataPtr); + binding(context, scopeObject, argumentsPtr); } else { - auto result = binding(context, scopeObject); - *reinterpret_cast<return_type *>(dataPtr) = std::move(result); + new (dataPtr) return_type(binding(context, scopeObject, argumentsPtr)); } } )"); writeStr("extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[] = {"); - QString header = QStringLiteral("[](QQmlContext *context, QObject *scopeObject, void *dataPtr) {\n"); - header += QStringLiteral("wrapCall(context, scopeObject, dataPtr, [](QQmlContext *context, QObject *scopeObject) {"); - header += QStringLiteral("Q_UNUSED(context); Q_UNUSED(scopeObject);\n"); + QString header = QStringLiteral("[](QQmlContext *context, QObject *scopeObject, void *dataPtr, const void **argumentsPtr) {\n"); + header += QStringLiteral("wrapCall(context, scopeObject, dataPtr, argumentsPtr, [](QQmlContext *context, QObject *scopeObject, const void **argumentsPtr) {"); + header += QStringLiteral("Q_UNUSED(context); Q_UNUSED(scopeObject); Q_UNUSED(argumentsPtr);\n"); QString footer = QStringLiteral("});}\n"); @@ -482,13 +481,23 @@ bool qSaveQmlJSUnitAsCpp(const QString &inputFileName, const QString &outputFile QString function = header + func.value().code + footer; - writeStr(QStringLiteral("{ %1, QMetaType::fromType<%2>(), %3 },") - .arg(func.key()).arg(func.value().returnType).arg(function) + QString argumentTypes = func.value().argumentTypes.join( + QStringLiteral(">(), QMetaType::fromType<")); + if (!argumentTypes.isEmpty()) { + argumentTypes = QStringLiteral("QMetaType::fromType<") + + argumentTypes + QStringLiteral(">()"); + } + + writeStr(QStringLiteral("{ %1, QMetaType::fromType<%2>(), { %3 }, %4 },") + .arg(func.key()) + .arg(func.value().returnType) + .arg(argumentTypes) + .arg(function) .toUtf8().constData()); } // Conclude the list with a nullptr - writeStr("{ 0, QMetaType::fromType<void>(), nullptr }"); + writeStr("{ 0, QMetaType::fromType<void>(), {}, nullptr }"); writeStr("};\n"); } diff --git a/src/qmlcompiler/qqmljscompiler_p.h b/src/qmlcompiler/qqmljscompiler_p.h index 1bfb1369c1..9fda257bd7 100644 --- a/src/qmlcompiler/qqmljscompiler_p.h +++ b/src/qmlcompiler/qqmljscompiler_p.h @@ -64,6 +64,7 @@ struct QQmlJSCompileError struct QQmlJSAotFunction { QStringList includes; + QStringList argumentTypes; QString code; QString returnType; }; |