diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/qml/compat/removed_api.cpp | 9 | ||||
| -rw-r--r-- | src/qml/qml/qqml.cpp | 4 | ||||
| -rw-r--r-- | src/qml/qml/qqmlglobal.cpp | 22 | ||||
| -rw-r--r-- | src/qml/qml/qqmlglobal_p.h | 2 | ||||
| -rw-r--r-- | src/qml/qml/qqmlprivate.h | 5 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljscodegenerator.cpp | 94 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljscodegenerator_p.h | 4 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljstypepropagator.cpp | 28 | ||||
| -rw-r--r-- | src/qmlcompiler/qqmljstyperesolver.cpp | 2 |
9 files changed, 132 insertions, 38 deletions
diff --git a/src/qml/compat/removed_api.cpp b/src/qml/compat/removed_api.cpp index 3ee11717cd..4cbaab71a9 100644 --- a/src/qml/compat/removed_api.cpp +++ b/src/qml/compat/removed_api.cpp @@ -116,4 +116,13 @@ void QQmlPrivate::AOTCompiledContext::initLoadGlobalLookup(uint index) const engine->handle()->amendException(); } +QVariant QQmlPrivate::AOTCompiledContext::constructValueType( + QMetaType resultMetaType, const QMetaObject *resultMetaObject, + int ctorIndex, void *ctorArg) const +{ + void *args[] = {ctorArg}; + return QQmlValueTypeProvider::constructValueType( + resultMetaType, resultMetaObject, ctorIndex, args); +} + #endif diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index 5eed97fb02..b1671f6e70 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -1742,10 +1742,10 @@ void AOTCompiledContext::writeToConsole( QVariant AOTCompiledContext::constructValueType( QMetaType resultMetaType, const QMetaObject *resultMetaObject, - int ctorIndex, void *ctorArg) const + int ctorIndex, void **args) const { return QQmlValueTypeProvider::constructValueType( - resultMetaType, resultMetaObject, ctorIndex, ctorArg); + resultMetaType, resultMetaObject, ctorIndex, args); } QDateTime AOTCompiledContext::constructDateTime(double timestamp) const diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp index 1d55efc4f6..f77f72fb40 100644 --- a/src/qml/qml/qqmlglobal.cpp +++ b/src/qml/qml/qqmlglobal.cpp @@ -5,6 +5,7 @@ #include <QtQml/private/qqmlglobal_p.h> #include <QtQml/private/qqmlmetatype_p.h> #include <QtQml/private/qv4qobjectwrapper_p.h> +#include <QtQml/private/qv4alloca_p.h> #include <QtQml/qqmlengine.h> #include <QtCore/private/qvariant_p.h> @@ -178,20 +179,29 @@ static void *createVariantData(QMetaType type, QVariant *variant) } static void callConstructor( + const QMetaObject *targetMetaObject, int i, void **args, int argc, void *target) +{ + Q_ALLOCA_VAR(void *, p, (argc + 1) * sizeof(void *)); + p[0] = target; + memcpy(p + 1, args, argc * sizeof(void *)); + targetMetaObject->static_metacall(QMetaObject::ConstructInPlace, i, p); +} + +static void callConstructor( const QMetaObject *targetMetaObject, int i, void *source, void *target) { void *p[] = { target, source }; targetMetaObject->static_metacall(QMetaObject::ConstructInPlace, i, p); } + template<typename Allocate> static void fromVerifiedType( - const QMetaObject *targetMetaObject, int ctorIndex, void *source, Allocate &&allocate) + const QMetaObject *targetMetaObject, int ctorIndex, void **args, + Allocate &&allocate) { const QMetaMethod ctor = targetMetaObject->constructor(ctorIndex); - Q_ASSERT_X(ctor.parameterCount() == 1, "fromVerifiedType", - "Value type constructor must take exactly one argument"); - callConstructor(targetMetaObject, ctorIndex, source, allocate()); + callConstructor(targetMetaObject, ctorIndex, args, ctor.parameterCount(), allocate()); } @@ -774,10 +784,10 @@ void *QQmlValueTypeProvider::heapCreateValueType( QVariant QQmlValueTypeProvider::constructValueType( QMetaType targetMetaType, const QMetaObject *targetMetaObject, - int ctorIndex, void *ctorArg) + int ctorIndex, void **args) { QVariant result; - fromVerifiedType(targetMetaObject, ctorIndex, ctorArg, + fromVerifiedType(targetMetaObject, ctorIndex, args, [&]() { return createVariantData(targetMetaType, &result); }); return result; } diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h index 9b8482724e..cd7250c30a 100644 --- a/src/qml/qml/qqmlglobal_p.h +++ b/src/qml/qml/qqmlglobal_p.h @@ -217,7 +217,7 @@ public: const QQmlType &targetType, const QV4::Value &source, QV4::ExecutionEngine *engine); static QVariant constructValueType( QMetaType targetMetaType, const QMetaObject *targetMetaObject, - int ctorIndex, void *ctorArg); + int ctorIndex, void **args); static QVariant createValueType(const QJSValue &, QMetaType); static QVariant createValueType(const QString &, QMetaType); diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index e538922900..93fd337dc5 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -652,7 +652,12 @@ namespace QQmlPrivate QVariant constructValueType( QMetaType resultMetaType, const QMetaObject *resultMetaObject, + int ctorIndex, void **args) const; +#if QT_QML_REMOVED_SINCE(6, 9) + QVariant constructValueType( + QMetaType resultMetaType, const QMetaObject *resultMetaObject, int ctorIndex, void *ctorArg) const; +#endif // Those are explicit arguments to the Date() ctor, not implicit coercions. QDateTime constructDateTime(double timestamp) const; diff --git a/src/qmlcompiler/qqmljscodegenerator.cpp b/src/qmlcompiler/qqmljscodegenerator.cpp index 2afa456075..063140f92d 100644 --- a/src/qmlcompiler/qqmljscodegenerator.cpp +++ b/src/qmlcompiler/qqmljscodegenerator.cpp @@ -1314,6 +1314,43 @@ bool QQmlJSCodeGenerator::generateContentPointerCheck( return needsVarContentConversion; } +QString QQmlJSCodeGenerator::generateCallConstructor( + const QQmlJSMetaMethod &ctor, const QList<QQmlJSRegisterContent> &argumentTypes, + const QStringList &arguments, const QString &metaType, const QString &metaObject) +{ + const auto parameterTypes = ctor.parameters(); + Q_ASSERT(parameterTypes.length() == argumentTypes.length()); + + // We need to store the converted arguments in a temporaries because they might not be lvalues. + QStringList argPointers; + + QString result = u"[&](){\n"_s; + for (qsizetype i = 0, end = parameterTypes.length(); i < end; ++i) { + const QQmlJSRegisterContent argumentType = argumentTypes[i]; + const QQmlJSScope::ConstPtr parameterType = parameterTypes[i].type(); + const QString argument = arguments[i]; + const QString arg = u"arg"_s + QString::number(i); + + result += u" auto "_s + arg + u" = "_s; + if (m_typeResolver->registerContains(argumentType, parameterType)) { + result += argument; + argPointers.append(contentPointer(argumentType, arg)); + } else { + const QQmlJSRegisterContent parameterTypeConversion = conversionType(parameterType) + .storedIn(m_typeResolver->genericType(parameterType)); + result += conversion(argumentType, parameterTypeConversion, argument); + argPointers.append(contentPointer(parameterTypeConversion, arg)); + } + result += u";\n"_s; + } + + result += u" void *args[] = {"_s + argPointers.join(u',') + u"};\n"_s; + result += u" return aotContext->constructValueType("_s + metaType + u", "_s + metaObject + + u", "_s + QString::number(int(ctor.constructorIndex())) + u", args);\n"_s; + + return result + u"}()"_s; +} + QString QQmlJSCodeGenerator::resolveValueTypeContentPointer( const QQmlJSScope::ConstPtr &required, const QQmlJSRegisterContent &actual, const QString &variable, const QString &errorMessage) @@ -2411,6 +2448,35 @@ void QQmlJSCodeGenerator::generate_Construct(int func, int argc, int argv) return; } + const QQmlJSScope::ConstPtr originalContained = originalResult.containedType(); + if (originalContained->isValueType() && originalResult.isMethodCall()) { + const QQmlJSMetaMethod ctor = originalResult.methodCall(); + if (ctor.isJavaScriptFunction()) { + reject(u"calling JavaScript constructor "_s + ctor.methodName()); + return; + } + + QList<QQmlJSRegisterContent> argumentTypes; + QStringList arguments; + for (int i = 0; i < argc; ++i) { + argumentTypes.append(registerType(argv + i)); + arguments.append(consumedRegisterVariable(argv + i)); + } + + const QQmlJSScope::ConstPtr extension = originalContained->extensionType().scope; + const QString result = generateCallConstructor( + ctor, argumentTypes, arguments, metaType(originalContained), + metaObject(extension ? extension : originalContained)); + + m_body += m_state.accumulatorVariableOut + u" = "_s + + conversion(originalResult.storedIn( + m_typeResolver->varType()), m_state.accumulatorOut(), result) + + u";\n"_s; + + return; + } + + reject(u"Construct"_s); } @@ -4251,31 +4317,9 @@ QString QQmlJSCodeGenerator::convertContained(const QQmlJSRegisterContent &from, return QString(); } else if (const auto ctor = m_typeResolver->selectConstructor( containedTo, containedFrom, &isExtension); ctor.isValid()) { - const auto argumentTypes = ctor.parameters(); - const QQmlJSScope::ConstPtr argumentType = argumentTypes[0].type(); - - // We need to store the converted argument in a temporary - // because it might not be an lvalue. - - QString input; - QString argPointer; - - if (m_typeResolver->equals(argumentType, containedFrom)) { - input = variable; - argPointer = contentPointer(from, u"arg"_s); - } else { - const QQmlJSRegisterContent argument = conversionType(argumentType) - .storedIn(m_typeResolver->genericType(argumentType)); - input = conversion(from, argument, variable); - argPointer = contentPointer(argument, u"arg"_s); - } - - return u"[&](){ auto arg = " + input - + u"; return aotContext->constructValueType("_s + metaType(containedTo) - + u", "_s + metaObject( - isExtension ? containedTo->extensionType().scope : containedTo) - + u", "_s + QString::number(int(ctor.constructorIndex())) - + u", "_s + argPointer + u"); }()"_s; + return generateCallConstructor( + ctor, {from}, {variable}, metaType(containedTo), + metaObject(isExtension ? containedTo->extensionType().scope : containedTo)); } const auto originalFrom = originalType(from); diff --git a/src/qmlcompiler/qqmljscodegenerator_p.h b/src/qmlcompiler/qqmljscodegenerator_p.h index 8843e6832e..0e8925c95b 100644 --- a/src/qmlcompiler/qqmljscodegenerator_p.h +++ b/src/qmlcompiler/qqmljscodegenerator_p.h @@ -338,6 +338,10 @@ private: const QQmlJSScope::ConstPtr &required, const QQmlJSRegisterContent &actual, const QString &variable, const QString &errorMessage); + QString generateCallConstructor( + const QQmlJSMetaMethod &ctor, const QList<QQmlJSRegisterContent> &argumentTypes, + const QStringList &arguments, const QString &metaType, const QString &metaObject); + QQmlJSRegisterContent originalType(const QQmlJSRegisterContent &tracked) { const QQmlJSRegisterContent restored = m_typeResolver->original(tracked); diff --git a/src/qmlcompiler/qqmljstypepropagator.cpp b/src/qmlcompiler/qqmljstypepropagator.cpp index 10690e5469..babed83b65 100644 --- a/src/qmlcompiler/qqmljstypepropagator.cpp +++ b/src/qmlcompiler/qqmljstypepropagator.cpp @@ -1547,9 +1547,14 @@ void QQmlJSTypePropagator::propagateCall( if (m_passManager) propagateCall_SAcheck(match, scope.containedType()); - const QQmlJSScope::ConstPtr returnType = match.isJavaScriptFunction() - ? m_typeResolver->jsValueType() - : QQmlJSScope::ConstPtr(match.returnType()); + QQmlJSScope::ConstPtr returnType; + if (match.isJavaScriptFunction()) + returnType = m_typeResolver->jsValueType(); + else if (match.isConstructor()) + returnType = scope.containedType(); + else + returnType = match.returnType(); + setAccumulator(m_typeResolver->returnType(match, returnType, scope)); if (!m_state.accumulatorOut().isValid()) addError(u"Cannot store return type of method %1()."_s.arg(match.methodName())); @@ -2023,6 +2028,23 @@ void QQmlJSTypePropagator::generate_Construct_SCArray( void QQmlJSTypePropagator::generate_Construct(int func, int argc, int argv) { const QQmlJSRegisterContent type = m_state.registers[func].content; + if (m_typeResolver->registerContains(type, m_typeResolver->metaObjectType())) { + const QQmlJSRegisterContent valueType = type.scopeType(); + const QQmlJSScope::ConstPtr contained = type.scopeType().containedType(); + if (contained->isValueType() && contained->isCreatable()) { + const auto extension = contained->extensionType(); + if (extension.extensionSpecifier == QQmlJSScope::ExtensionType) { + propagateCall( + extension.scope->ownMethods(extension.scope->internalName()), + argc, argv, valueType); + } else { + propagateCall( + contained->ownMethods(contained->internalName()), argc, argv, valueType); + } + return; + } + } + if (!type.isMethod()) { m_state.setHasSideEffects(true); QQmlJSMetaMethod method; diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp index dc3dff2c09..57318a5ff5 100644 --- a/src/qmlcompiler/qqmljstyperesolver.cpp +++ b/src/qmlcompiler/qqmljstyperesolver.cpp @@ -566,7 +566,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::registerContentForName( QQmlJSRegisterContent::MetaType, namedType); case QQmlJSScope::AccessSemantics::Sequence: case QQmlJSScope::AccessSemantics::Value: - if (canAddressValueTypes()) { + if (scopeType.isImportNamespace() || canAddressValueTypes()) { return QQmlJSRegisterContent::create( metaObjectType(), QQmlJSRegisterContent::InvalidLookupIndex, QQmlJSRegisterContent::MetaType, namedType); |
