QMetaObject: rewrite newInstance()

Like in the previous commit, use QMetaMethodPrivate::invokeImpl() to
avoid having to reconstruct the method signature.

Change-Id: I36b24183fbd041179f2ffffd17021c7a0bfa48c0
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
bb10
Thiago Macieira 2022-07-15 14:02:03 -07:00
parent 0f76e55bc4
commit b73ab954df
1 changed files with 57 additions and 38 deletions

View File

@ -185,6 +185,7 @@ public:
inline QList<QByteArray> parameterNames() const;
inline QByteArray tag() const;
inline int ownMethodIndex() const;
inline int ownConstructorIndex() const;
// shadows the public function
enum class InvokeFailReason : int {
@ -194,6 +195,8 @@ public:
DeadLockDetected = -2,
CallViaVirtualFailed = -3, // no warning
ConstructorCallOnObject = -4,
ConstructorCallWithoutResult = -5,
ConstructorCallFailed = -6, // no warning
CouldNotQueueParameter = -0x1000,
@ -213,6 +216,8 @@ private:
QMetaMethodPrivate();
};
enum { MaximumParamCount = 11 }; // up to 10 arguments + 1 return value
/*!
\since 4.5
@ -243,48 +248,42 @@ QObject *QMetaObject::newInstance(QGenericArgument val0,
return nullptr;
}
QByteArray constructorName = className();
{
int idx = constructorName.lastIndexOf(':');
if (idx != -1)
constructorName.remove(0, idx+1); // remove qualified part
}
QVarLengthArray<char, 512> sig;
sig.append(constructorName.constData(), constructorName.length());
sig.append('(');
QObject *returnValue = nullptr;
QMetaType returnValueMetaType = QMetaType::fromType<decltype(returnValue)>();
enum { MaximumParamCount = 10 };
const char *typeNames[] = {val0.name(), val1.name(), val2.name(), val3.name(), val4.name(),
val5.name(), val6.name(), val7.name(), val8.name(), val9.name()};
const char *typeNames[] = {
returnValueMetaType.name(),
val0.name(), val1.name(), val2.name(), val3.name(), val4.name(),
val5.name(), val6.name(), val7.name(), val8.name(), val9.name()
};
const void *parameters[] = {
&returnValue,
val0.data(), val1.data(), val2.data(), val3.data(), val4.data(),
val5.data(), val6.data(), val7.data(), val8.data(), val9.data()
};
int paramCount;
for (paramCount = 0; paramCount < MaximumParamCount; ++paramCount) {
for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) {
int len = int(qstrlen(typeNames[paramCount]));
if (len <= 0)
break;
sig.append(typeNames[paramCount], len);
sig.append(',');
}
if (paramCount == 0)
sig.append(')'); // no parameters
else
sig[sig.size() - 1] = ')';
sig.append('\0');
int idx = indexOfConstructor(sig.constData());
if (idx < 0) {
QByteArray norm = QMetaObject::normalizedSignature(sig.constData());
idx = indexOfConstructor(norm.constData());
// find the constructor
auto priv = QMetaObjectPrivate::get(this);
for (int i = 0; i < priv->constructorCount; ++i) {
QMetaMethod m = QMetaMethod::fromRelativeConstructorIndex(this, i);
// attempt to call
QMetaMethodPrivate::InvokeFailReason r =
QMetaMethodPrivate::invokeImpl(m, nullptr, Qt::DirectConnection, paramCount,
parameters, typeNames);
if (r == QMetaMethodPrivate::InvokeFailReason::None)
return returnValue;
if (int(r) < 0)
return nullptr;
}
if (idx < 0)
return nullptr;
QObject *returnValue = nullptr;
void *param[] = {&returnValue, val0.data(), val1.data(), val2.data(), val3.data(), val4.data(),
val5.data(), val6.data(), val7.data(), val8.data(), val9.data()};
if (static_metacall(CreateInstance, idx, param) >= 0)
return nullptr;
return returnValue;
}
@ -1341,8 +1340,6 @@ QByteArray QMetaObject::normalizedSignature(const char *method)
return result;
}
enum { MaximumParamCount = 11 }; // up to 10 arguments + 1 return value
/*
Returns the signatures of all methods whose name matches \a nonExistentMember,
or an empty QByteArray if there are no matches.
@ -1877,10 +1874,18 @@ QByteArray QMetaMethodPrivate::tag() const
int QMetaMethodPrivate::ownMethodIndex() const
{
// recompute the methodIndex by reversing the arithmetic in QMetaObject::property()
// recompute the methodIndex by reversing the arithmetic in QMetaObject::method()
Q_ASSERT(methodType() != Constructor);
return ( data.d - mobj->d.data - priv(mobj->d.data)->methodData)/Data::Size;
}
int QMetaMethodPrivate::ownConstructorIndex() const
{
// recompute the methodIndex by reversing the arithmetic in QMetaObject::constructor()
Q_ASSERT(methodType() == Constructor);
return ( data.d - mobj->d.data - priv(mobj->d.data)->constructorData)/Data::Size;
}
/*!
\since 5.0
@ -2410,14 +2415,28 @@ auto QMetaMethodPrivate::invokeImpl(QMetaMethod self, void *target,
return InvokeFailReason(int(InvokeFailReason::FormalParameterMismatch) + i - 1);
}
// regular type - check return type
if (parameters[0]) {
if (self.methodType() == Constructor) {
// handle constructors first
if (self.methodType() == Constructor) {
if (object) {
qWarning("QMetaMethod::invokeMethod: cannot call constructor %s on object %p",
self.methodSignature().constData(), object);
return InvokeFailReason::ConstructorCallOnObject;
}
if (!parameters[0]) {
qWarning("QMetaMethod::invokeMethod: constructor call to %s must assign a return type",
self.methodSignature().constData());
return InvokeFailReason::ConstructorCallWithoutResult;
}
int idx = priv->ownConstructorIndex();
if (priv->mobj->static_metacall(QMetaObject::CreateInstance, idx, param) >= 0)
return InvokeFailReason::ConstructorCallFailed;
return {};
}
// regular type - check return type
if (parameters[0]) {
if (!checkTypesAreCompatible(0)) {
qWarning("QMetaMethod::invokeMethod: return type mismatch for method %s::%s:"
" cannot convert from %s to %s during invocation",