diff options
Diffstat (limited to 'src/qml/jsruntime/qv4function.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4function.cpp | 105 |
1 files changed, 91 insertions, 14 deletions
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index e03c85d382..34b548113d 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -14,10 +14,11 @@ #include <private/qv4vme_moth_p.h> #include <private/qqmlglobal_p.h> #include <private/qv4jscall_p.h> +#include <private/qqmlpropertycachecreator_p.h> QT_BEGIN_NAMESPACE -using namespace QV4; +namespace QV4 { bool Function::call(QObject *thisObject, void **a, const QMetaType *types, int argc, ExecutionContext *context) @@ -39,20 +40,13 @@ bool Function::call(QObject *thisObject, void **a, const QMetaType *types, int a return !frame.isReturnValueUndefined(); } -ReturnedValue Function::call( - const Value *thisObject, const Value *argv, int argc, ExecutionContext *context) { - if (kind == AotCompiled) { - return QV4::convertAndCall( - context->engine(), typedFunction, thisObject, argv, argc, - [this, context](QObject *thisObject, - void **a, const QMetaType *types, int argc) { - call(thisObject, a, types, argc, context); - }); - } - +static ReturnedValue doCall( + Function *self, const Value *thisObject, const Value *argv, int argc, + ExecutionContext *context) +{ ExecutionEngine *engine = context->engine(); JSTypesStackFrame frame; - frame.init(this, argv, argc); + frame.init(self, argv, argc); frame.setupJSFrame(engine->jsStackTop, Value::undefinedValue(), context->d(), thisObject ? *thisObject : Value::undefinedValue()); engine->jsStackTop += frame.requiredJSStackFrameSize(); @@ -62,6 +56,29 @@ ReturnedValue Function::call( return result; } +ReturnedValue Function::call( + const Value *thisObject, const Value *argv, int argc, ExecutionContext *context) { + switch (kind) { + case AotCompiled: + return QV4::convertAndCall( + context->engine(), typedFunction, 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(), typedFunction, thisObject, argv, argc, + [this, context](const Value *thisObject, const Value *argv, int argc) { + return doCall(this, thisObject, argv, argc, context); + }); + default: + break; + } + + return doCall(this, thisObject, argv, argc, context); +} + Function *Function::create(ExecutionEngine *engine, ExecutableCompilationUnit *unit, const CompiledData::Function *function, const QQmlPrivate::TypedFunction *aotFunction) @@ -94,11 +111,67 @@ Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit, ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable); const CompiledData::Parameter *formalsIndices = compiledFunction->formalsTable(); - for (quint32 i = 0; i < compiledFunction->nFormals; ++i) + const bool enforcesSignature = !aotFunction && unit->enforcesFunctionSignature(); + bool hasTypes = false; + for (quint32 i = 0; i < compiledFunction->nFormals; ++i) { ic = ic->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[formalsIndices[i].nameIndex]), Attr_NotConfigurable); + if (enforcesSignature + && !hasTypes + && formalsIndices[i].type.typeNameIndexOrBuiltinType() + != quint32(QV4::CompiledData::BuiltinType::InvalidBuiltin)) { + hasTypes = true; + } + } internalClass = ic->d(); nFormals = compiledFunction->nFormals; + + if (!enforcesSignature) + return; + + if (!hasTypes + && compiledFunction->returnType.typeNameIndexOrBuiltinType() + == quint32(QV4::CompiledData::BuiltinType::InvalidBuiltin)) { + return; + } + + QQmlPrivate::TypedFunction *synthesized = new QQmlPrivate::TypedFunction; + QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine->qmlEngine()); + + auto findMetaType = [&](const CompiledData::ParameterType ¶m) { + if (param.indexIsBuiltinType()) { + return QQmlPropertyCacheCreatorBase::metaTypeForPropertyType( + QV4::CompiledData::BuiltinType(param.typeNameIndexOrBuiltinType())); + } + + const quint32 type = param.typeNameIndexOrBuiltinType(); + if (type == 0) + return QMetaType(); + + const QQmlType qmltype = unit->typeNameCache->query(unit->stringAt(type)).type; + if (!qmltype.isValid()) + return QMetaType(); + + const QMetaType metaType = qmltype.typeId(); + if (metaType.isValid()) + return metaType; + + if (!qmltype.isComposite()) { + return qmltype.isInlineComponentType() + ? unit->typeIdsForComponent(qmltype.inlineComponentId()).id + : QMetaType(); + } + + return enginePrivate->typeLoader.getType( + qmltype.sourceUrl())->compilationUnit()->typeIds.id; + }; + + for (quint16 i = 0; i < nFormals; ++i) + synthesized->argumentTypes.append(findMetaType(formalsIndices[i].type)); + + synthesized->returnType = findMetaType(compiledFunction->returnType); + typedFunction = synthesized; + kind = JsTyped; } Function::~Function() @@ -107,6 +180,8 @@ Function::~Function() destroyFunctionTable(this, codeRef); delete codeRef; } + if (kind == JsTyped) + delete typedFunction; } void Function::updateInternalClass(ExecutionEngine *engine, const QList<QByteArray> ¶meters) @@ -173,4 +248,6 @@ QQmlSourceLocation Function::sourceLocation() const sourceFile(), compiledFunction->location.line(), compiledFunction->location.column()); } +} // namespace QV4 + QT_END_NAMESPACE |