diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2024-04-16 17:03:01 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2024-04-26 12:18:15 +0000 |
commit | 8bf5aae19b77b618f3f7a55a59e87c8a319475a8 (patch) | |
tree | d331328f478ac13593524eaaeb3a874691ccadd2 /src/qml/jsruntime/qv4function.cpp | |
parent | 23fc22e16022e355f2a1aff8705c09b807fbe024 (diff) |
QtQml: Properly enforce signatures of AOT-compiled functions
Pass the metatypes of the contained types rather than the stored types.
[ChangeLog][QtQml][Important Behavior Changes] The AOT compiled code for
type-annotated JavaScript functions does not let you pass or return
values of the wrong type anymore.
Fixes: QTBUG-119885
Change-Id: I685d398c0745d32a999a3abd76c622a2c0d6651f
Reviewed-by: Olivier De Cannière <olivier.decanniere@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4function.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4function.cpp | 74 |
1 files changed, 37 insertions, 37 deletions
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index caba2b1a9a..ae36b563e0 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -61,14 +61,14 @@ ReturnedValue Function::call( switch (kind) { case AotCompiled: return QV4::convertAndCall( - context->engine(), aotCompiledFunction, thisObject, argv, argc, + context->engine(), &aotCompiledFunction, thisObject, argv, argc, [this, context]( QObject *thisObject, void **a, const QMetaType *types, int argc) { call(thisObject, a, types, argc, context); }); case JsTyped: return QV4::coerceAndCall( - context->engine(), jsTypedFunction, compiledFunction, argv, argc, + context->engine(), &jsTypedFunction, compiledFunction, argv, argc, [this, context, thisObject](const Value *argv, int argc) { return doCall(this, thisObject, argv, argc, context); }); @@ -109,10 +109,6 @@ Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit, : FunctionData(engine, unit) , compiledFunction(function) , codeData(function->code()) - , jittedCode(nullptr) - , codeRef(nullptr) - , aotCompiledFunction(aotFunction) - , kind(aotFunction ? AotCompiled : JsUntyped) { Scope scope(engine); Scoped<InternalClass> ic(scope, engine->internalClasses(EngineBase::Class_CallContext)); @@ -123,7 +119,7 @@ Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit, ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable); const CompiledData::Parameter *formalsIndices = compiledFunction->formalsTable(); - bool enforceJsTypes = !aotFunction && !unit->ignoresFunctionSignature(); + bool enforceJsTypes = !unit->ignoresFunctionSignature(); for (quint32 i = 0; i < compiledFunction->nFormals; ++i) { ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[formalsIndices[i].nameIndex]), Attr_NotConfigurable); @@ -134,14 +130,24 @@ Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit, nFormals = compiledFunction->nFormals; + if (!enforceJsTypes) + return; + + if (aotFunction) { + aotCompiledCode = aotFunction->functionPtr; + new (&aotCompiledFunction) AOTCompiledFunction; + kind = AotCompiled; + aotCompiledFunction.types.resize(aotFunction->numArguments + 1); + aotFunction->signature(unit, aotCompiledFunction.types.data()); + return; + } + // If a function has any typed arguments, but an untyped return value, the return value is void. // If it doesn't have any arguments at all and the return value is untyped, the function is // untyped. Users can specifically set the return type to "void" to have it enforced. - if (!enforceJsTypes || (nFormals == 0 && !isSpecificType(compiledFunction->returnType))) + if (nFormals == 0 && !isSpecificType(compiledFunction->returnType)) return; - JSTypedFunction *synthesized = new JSTypedFunction; - QQmlTypeLoader *typeLoader = engine->typeLoader(); auto findQmlType = [&](const CompiledData::ParameterType ¶m) { @@ -151,37 +157,21 @@ Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit, QV4::CompiledData::CommonType(type))); } - if (type == 0) + if (type == 0 || !typeLoader) return QQmlType(); - const auto base = unit->baseCompilationUnit(); - const QQmlType qmltype = typeLoader - ? base->typeNameCache->query<QQmlImport::AllowRecursion>( - base->stringAt(type), typeLoader).type - : QQmlType(); - - if (!qmltype.isValid() || qmltype.isComposite()) - return qmltype; - - if (qmltype.isInlineComponentType()) { - Q_ASSERT(qmltype.typeId().isValid()); - - // If it seems to be an IC type, make sure there is an actual - // compilation unit for it. We create inline component types speculatively. - return QQmlMetaType::obtainCompilationUnit(qmltype.typeId()) - ? qmltype - : QQmlType(); - } - + const auto &base = unit->baseCompilationUnit(); + const QQmlType qmltype = QQmlTypePrivate::compositeQmlType( + base, typeLoader, base->stringAt(type)); return qmltype.typeId().isValid() ? qmltype : QQmlType(); }; - for (quint16 i = 0; i < nFormals; ++i) - synthesized->argumentTypes.append(findQmlType(formalsIndices[i].type)); - - synthesized->returnType = findQmlType(compiledFunction->returnType); - jsTypedFunction = synthesized; + new (&jsTypedFunction) JSTypedFunction; kind = JsTyped; + jsTypedFunction.types.reserve(nFormals + 1); + jsTypedFunction.types.append(findQmlType(compiledFunction->returnType)); + for (quint16 i = 0; i < nFormals; ++i) + jsTypedFunction.types.append(findQmlType(formalsIndices[i].type)); } Function::~Function() @@ -190,8 +180,18 @@ Function::~Function() destroyFunctionTable(this, codeRef); delete codeRef; } - if (kind == JsTyped) - delete jsTypedFunction; + + switch (kind) { + case JsTyped: + jsTypedFunction.~JSTypedFunction(); + break; + case AotCompiled: + aotCompiledFunction.~AOTCompiledFunction(); + break; + case JsUntyped: + case Eval: + break; + } } void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> ¶meters) |