aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4function.cpp
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2024-04-16 17:03:01 +0200
committerUlf Hermann <ulf.hermann@qt.io>2024-04-26 12:18:15 +0000
commit8bf5aae19b77b618f3f7a55a59e87c8a319475a8 (patch)
treed331328f478ac13593524eaaeb3a874691ccadd2 /src/qml/jsruntime/qv4function.cpp
parent23fc22e16022e355f2a1aff8705c09b807fbe024 (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.cpp74
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 &param) {
@@ -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> &parameters)