summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/io/qdirlisting.cpp18
-rw-r--r--src/corelib/kernel/qmetaobject.cpp42
-rw-r--r--src/corelib/kernel/qobject.cpp154
-rw-r--r--src/corelib/kernel/qobject_p.h60
-rw-r--r--tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp7
5 files changed, 208 insertions, 73 deletions
diff --git a/src/corelib/io/qdirlisting.cpp b/src/corelib/io/qdirlisting.cpp
index c626033dcdb..1fec92a01e2 100644
--- a/src/corelib/io/qdirlisting.cpp
+++ b/src/corelib/io/qdirlisting.cpp
@@ -510,16 +510,14 @@ bool QDirListingPrivate::matchesFilters(QDirEntryInfo &entryInfo) const
if (!iteratorFlags.testAnyFlag(F::IncludeHidden) && entryInfo.isHidden())
return false;
- if (entryInfo.isSymLink()) {
- // With ResolveSymlinks, we look at the type of the link's target,
- // and exclude broken symlinks (where the target doesn't exist).
- if (iteratorFlags.testAnyFlag(F::ResolveSymlinks)) {
- if (!entryInfo.exists())
- return false;
- } else if (iteratorFlags.testAnyFlags(F::FilesOnly)
- || iteratorFlags.testAnyFlags(F::DirsOnly)) {
- return false; // symlink is not a file or dir
- }
+ // With ResolveSymlinks, we look at the type of the link's target,
+ // and exclude broken symlinks (where the target doesn't exist).
+ if (iteratorFlags.testAnyFlag(F::ResolveSymlinks)) {
+ if (entryInfo.isSymLink() && !entryInfo.exists())
+ return false;
+ } else if ((iteratorFlags.testAnyFlags(F::FilesOnly)
+ || iteratorFlags.testAnyFlags(F::DirsOnly)) && entryInfo.isSymLink()) {
+ return false; // symlink is not a file or dir
}
if (iteratorFlags.testAnyFlag(F::ExcludeOther)
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index de5f27f9619..8684a02b727 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -1733,16 +1733,8 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *
"queued connections");
return false;
}
- auto event = std::make_unique<QMetaCallEvent>(std::move(slot), nullptr, -1, parameterCount);
- void **args = event->args();
- QMetaType *types = event->types();
-
- for (int i = 1; i < parameterCount; ++i) {
- types[i] = QMetaType(metaTypes[i]);
- args[i] = types[i].create(argv[i]);
- }
-
- QCoreApplication::postEvent(object, event.release());
+ QCoreApplication::postEvent(object, new QQueuedMetaCallEvent(std::move(slot), nullptr, -1,
+ parameterCount, metaTypes, params));
} else if (type == Qt::BlockingQueuedConnection) {
#if QT_CONFIG(thread)
if (receiverInSameThread)
@@ -2889,31 +2881,27 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
return InvokeFailReason::CouldNotQueueParameter;
}
- auto event = std::make_unique<QMetaCallEvent>(idx_offset, idx_relative, callFunction, nullptr, -1, paramCount);
- QMetaType *types = event->types();
- void **args = event->args();
-
+ QVarLengthArray<const QtPrivate::QMetaTypeInterface *> argTypes;
+ argTypes.emplace_back(nullptr); // return type
// fill in the meta types first
for (int i = 1; i < paramCount; ++i) {
- types[i] = QMetaType(methodMetaTypes[i - 1]);
- if (!types[i].iface() && (!MetaTypesAreOptional || metaTypes))
- types[i] = QMetaType(metaTypes[i]);
- if (!types[i].iface())
- types[i] = priv->parameterMetaType(i - 1);
- if (!types[i].iface() && typeNames[i])
- types[i] = QMetaType::fromName(typeNames[i]);
- if (!types[i].iface()) {
+ QMetaType type = QMetaType(methodMetaTypes[i - 1]);
+ if (!type.iface() && (!MetaTypesAreOptional || metaTypes))
+ type = QMetaType(metaTypes[i]);
+ if (!type.iface())
+ type = priv->parameterMetaType(i - 1);
+ if (!type.iface() && typeNames[i])
+ type = QMetaType::fromName(typeNames[i]);
+ if (!type.iface()) {
qWarning("QMetaMethod::invoke: Unable to handle unregistered datatype '%s'",
typeNames[i]);
return InvokeFailReason(int(InvokeFailReason::CouldNotQueueParameter) - i);
}
+ argTypes.emplace_back(type.iface());
}
- // now create copies of our parameters using those meta types
- for (int i = 1; i < paramCount; ++i)
- args[i] = types[i].create(parameters[i]);
-
- QCoreApplication::postEvent(object, event.release());
+ QCoreApplication::postEvent(object, new QQueuedMetaCallEvent(idx_offset, idx_relative, callFunction, nullptr,
+ -1, paramCount, argTypes.data(), parameters));
} else { // blocking queued connection
#if QT_CONFIG(thread)
if (receiverInSameThread()) {
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 888c71f5a49..d67ada64c45 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -599,14 +599,19 @@ QMetaCallEvent::QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotO,
/*!
\internal
*/
+QMetaCallEvent::QMetaCallEvent(const QObject *sender, int signalId, Data &&data)
+ : QAbstractMetaCallEvent(sender, signalId),
+ d(std::move(data)),
+ prealloc_()
+{
+}
+
+/*!
+ \internal
+ */
QMetaCallEvent::~QMetaCallEvent()
{
if (d.nargs_) {
- QMetaType *t = types();
- for (int i = 0; i < d.nargs_; ++i) {
- if (t[i].isValid() && d.args_[i])
- t[i].destroy(d.args_[i]);
- }
if (reinterpret_cast<void *>(d.args_) != reinterpret_cast<void *>(prealloc_))
free(d.args_);
}
@@ -628,6 +633,115 @@ void QMetaCallEvent::placeMetaCall(QObject *object)
}
/*!
+ \internal
+
+ Constructs a QQueuedMetaCallEvent by copying the argument values using their meta-types.
+ */
+QQueuedMetaCallEvent::QQueuedMetaCallEvent(ushort method_offset, ushort method_relative,
+ QObjectPrivate::StaticMetaCallFunction callFunction,
+ const QObject *sender, int signalId, int argCount,
+ const QtPrivate::QMetaTypeInterface * const *argTypes,
+ const void * const *argValues)
+ : QMetaCallEvent(sender, signalId, {nullptr, nullptr, callFunction, argCount,
+ method_offset, method_relative})
+{
+ allocArgs();
+ copyArgValues(argCount, argTypes, argValues);
+}
+
+/*!
+ \internal
+
+ Constructs a QQueuedMetaCallEvent by copying the argument values using their meta-types.
+ */
+QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
+ const QObject *sender, int signalId, int argCount,
+ const QtPrivate::QMetaTypeInterface * const *argTypes,
+ const void * const *argValues)
+ : QMetaCallEvent(sender, signalId, {QtPrivate::SlotObjUniquePtr(slotObj), nullptr, nullptr, argCount,
+ 0, ushort(-1)})
+{
+ if (d.slotObj_)
+ d.slotObj_->ref();
+ allocArgs();
+ copyArgValues(argCount, argTypes, argValues);
+}
+
+/*!
+ \internal
+
+ Constructs a QQueuedMetaCallEvent by copying the argument values using their meta-types.
+ */
+QQueuedMetaCallEvent::QQueuedMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj,
+ const QObject *sender, int signalId, int argCount,
+ const QtPrivate::QMetaTypeInterface * const *argTypes,
+ const void * const *argValues)
+ : QMetaCallEvent(sender, signalId, {std::move(slotObj), nullptr, nullptr, argCount,
+ 0, ushort(-1)})
+{
+ allocArgs();
+ copyArgValues(argCount, argTypes, argValues);
+}
+
+/*!
+ \internal
+ */
+QQueuedMetaCallEvent::~QQueuedMetaCallEvent()
+{
+ const QMetaType *t = types();
+ int inplaceIndex = 0;
+ for (int i = 0; i < d.nargs_; ++i) {
+ if (t[i].isValid() && d.args_[i]) {
+ if (typeFitsInPlace(t[i]) && inplaceIndex < InplaceValuesCapacity) {
+ // Only destruct
+ void *where = &valuesPrealloc_[inplaceIndex++].storage;
+ t[i].destruct(where);
+ } else {
+ // Destruct and deallocate
+ t[i].destroy(d.args_[i]);
+ }
+ }
+ }
+}
+
+/*!
+ \internal
+ */
+inline void QQueuedMetaCallEvent::copyArgValues(int argCount, const QtPrivate::QMetaTypeInterface * const *argTypes,
+ const void * const *argValues)
+{
+ void **args = d.args_;
+ QMetaType *types = this->types();
+ int inplaceIndex = 0;
+
+ types[0] = QMetaType(); // return type
+ args[0] = nullptr; // return value pointer
+ // no return value
+
+ for (int n = 1; n < argCount; ++n) {
+ types[n] = QMetaType(argTypes[n]);
+ if (typeFitsInPlace(types[n]) && inplaceIndex < InplaceValuesCapacity) {
+ // Copy-construct in place
+ void *where = &valuesPrealloc_[inplaceIndex++].storage;
+ types[n].construct(where, argValues[n]);
+ args[n] = where;
+ } else {
+ // Allocate and copy-construct
+ args[n] = types[n].create(argValues[n]);
+ }
+ }
+}
+
+/*!
+ \internal
+ */
+inline bool QQueuedMetaCallEvent::typeFitsInPlace(const QMetaType type)
+{
+ return (q20::cmp_less_equal(type.sizeOf(), sizeof(ArgValueStorage)) &&
+ q20::cmp_less_equal(type.alignOf(), alignof(ArgValueStorage)));
+}
+
+/*!
\class QSignalBlocker
\brief Exception-safe wrapper around QObject::blockSignals().
\since 5.3
@@ -4069,26 +4183,19 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect
SlotObjectGuard slotObjectGuard { c->isSlotObject ? c->slotObj : nullptr };
locker.unlock();
- QMetaCallEvent *ev = c->isSlotObject ?
- new QMetaCallEvent(c->slotObj, sender, signal, nargs) :
- new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal, nargs);
-
- void **args = ev->args();
- QMetaType *types = ev->types();
-
- types[0] = QMetaType(); // return type
- args[0] = nullptr; // return value
-
- if (nargs > 1) {
- for (int n = 1; n < nargs; ++n)
- types[n] = QMetaType(argumentTypes[n - 1]);
-
- for (int n = 1; n < nargs; ++n)
- args[n] = types[n].create(argv[n]);
+ QVarLengthArray<const QtPrivate::QMetaTypeInterface *> argTypes;
+ argTypes.emplace_back(nullptr); // return type
+ for (int n = 1; n < nargs; ++n) {
+ argTypes.emplace_back(QMetaType(argumentTypes[n - 1]).iface()); // convert type ids to QMetaTypeInterfaces
}
+ auto ev = c->isSlotObject ?
+ std::make_unique<QQueuedMetaCallEvent>(c->slotObj,
+ sender, signal, nargs, argTypes.data(), argv) :
+ std::make_unique<QQueuedMetaCallEvent>(c->method_offset, c->method_relative, c->callFunction,
+ sender, signal, nargs, argTypes.data(), argv);
+
if (c->isSingleShot && !QObjectPrivate::removeConnection(c)) {
- delete ev;
return;
}
@@ -4096,11 +4203,10 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect
if (!c->isSingleShot && !c->receiver.loadRelaxed()) {
// the connection has been disconnected while we were unlocked
locker.unlock();
- delete ev;
return;
}
- QCoreApplication::postEvent(receiver, ev);
+ QCoreApplication::postEvent(receiver, ev.release());
}
template <bool callbacks_enabled>
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index dca9c1af932..75aeba73583 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -351,7 +351,7 @@ private:
class Q_CORE_EXPORT QMetaCallEvent : public QAbstractMetaCallEvent
{
public:
- // blocking queued with latch - args always owned by caller
+ // blocking queued with latch - arguments always remain owned by the caller
QMetaCallEvent(ushort method_offset, ushort method_relative,
QObjectPrivate::StaticMetaCallFunction callFunction,
const QObject *sender, int signalId,
@@ -363,14 +363,17 @@ public:
const QObject *sender, int signalId,
void **args, QLatch *latch);
- // queued - args allocated by event, copied by caller
+ // OLD - queued - args allocated by event, copied by caller
+ Q_DECL_DEPRECATED_X("Remove this constructor once the qtdeclarative patch is merged. Arguments are now copied by the QQueuedMetaCallEvent constructor and not the caller.")
QMetaCallEvent(ushort method_offset, ushort method_relative,
QObjectPrivate::StaticMetaCallFunction callFunction,
const QObject *sender, int signalId,
int nargs);
+ Q_DECL_DEPRECATED_X("Remove this constructor once the qtdeclarative patch is merged. Arguments are now copied by the QQueuedMetaCallEvent constructor and not the caller.")
QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
const QObject *sender, int signalId,
int nargs);
+ Q_DECL_DEPRECATED_X("Remove this constructor once the qtdeclarative patch is merged. Arguments are now copied by the QQueuedMetaCallEvent constructor and not the caller.")
QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj,
const QObject *sender, int signalId,
int nargs);
@@ -378,14 +381,16 @@ public:
~QMetaCallEvent() override;
inline int id() const { return d.method_offset_ + d.method_relative_; }
- inline const void * const* args() const { return d.args_; }
+ Q_DECL_DEPRECATED_X("Remove this function once the qtdeclarative patch is merged. Arguments are now copied by the QQueuedMetaCallEvent constructor and not the caller.")
inline void ** args() { return d.args_; }
- inline const QMetaType *types() const { return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); }
+ Q_DECL_DEPRECATED_X("Remove this function once the qtdeclarative patch is merged. Arguments are now copied by the QQueuedMetaCallEvent constructor and not the caller.")
inline QMetaType *types() { return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); }
virtual void placeMetaCall(QObject *object) override;
-private:
+protected:
+ // Move to QQueuedMetaCallEvent once the qtdeclarative patch is merged.
+ // QMetaCallEvent should not alloc anything anymore.
inline void allocArgs();
struct Data {
@@ -396,9 +401,50 @@ private:
ushort method_offset_;
ushort method_relative_;
} d;
- // preallocate enough space for three arguments
- alignas(void *) char prealloc_[3 * sizeof(void *) + 3 * sizeof(QMetaType)];
+
+ inline QMetaCallEvent(const QObject *sender, int signalId, Data &&data);
+ inline void * const *args() const { return d.args_; }
+ inline QMetaType const *types() const { return reinterpret_cast<QMetaType *>(d.args_ + d.nargs_); }
+
+ // Space for 5 argument pointers and types (including 1 return arg).
+ // Contiguous so that we can make one calloc() for both the pointers and the types when necessary.
+ // Move to QQueuedMetaCallEvent once the qtdeclarative patch is merged.
+ alignas(void *) char prealloc_[5 * sizeof(void *) + 5 * sizeof(QMetaType)];
+};
+
+class Q_CORE_EXPORT QQueuedMetaCallEvent : public QMetaCallEvent
+{
+public:
+ // queued - arguments are allocated and copied from argValues by these constructors
+ QQueuedMetaCallEvent(ushort method_offset, ushort method_relative,
+ QObjectPrivate::StaticMetaCallFunction callFunction,
+ const QObject *sender, int signalId,
+ int argCount, const QtPrivate::QMetaTypeInterface * const *argTypes,
+ const void * const *argValues);
+ QQueuedMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
+ const QObject *sender, int signalId,
+ int argCount, const QtPrivate::QMetaTypeInterface * const *argTypes,
+ const void * const *argValues);
+ QQueuedMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj,
+ const QObject *sender, int signalId,
+ int argCount, const QtPrivate::QMetaTypeInterface * const *argTypes,
+ const void * const *argValues);
+
+ ~QQueuedMetaCallEvent() override;
+
+private:
+ inline void copyArgValues(int argCount, const QtPrivate::QMetaTypeInterface * const *argTypes,
+ const void * const *argValues);
+ static inline bool typeFitsInPlace(const QMetaType type);
+
+ struct ArgValueStorage { // size and alignment matching QString, QList, etc
+ static constexpr size_t MaxSize = 3 * sizeof(void *);
+ alignas(void *) char storage[MaxSize];
+ };
+ static constexpr int InplaceValuesCapacity = 3;
+ ArgValueStorage valuesPrealloc_[InplaceValuesCapacity];
};
+// The total QQueuedMetaCallEvent size is 224 bytes which is a 32-byte multiple, efficient for memory allocators.
struct QAbstractDynamicMetaObject;
struct Q_CORE_EXPORT QDynamicMetaObjectData
diff --git a/tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp b/tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp
index 6dd8a6d07f9..103530ec3ed 100644
--- a/tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp
+++ b/tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp
@@ -1379,17 +1379,14 @@ void tst_QTextStream::pos2()
// ------------------------------------------------------------------------------
void tst_QTextStream::pos3LargeFile()
{
- if (QTestPrivate::isRunningArmOnX86())
- QSKIP("Running QTextStream::pos() in tight loop is too slow on emulator");
-
{
QFile file(testFileName);
QVERIFY(file.open(QIODevice::WriteOnly | QIODevice::Text));
QTextStream out( &file );
// NOTE: The unusual spacing is to ensure non-1-character whitespace.
QString lineString = " 0 1 2\t3 4\t \t5 6 7 8 9 \n";
- // Approximate 50kb text file
- const int NbLines = (50*1024) / lineString.size() + 1;
+ // Approximately 5kb text file (more is too slow (QTBUG-138435))
+ const int NbLines = (5 * 1024) / lineString.size() + 1;
for (int line = 0; line < NbLines; ++line)
QVERIFY(out << lineString);
// File is automatically flushed and closed on destruction.