diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2021-01-07 16:07:00 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2021-01-11 22:59:34 +0100 |
commit | 9694e0631da9ae94dab4229091f382528700af90 (patch) | |
tree | bd2462d87e497829310df0bf6e2b18e5ea5161cb /src | |
parent | 05b5a0896da2c12d50898abb2bf3dc5c5f158a16 (diff) |
Pass a more comprehensive context to AOT-compiled functions
We need the compilation unit, and a way to retrieve JavaScript metatypes
from it. Also, prepare for cases where we only have a QJSEngine, not a
QQmlEngine, and pass the scope object as part of the AOT context.
Change-Id: Ica81e92c99f3c9b6baffd04db1e0e91603fd2ac7
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 9 | ||||
-rw-r--r-- | src/qml/qml/qqml.cpp | 7 | ||||
-rw-r--r-- | src/qml/qml/qqmlprivate.h | 12 | ||||
-rw-r--r-- | src/qml/qml/qqmlpropertybinding.cpp | 11 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljscompiler.cpp | 41 |
5 files changed, 55 insertions, 25 deletions
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 9fefa2a38c..bea301c6e3 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -489,9 +489,12 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine) Scope scope(engine); Scoped<QmlContext> qmlContext(scope, engine->qmlContext()); - function->aotFunction->functionPtr( - qmlContext->qmlContext()->asQQmlContext(), qmlContext->qmlScope(), - returnValue, argumentPtrs); + QQmlPrivate::AOTCompiledContext aotContext; + aotContext.qmlContext = qmlContext ? qmlContext->qmlContext()->asQQmlContext() : nullptr; + aotContext.qmlScopeObject = qmlContext ? qmlContext->qmlScope() : nullptr; + aotContext.engine = engine->jsEngine(); + aotContext.compilationUnit = function->executableCompilationUnit(); + function->aotFunction->functionPtr(&aotContext, returnValue, argumentPtrs); if (returnValue) { result = engine->metaTypeToJS(returnType.id(), returnValue); diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index 40e629284b..9e71c968b8 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -41,6 +41,7 @@ #include <QtQml/qqmlprivate.h> +#include <private/qjsvalue_p.h> #include <private/qqmlengine_p.h> #include <private/qqmlmetatype_p.h> #include <private/qqmlmetatypedata_p.h> @@ -561,4 +562,10 @@ namespace QQmlPrivate { } } +QJSValue QQmlPrivate::AOTCompiledContext::jsMetaType(int index) const +{ + return QJSValuePrivate::fromReturnedValue( + compilationUnit->runtimeClasses[index]->asReturnedValue()); +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index a2cd9452ac..ce83b33eaa 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -589,12 +589,20 @@ namespace QQmlPrivate QVector<int> *qmlTypeIds; }; + struct AOTCompiledContext { + QQmlContext *qmlContext; + QObject *qmlScopeObject; + QJSEngine *engine; + QV4::CompiledData::CompilationUnit *compilationUnit; + + QJSValue Q_QML_EXPORT jsMetaType(int index) const; + }; + struct AOTCompiledFunction { int index; QMetaType returnType; QList<QMetaType> argumentTypes; - void (*functionPtr)(QQmlContext *context, QObject *scopeObject, void *resultPtr, - void **arguments); + void (*functionPtr)(const AOTCompiledContext *context, void *resultPtr, void **arguments); }; struct CachedQmlUnit { diff --git a/src/qml/qml/qqmlpropertybinding.cpp b/src/qml/qml/qqmlpropertybinding.cpp index 235d9f578f..eaf3524487 100644 --- a/src/qml/qml/qqmlpropertybinding.cpp +++ b/src/qml/qml/qqmlpropertybinding.cpp @@ -52,10 +52,15 @@ QUntypedPropertyBinding QQmlPropertyBinding::create(const QQmlPropertyData *pd, aotFunction, unit = QQmlRefPointer<QV4::ExecutableCompilationUnit>(function->executableCompilationUnit()), scopeObject = QPointer<QObject>(obj), - context = ctxt + context = ctxt, + engine = scope->engine() ](const QMetaType &, void *dataPtr) -> bool { - Q_UNUSED(unit); // to keep refcount - aotFunction->functionPtr(context->asQQmlContext(), scopeObject.data(), dataPtr, nullptr); + QQmlPrivate::AOTCompiledContext aotContext; + aotContext.qmlContext = context->asQQmlContext(); + aotContext.qmlScopeObject = scopeObject.data(); + aotContext.engine = engine->jsEngine(); + aotContext.compilationUnit = unit.data(); + aotFunction->functionPtr(&aotContext, 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 bf4dc55b6d..549ee9116b 100644 --- a/src/qmlcompiler/qqmljscompiler.cpp +++ b/src/qmlcompiler/qqmljscompiler.cpp @@ -377,6 +377,27 @@ bool qCompileJSFile(const QString &inputFileName, const QString &inputFileUrl, Q return saveFunction(QV4::CompiledData::SaveableUnitPointer(unit.data), empty, &error->message); } +static const char *wrapCallCode = R"( +template <typename Binding> +void wrapCall(const QQmlPrivate::AOTCompiledContext *context, 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(context, argumentsPtr); + } else { + new (dataPtr) return_type(binding(context, argumentsPtr)); + } +} +)"; + +static const char *funcHeaderCode = R"( + [](const QQmlPrivate::AOTCompiledContext *context, void *dataPtr, void **argumentsPtr) { + wrapCall(context, dataPtr, argumentsPtr, [](const QQmlPrivate::AOTCompiledContext *context, void **argumentsPtr) { +Q_UNUSED(context); +Q_UNUSED(argumentsPtr); +)"; + bool qSaveQmlJSUnitAsCpp(const QString &inputFileName, const QString &outputFileName, const QV4::CompiledData::SaveableUnitPointer &unit, const QQmlJSAotFunctionMap &aotFunctions, QString *errorString) { #if QT_CONFIG(temporaryfile) @@ -463,22 +484,8 @@ bool qSaveQmlJSUnitAsCpp(const QString &inputFileName, const QString &outputFile // FileScopeCodeIndex is always there, but it may be the only one. 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, void **argumentsPtr, Binding &&binding) { - using return_type = std::invoke_result_t<Binding, QQmlContext*, QObject*, void **>; - if constexpr (std::is_same_v<return_type, void>) { - Q_UNUSED(dataPtr); - binding(context, scopeObject, argumentsPtr); - } else { - new (dataPtr) return_type(binding(context, scopeObject, argumentsPtr)); - } - } )"); - - writeStr("extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[] = {"); - - QString header = QStringLiteral("[](QQmlContext *context, QObject *scopeObject, void *dataPtr, void **argumentsPtr) {\n"); - header += QStringLiteral("wrapCall(context, scopeObject, dataPtr, argumentsPtr, [](QQmlContext *context, QObject *scopeObject, void **argumentsPtr) {"); - header += QStringLiteral("Q_UNUSED(context); Q_UNUSED(scopeObject); Q_UNUSED(argumentsPtr);\n"); + writeStr(wrapCallCode); + writeStr("extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[] = {\n"); QString footer = QStringLiteral("});}\n"); @@ -489,7 +496,7 @@ bool qSaveQmlJSUnitAsCpp(const QString &inputFileName, const QString &outputFile if (func.key() == FileScopeCodeIndex) continue; - QString function = header + func.value().code + footer; + QString function = QString::fromUtf8(funcHeaderCode) + func.value().code + footer; QString argumentTypes = func.value().argumentTypes.join( QStringLiteral(">(), QMetaType::fromType<")); |