diff options
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/global/qglobal.h | 3 | ||||
-rw-r--r-- | src/corelib/global/qmalloc.cpp | 58 | ||||
-rw-r--r-- | src/corelib/io/qprocess_unix.cpp | 18 | ||||
-rw-r--r-- | src/corelib/kernel/qmetaobject.cpp | 4 | ||||
-rw-r--r-- | src/corelib/plugin/qlibrary.cpp | 3 | ||||
-rw-r--r-- | src/corelib/tools/qcontiguouscache.cpp | 10 | ||||
-rw-r--r-- | src/corelib/tools/qcontiguouscache.h | 147 | ||||
-rw-r--r-- | src/corelib/tools/qhash.cpp | 28 | ||||
-rw-r--r-- | src/corelib/tools/qhash.h | 37 | ||||
-rw-r--r-- | src/corelib/tools/qmap.cpp | 32 | ||||
-rw-r--r-- | src/corelib/tools/qmap.h | 21 | ||||
-rw-r--r-- | src/corelib/tools/qvector.cpp | 29 | ||||
-rw-r--r-- | src/corelib/tools/qvector.h | 22 |
13 files changed, 306 insertions, 106 deletions
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 5ee1815..cbb8fda 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -2065,6 +2065,9 @@ Q_DECLARE_TYPEINFO(long double, Q_PRIMITIVE_TYPE); Q_CORE_EXPORT void *qMalloc(size_t size); Q_CORE_EXPORT void qFree(void *ptr); Q_CORE_EXPORT void *qRealloc(void *ptr, size_t size); +Q_CORE_EXPORT void *qMallocAligned(size_t size, size_t alignment); +Q_CORE_EXPORT void *qReallocAligned(void *ptr, size_t size, size_t oldsize, size_t alignment); +Q_CORE_EXPORT void qFreeAligned(void *ptr); Q_CORE_EXPORT void *qMemCopy(void *dest, const void *src, size_t n); Q_CORE_EXPORT void *qMemSet(void *dest, int c, size_t n); diff --git a/src/corelib/global/qmalloc.cpp b/src/corelib/global/qmalloc.cpp index a9f103c..4aab1bd 100644 --- a/src/corelib/global/qmalloc.cpp +++ b/src/corelib/global/qmalloc.cpp @@ -65,4 +65,62 @@ void *qRealloc(void *ptr, size_t size) return ::realloc(ptr, size); } +void *qMallocAligned(size_t size, size_t alignment) +{ + return qReallocAligned(0, size, 0, alignment); +} + +void *qReallocAligned(void *oldptr, size_t newsize, size_t oldsize, size_t alignment) +{ + // fake an aligned allocation + Q_UNUSED(oldsize); + + void *actualptr = oldptr ? static_cast<void **>(oldptr)[-1] : 0; + if (alignment <= sizeof(void*)) { + // special, fast case + void **newptr = static_cast<void **>(qRealloc(actualptr, newsize + sizeof(void*))); + if (!newptr) + return 0; + if (newptr == actualptr) { + // realloc succeeded without reallocating + return oldptr; + } + + *newptr = newptr; + return newptr + 1; + } + + union { void *ptr; void **pptr; quintptr n; } real, faked; + + // qMalloc returns pointers aligned at least at sizeof(size_t) boundaries + // but usually more (8- or 16-byte boundaries). + // So we overallocate by alignment-sizeof(size_t) bytes, so we're guaranteed to find a + // somewhere within the first alignment-sizeof(size_t) that is properly aligned. + + // However, we need to store the actual pointer, so we need to allocate actually size + + // alignment anyway. + + real.ptr = qRealloc(actualptr, newsize + alignment); + if (!real.ptr) + return 0; + + faked.n = real.n + alignment; + faked.n &= ~(alignment - 1); + + // now save the value of the real pointer at faked-sizeof(void*) + // by construction, alignment > sizeof(void*) and is a power of 2, so + // faked-sizeof(void*) is properly aligned for a pointer + faked.pptr[-1] = real.ptr; + + return faked.ptr; +} + +void qFreeAligned(void *ptr) +{ + if (!ptr) + return; + void **ptr2 = static_cast<void **>(ptr); + free(ptr2[-1]); +} + QT_END_NAMESPACE diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 99296c7..f040d16 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -108,6 +108,10 @@ QT_END_NAMESPACE QT_BEGIN_NAMESPACE +// POSIX requires PIPE_BUF to be 512 or larger +// so we will use 512 +static const int errorBufferMax = 512; + #ifdef Q_OS_INTEGRITY static inline char *strdup(const char *data) { @@ -752,18 +756,19 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv } // notify failure + QString error = qt_error_string(errno); #if defined (QPROCESS_DEBUG) - fprintf(stderr, "QProcessPrivate::execChild() failed, notifying parent process\n"); + fprintf(stderr, "QProcessPrivate::execChild() failed (%s), notifying parent process\n", qPrintable(error)); #endif - qt_safe_write(childStartedPipe[1], "", 1); + qt_safe_write(childStartedPipe[1], error.data(), error.length() * sizeof(QChar)); qt_safe_close(childStartedPipe[1]); childStartedPipe[1] = -1; } bool QProcessPrivate::processStarted() { - char c; - int i = qt_safe_read(childStartedPipe[0], &c, 1); + ushort buf[errorBufferMax]; + int i = qt_safe_read(childStartedPipe[0], &buf, sizeof buf); if (startupSocketNotifier) { startupSocketNotifier->setEnabled(false); startupSocketNotifier->deleteLater(); @@ -775,6 +780,11 @@ bool QProcessPrivate::processStarted() #if defined (QPROCESS_DEBUG) qDebug("QProcessPrivate::processStarted() == %s", i <= 0 ? "true" : "false"); #endif + + // did we read an error message? + if (i > 0) + q_func()->setErrorString(QString::fromUtf16(buf, i / sizeof(QChar))); + return i <= 0; } diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index f98c449..71afc5b 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -574,8 +574,8 @@ int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject, co if (i >= 0 && m && m->d.superdata) { int conflict = m->d.superdata->indexOfMethod(signal); if (conflict >= 0) - qWarning("QMetaObject::indexOfSignal:%s: Conflict with %s::%s", - m->d.stringdata, m->d.superdata->d.stringdata, signal); + qWarning("QMetaObject::indexOfSignal: signal %s from %s redefined in %s", + signal, m->d.superdata->d.stringdata, m->d.stringdata); } #endif return i; diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index 2b463a1..6496876 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -659,7 +659,10 @@ bool QLibraryPrivate::isPlugin(QSettings *settings) #endif if (!pHnd) { #ifdef Q_OS_WIN + //avoid 'Bad Image' message box + UINT oldmode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); hTempModule = ::LoadLibraryEx((wchar_t*)QDir::toNativeSeparators(fileName).utf16(), 0, DONT_RESOLVE_DLL_REFERENCES); + SetErrorMode(oldmode); #else # if defined(Q_OS_SYMBIAN) //Guard against accidentally trying to load non-plugin libraries by making sure the stub exists diff --git a/src/corelib/tools/qcontiguouscache.cpp b/src/corelib/tools/qcontiguouscache.cpp index b0ed701..dd7cab6 100644 --- a/src/corelib/tools/qcontiguouscache.cpp +++ b/src/corelib/tools/qcontiguouscache.cpp @@ -56,6 +56,16 @@ void QContiguousCacheData::dump() const } #endif +QContiguousCacheData *QContiguousCacheData::allocate(int size, int alignment) +{ + return static_cast<QContiguousCacheData *>(qMallocAligned(size, alignment)); +} + +void QContiguousCacheData::free(QContiguousCacheData *data) +{ + qFreeAligned(data); +} + /*! \class QContiguousCache \brief The QContiguousCache class is a template class that provides a contiguous cache. \ingroup tools diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h index ad78d1f..3785938 100644 --- a/src/corelib/tools/qcontiguouscache.h +++ b/src/corelib/tools/qcontiguouscache.h @@ -62,6 +62,15 @@ struct Q_CORE_EXPORT QContiguousCacheData int start; int offset; uint sharable : 1; + uint reserved : 31; + + // total is 24 bytes (HP-UX aCC: 40 bytes) + // the next entry is already aligned to 8 bytes + // there will be an 8 byte gap here if T requires 16-byte alignment + // (such as long double on 64-bit platforms, __int128, __float128) + + static QContiguousCacheData *allocate(int size, int alignment); + static void free(QContiguousCacheData *data); #ifdef QT_QCONTIGUOUSCACHE_DEBUG void dump() const; @@ -69,33 +78,32 @@ struct Q_CORE_EXPORT QContiguousCacheData }; template <typename T> -struct QContiguousCacheTypedData +struct QContiguousCacheTypedData: private QContiguousCacheData { - QBasicAtomicInt ref; - int alloc; - int count; - int start; - int offset; - uint sharable : 1; - // uint unused : 31; - - // total is 24 bytes (HP-UX aCC: 40 bytes) - // the next entry is already aligned to 8 bytes - // there will be an 8 byte gap here if T requires 16-byte alignment - // (such as long double on 64-bit platforms, __int128, __float128) - + // private inheritance to avoid aliasing warningss T array[1]; + + static inline void free(QContiguousCacheTypedData *data) { QContiguousCacheData::free(data); } }; template<typename T> class QContiguousCache { typedef QContiguousCacheTypedData<T> Data; - union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; }; + union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; }; public: + // STL compatibility + typedef T value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef ptrdiff_t difference_type; + typedef int size_type; + explicit QContiguousCache(int capacity = 0); QContiguousCache(const QContiguousCache<T> &v) : d(v.d) { d->ref.ref(); if (!d->sharable) detach_helper(); } - inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) free(d); } + inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) free(p); } inline void detach() { if (d->ref != 1) detach_helper(); } inline bool isDetached() const { return d->ref == 1; } @@ -128,10 +136,10 @@ public: inline int firstIndex() const { return d->offset; } inline int lastIndex() const { return d->offset + d->count - 1; } - inline const T &first() const { Q_ASSERT(!isEmpty()); return d->array[d->start]; } - inline const T &last() const { Q_ASSERT(!isEmpty()); return d->array[(d->start + d->count -1) % d->alloc]; } - inline T &first() { Q_ASSERT(!isEmpty()); detach(); return d->array[d->start]; } - inline T &last() { Q_ASSERT(!isEmpty()); detach(); return d->array[(d->start + d->count -1) % d->alloc]; } + inline const T &first() const { Q_ASSERT(!isEmpty()); return p->array[d->start]; } + inline const T &last() const { Q_ASSERT(!isEmpty()); return p->array[(d->start + d->count -1) % d->alloc]; } + inline T &first() { Q_ASSERT(!isEmpty()); detach(); return p->array[d->start]; } + inline T &last() { Q_ASSERT(!isEmpty()); detach(); return p->array[(d->start + d->count -1) % d->alloc]; } void removeFirst(); T takeFirst(); @@ -156,23 +164,32 @@ private: // count the padding at the end return reinterpret_cast<const char *>(&(reinterpret_cast<const Data *>(this))->array[1]) - reinterpret_cast<const char *>(this); } + int alignOfTypedData() const + { +#ifdef Q_ALIGNOF + return qMax<int>(sizeof(void*), Q_ALIGNOF(Data)); +#else + return 0; +#endif + } }; template <typename T> void QContiguousCache<T>::detach_helper() { - union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; } x; + union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x; - x.p = malloc(d->alloc); + x.d = malloc(d->alloc); x.d->ref = 1; x.d->count = d->count; x.d->start = d->start; x.d->offset = d->offset; x.d->alloc = d->alloc; x.d->sharable = true; + x.d->reserved = 0; - T *dest = x.d->array + x.d->start; - T *src = d->array + d->start; + T *dest = x.p->array + x.d->start; + T *src = p->array + d->start; int oldcount = x.d->count; while (oldcount--) { if (QTypeInfo<T>::isComplex) { @@ -181,15 +198,15 @@ void QContiguousCache<T>::detach_helper() *dest = *src; } dest++; - if (dest == x.d->array + x.d->alloc) - dest = x.d->array; + if (dest == x.p->array + x.d->alloc) + dest = x.p->array; src++; - if (src == d->array + d->alloc) - src = d->array; + if (src == p->array + d->alloc) + src = p->array; } if (!d->ref.deref()) - free(d); + free(p); d = x.d; } @@ -199,14 +216,14 @@ void QContiguousCache<T>::setCapacity(int asize) if (asize == d->alloc) return; detach(); - union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; } x; - x.p = malloc(asize); + union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x; + x.d = malloc(asize); x.d->alloc = asize; x.d->count = qMin(d->count, asize); x.d->offset = d->offset + d->count - x.d->count; x.d->start = x.d->offset % x.d->alloc; - T *dest = x.d->array + (x.d->start + x.d->count-1) % x.d->alloc; - T *src = d->array + (d->start + d->count-1) % d->alloc; + T *dest = x.p->array + (x.d->start + x.d->count-1) % x.d->alloc; + T *src = p->array + (d->start + d->count-1) % d->alloc; int oldcount = x.d->count; while (oldcount--) { if (QTypeInfo<T>::isComplex) { @@ -214,15 +231,15 @@ void QContiguousCache<T>::setCapacity(int asize) } else { *dest = *src; } - if (dest == x.d->array) - dest = x.d->array + x.d->alloc; + if (dest == x.p->array) + dest = x.p->array + x.d->alloc; dest--; - if (src == d->array) - src = d->array + d->alloc; + if (src == p->array) + src = p->array + d->alloc; src--; } /* free old */ - free(d); + free(p); d = x.d; } @@ -232,24 +249,24 @@ void QContiguousCache<T>::clear() if (d->ref == 1) { if (QTypeInfo<T>::isComplex) { int oldcount = d->count; - T * i = d->array + d->start; - T * e = d->array + d->alloc; + T * i = p->array + d->start; + T * e = p->array + d->alloc; while (oldcount--) { i->~T(); i++; if (i == e) - i = d->array; + i = p->array; } } d->count = d->start = d->offset = 0; } else { - union { QContiguousCacheData *p; QContiguousCacheTypedData<T> *d; } x; - x.p = malloc(d->alloc); + union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x; + x.d = malloc(d->alloc); x.d->ref = 1; x.d->alloc = d->alloc; x.d->count = x.d->start = x.d->offset = 0; x.d->sharable = true; - if (!d->ref.deref()) free(d); + if (!d->ref.deref()) free(p); d = x.d; } } @@ -257,13 +274,13 @@ void QContiguousCache<T>::clear() template <typename T> inline QContiguousCacheData *QContiguousCache<T>::malloc(int aalloc) { - return static_cast<QContiguousCacheData *>(qMalloc(sizeOfTypedData() + (aalloc - 1) * sizeof(T))); + return QContiguousCacheData::allocate(sizeOfTypedData() + (aalloc - 1) * sizeof(T), alignOfTypedData()); } template <typename T> QContiguousCache<T>::QContiguousCache(int cap) { - p = malloc(cap); + d = malloc(cap); d->ref = 1; d->alloc = cap; d->count = d->start = d->offset = 0; @@ -303,16 +320,16 @@ void QContiguousCache<T>::free(Data *x) { if (QTypeInfo<T>::isComplex) { int oldcount = d->count; - T * i = d->array + d->start; - T * e = d->array + d->alloc; + T * i = p->array + d->start; + T * e = p->array + d->alloc; while (oldcount--) { i->~T(); i++; if (i == e) - i = d->array; + i = p->array; } } - qFree(x); + x->free(x); } template <typename T> void QContiguousCache<T>::append(const T &value) @@ -320,10 +337,10 @@ void QContiguousCache<T>::append(const T &value) detach(); if (QTypeInfo<T>::isComplex) { if (d->count == d->alloc) - (d->array + (d->start+d->count) % d->alloc)->~T(); - new (d->array + (d->start+d->count) % d->alloc) T(value); + (p->array + (d->start+d->count) % d->alloc)->~T(); + new (p->array + (d->start+d->count) % d->alloc) T(value); } else { - d->array[(d->start+d->count) % d->alloc] = value; + p->array[(d->start+d->count) % d->alloc] = value; } if (d->count == d->alloc) { @@ -349,12 +366,12 @@ void QContiguousCache<T>::prepend(const T &value) d->count++; else if (d->count == d->alloc) - (d->array + d->start)->~T(); + (p->array + d->start)->~T(); if (QTypeInfo<T>::isComplex) - new (d->array + d->start) T(value); + new (p->array + d->start) T(value); else - d->array[d->start] = value; + p->array[d->start] = value; } template<typename T> @@ -364,9 +381,9 @@ void QContiguousCache<T>::insert(int pos, const T &value) detach(); if (containsIndex(pos)) { if(QTypeInfo<T>::isComplex) - new (d->array + pos % d->alloc) T(value); + new (p->array + pos % d->alloc) T(value); else - d->array[pos % d->alloc] = value; + p->array[pos % d->alloc] = value; } else if (pos == d->offset-1) prepend(value); else if (pos == d->offset+d->count) @@ -378,18 +395,18 @@ void QContiguousCache<T>::insert(int pos, const T &value) d->start = pos % d->alloc; d->count = 1; if (QTypeInfo<T>::isComplex) - new (d->array + d->start) T(value); + new (p->array + d->start) T(value); else - d->array[d->start] = value; + p->array[d->start] = value; } } template <typename T> inline const T &QContiguousCache<T>::at(int pos) const -{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return d->array[pos % d->alloc]; } +{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return p->array[pos % d->alloc]; } template <typename T> inline const T &QContiguousCache<T>::operator[](int pos) const -{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return d->array[pos % d->alloc]; } +{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return p->array[pos % d->alloc]; } template <typename T> inline T &QContiguousCache<T>::operator[](int pos) @@ -397,7 +414,7 @@ inline T &QContiguousCache<T>::operator[](int pos) detach(); if (!containsIndex(pos)) insert(pos, T()); - return d->array[pos % d->alloc]; + return p->array[pos % d->alloc]; } template <typename T> @@ -407,7 +424,7 @@ inline void QContiguousCache<T>::removeFirst() detach(); d->count--; if (QTypeInfo<T>::isComplex) - (d->array + d->start)->~T(); + (p->array + d->start)->~T(); d->start = (d->start + 1) % d->alloc; d->offset++; } @@ -419,7 +436,7 @@ inline void QContiguousCache<T>::removeLast() detach(); d->count--; if (QTypeInfo<T>::isComplex) - (d->array + (d->start + d->count) % d->alloc)->~T(); + (p->array + (d->start + d->count) % d->alloc)->~T(); } template <typename T> diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index f33aba9..c82c389 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -166,29 +166,38 @@ static int countBits(int hint) const int MinNumBits = 4; QHashData QHashData::shared_null = { - 0, 0, Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0, MinNumBits, 0, 0, true + 0, 0, Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0, MinNumBits, 0, 0, true, false, 0 }; void *QHashData::allocateNode() { - void *ptr = qMalloc(nodeSize); + return allocateNode(0); +} + +void *QHashData::allocateNode(int nodeAlign) +{ + void *ptr = strictAlignment ? qMallocAligned(nodeSize, nodeAlign) : qMalloc(nodeSize); Q_CHECK_PTR(ptr); return ptr; } void QHashData::freeNode(void *node) { - qFree(node); + if (strictAlignment) + qFreeAligned(node); + else + qFree(node); } QHashData *QHashData::detach_helper(void (*node_duplicate)(Node *, void *), int nodeSize) { - return detach_helper( node_duplicate, 0, nodeSize ); + return detach_helper2( node_duplicate, 0, nodeSize, 0 ); } -QHashData *QHashData::detach_helper(void (*node_duplicate)(Node *, void *), - void (*node_delete)(Node *), - int nodeSize) +QHashData *QHashData::detach_helper2(void (*node_duplicate)(Node *, void *), + void (*node_delete)(Node *), + int nodeSize, + int nodeAlign) { union { QHashData *d; @@ -204,6 +213,8 @@ QHashData *QHashData::detach_helper(void (*node_duplicate)(Node *, void *), d->numBits = numBits; d->numBuckets = numBuckets; d->sharable = true; + d->strictAlignment = nodeAlign > 8; + d->reserved = 0; if (numBuckets) { QT_TRY { @@ -222,7 +233,7 @@ QHashData *QHashData::detach_helper(void (*node_duplicate)(Node *, void *), Node *oldNode = buckets[i]; while (oldNode != this_e) { QT_TRY { - Node *dup = static_cast<Node *>(allocateNode()); + Node *dup = static_cast<Node *>(allocateNode(nodeAlign)); QT_TRY { node_duplicate(oldNode, dup); @@ -262,6 +273,7 @@ void QHashData::free_helper(void (*node_delete)(Node *)) while (cur != this_e) { Node *next = cur->next; node_delete(cur); + freeNode(cur); cur = next; } } diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index b65f1d3..1918229 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -125,12 +125,15 @@ struct Q_CORE_EXPORT QHashData short numBits; int numBuckets; uint sharable : 1; + uint strictAlignment : 1; + uint reserved : 30; - void *allocateNode(); + void *allocateNode(); // ### Qt5 remove me + void *allocateNode(int nodeAlign); void freeNode(void *node); QHashData *detach_helper(void (*node_duplicate)(Node *, void *), int nodeSize); // ### Qt5 remove me - QHashData *detach_helper(void (*node_duplicate)(Node *, void *), void (*node_delete)(Node *), - int nodeSize); + QHashData *detach_helper2(void (*node_duplicate)(Node *, void *), void (*node_delete)(Node *), + int nodeSize, int nodeAlign); void mightGrow(); bool willGrow(); void hasShrunk(); @@ -267,6 +270,14 @@ class QHash return reinterpret_cast<Node *>(node); } +#ifdef Q_ALIGNOF + static inline int alignOfNode() { return qMax<int>(sizeof(void*), Q_ALIGNOF(Node)); } + static inline int alignOfDummyNode() { return qMax<int>(sizeof(void*), Q_ALIGNOF(DummyNode)); } +#else + static inline int alignOfNode() { return 0; } + static inline int alignOfDummyNode() { return 0; } +#endif + public: inline QHash() : d(&QHashData::shared_null) { d->ref.ref(); } inline QHash(const QHash<Key, T> &other) : d(other.d) { d->ref.ref(); if (!d->sharable) detach(); } @@ -483,7 +494,7 @@ private: Node **findNode(const Key &key, uint *hp = 0) const; Node *createNode(uint h, const Key &key, const T &value, Node **nextNode); void deleteNode(Node *node); - static void deleteNode(QHashData::Node *node); + static void deleteNode2(QHashData::Node *node); static void duplicateNode(QHashData::Node *originalNode, void *newNode); }; @@ -492,12 +503,12 @@ private: template <class Key, class T> Q_INLINE_TEMPLATE void QHash<Key, T>::deleteNode(Node *node) { - deleteNode(reinterpret_cast<QHashData::Node*>(node)); + deleteNode2(reinterpret_cast<QHashData::Node*>(node)); + d->freeNode(node); } - template <class Key, class T> -Q_INLINE_TEMPLATE void QHash<Key, T>::deleteNode(QHashData::Node *node) +Q_INLINE_TEMPLATE void QHash<Key, T>::deleteNode2(QHashData::Node *node) { #ifdef Q_CC_BOR concrete(node)->~QHashNode<Key, T>(); @@ -506,7 +517,6 @@ Q_INLINE_TEMPLATE void QHash<Key, T>::deleteNode(QHashData::Node *node) #else concrete(node)->~Node(); #endif - qFree(node); } template <class Key, class T> @@ -527,9 +537,9 @@ QHash<Key, T>::createNode(uint ah, const Key &akey, const T &avalue, Node **anex Node *node; if (QTypeInfo<T>::isDummy) { - node = reinterpret_cast<Node *>(new (d->allocateNode()) DummyNode(akey)); + node = reinterpret_cast<Node *>(new (d->allocateNode(alignOfDummyNode())) DummyNode(akey)); } else { - node = new (d->allocateNode()) Node(akey, avalue); + node = new (d->allocateNode(alignOfNode())) Node(akey, avalue); } node->h = ah; @@ -554,7 +564,7 @@ Q_INLINE_TEMPLATE QHash<Key, T> &QHash<Key, T>::unite(const QHash<Key, T> &other template <class Key, class T> Q_OUTOFLINE_TEMPLATE void QHash<Key, T>::freeData(QHashData *x) { - x->free_helper(deleteNode); + x->free_helper(deleteNode2); } template <class Key, class T> @@ -566,8 +576,9 @@ Q_INLINE_TEMPLATE void QHash<Key, T>::clear() template <class Key, class T> Q_OUTOFLINE_TEMPLATE void QHash<Key, T>::detach_helper() { - QHashData *x = d->detach_helper(duplicateNode, deleteNode, - QTypeInfo<T>::isDummy ? sizeof(DummyNode) : sizeof(Node)); + QHashData *x = d->detach_helper2(duplicateNode, deleteNode2, + QTypeInfo<T>::isDummy ? sizeof(DummyNode) : sizeof(Node), + QTypeInfo<T>::isDummy ? alignOfDummyNode() : alignOfNode()); if (!d->ref.deref()) freeData(d); d = x; diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp index 1385810..3b48c3f 100644 --- a/src/corelib/tools/qmap.cpp +++ b/src/corelib/tools/qmap.cpp @@ -53,11 +53,16 @@ QT_BEGIN_NAMESPACE QMapData QMapData::shared_null = { &shared_null, { &shared_null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0, 0, false, true + Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0, 0, false, true, false, 0 }; QMapData *QMapData::createData() { + return createData(0); +} + +QMapData *QMapData::createData(int alignment) +{ QMapData *d = new QMapData; Q_CHECK_PTR(d); Node *e = reinterpret_cast<Node *>(d); @@ -69,6 +74,8 @@ QMapData *QMapData::createData() d->randomBits = 0; d->insertInOrder = false; d->sharable = true; + d->strictAlignment = alignment > 8; + d->reserved = 0; return d; } @@ -80,11 +87,19 @@ void QMapData::continueFreeData(int offset) while (cur != e) { prev = cur; cur = cur->forward[0]; - qFree(reinterpret_cast<char *>(prev) - offset); + if (strictAlignment) + qFreeAligned(reinterpret_cast<char *>(prev) - offset); + else + qFree(reinterpret_cast<char *>(prev) - offset); } delete this; } +QMapData::Node *QMapData::node_create(Node *update[], int offset) +{ + return node_create(update, offset, 0); +} + /*! Creates a new node inside the data structure. @@ -94,10 +109,12 @@ void QMapData::continueFreeData(int offset) \a offset is an amount of bytes that needs to reserved just before the QMapData::Node structure. + \a alignment dictates the alignment for the data. + \internal \since 4.6 */ -QMapData::Node *QMapData::node_create(Node *update[], int offset) +QMapData::Node *QMapData::node_create(Node *update[], int offset, int alignment) { int level = 0; uint mask = (1 << Sparseness) - 1; @@ -118,7 +135,9 @@ QMapData::Node *QMapData::node_create(Node *update[], int offset) if (level == 3 && !insertInOrder) randomBits = qrand(); - void *concreteNode = qMalloc(offset + sizeof(Node) + level * sizeof(Node *)); + void *concreteNode = strictAlignment ? + qMallocAligned(offset + sizeof(Node) + level * sizeof(Node *), alignment) : + qMalloc(offset + sizeof(Node) + level * sizeof(Node *)); Q_CHECK_PTR(concreteNode); Node *abstractNode = reinterpret_cast<Node *>(reinterpret_cast<char *>(concreteNode) + offset); @@ -145,7 +164,10 @@ void QMapData::node_delete(Node *update[], int offset, Node *node) update[i]->forward[i] = node->forward[i]; } --size; - qFree(reinterpret_cast<char *>(node) - offset); + if (strictAlignment) + qFreeAligned(reinterpret_cast<char *>(node) - offset); + else + qFree(reinterpret_cast<char *>(node) - offset); } #ifdef QT_QMAP_DEBUG diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index 688aca6..65c3d2a 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -74,10 +74,14 @@ struct Q_CORE_EXPORT QMapData uint randomBits; uint insertInOrder : 1; uint sharable : 1; + uint strictAlignment : 1; + uint reserved : 29; - static QMapData *createData(); + static QMapData *createData(); // ### Qt5 remove me + static QMapData *createData(int alignment); void continueFreeData(int offset); - Node *node_create(Node *update[], int offset); + Node *node_create(Node *update[], int offset); // ### Qt5 remove me + Node *node_create(Node *update[], int offset, int alignment); void node_delete(Node *update[], int offset, Node *node); #ifdef QT_QMAP_DEBUG uint adjust_ptr(Node *node); @@ -145,6 +149,13 @@ class QMap }; static inline int payload() { return sizeof(PayloadNode) - sizeof(QMapData::Node *); } + static inline int alignment() { +#ifdef Q_ALIGNOF + return qMax(sizeof(void*), Q_ALIGNOF(Node)); +#else + return 0; +#endif + } static inline Node *concrete(QMapData::Node *node) { return reinterpret_cast<Node *>(reinterpret_cast<char *>(node) - payload()); } @@ -414,7 +425,7 @@ template <class Key, class T> Q_INLINE_TEMPLATE typename QMapData::Node * QMap<Key, T>::node_create(QMapData *adt, QMapData::Node *aupdate[], const Key &akey, const T &avalue) { - QMapData::Node *abstractNode = adt->node_create(aupdate, payload()); + QMapData::Node *abstractNode = adt->node_create(aupdate, payload(), alignment()); QT_TRY { Node *concreteNode = concrete(abstractNode); new (&concreteNode->key) Key(akey); @@ -715,7 +726,7 @@ template <class Key, class T> Q_OUTOFLINE_TEMPLATE void QMap<Key, T>::detach_helper() { union { QMapData *d; QMapData::Node *e; } x; - x.d = QMapData::createData(); + x.d = QMapData::createData(alignment()); if (d->size) { x.d->insertInOrder = true; QMapData::Node *update[QMapData::LastLevel + 1]; @@ -905,7 +916,7 @@ Q_OUTOFLINE_TEMPLATE bool QMap<Key, T>::operator==(const QMap<Key, T> &other) co template <class Key, class T> Q_OUTOFLINE_TEMPLATE QMap<Key, T>::QMap(const std::map<Key, T> &other) { - d = QMapData::createData(); + d = QMapData::createData(alignment()); d->insertInOrder = true; typename std::map<Key,T>::const_iterator it = other.end(); while (it != other.begin()) { diff --git a/src/corelib/tools/qvector.cpp b/src/corelib/tools/qvector.cpp index 20f3a80..8bb1074 100644 --- a/src/corelib/tools/qvector.cpp +++ b/src/corelib/tools/qvector.cpp @@ -45,7 +45,14 @@ QT_BEGIN_NAMESPACE -QVectorData QVectorData::shared_null = { Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0, true, false }; +static inline int alignmentThreshold() +{ + // malloc on 32-bit platforms should return pointers that are 8-byte aligned or more + // while on 64-bit platforms they should be 16-byte aligned or more + return 2 * sizeof(void*); +} + +QVectorData QVectorData::shared_null = { Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0, true, false, 0 }; QVectorData *QVectorData::malloc(int sizeofTypedData, int size, int sizeofT, QVectorData *init) { @@ -55,6 +62,26 @@ QVectorData *QVectorData::malloc(int sizeofTypedData, int size, int sizeofT, QVe return p; } +QVectorData *QVectorData::allocate(int size, int alignment) +{ + return static_cast<QVectorData *>(alignment > alignmentThreshold() ? qMallocAligned(size, alignment) : qMalloc(size)); +} + +QVectorData *QVectorData::reallocate(QVectorData *x, int newsize, int oldsize, int alignment) +{ + if (alignment > alignmentThreshold()) + return static_cast<QVectorData *>(qReallocAligned(x, newsize, oldsize, alignment)); + return static_cast<QVectorData *>(qRealloc(x, newsize)); +} + +void QVectorData::free(QVectorData *x, int alignment) +{ + if (alignment > alignmentThreshold()) + qFreeAligned(x); + else + qFree(x); +} + int QVectorData::grow(int sizeofTypedData, int size, int sizeofT, bool excessive) { if (excessive) diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index b77b53a..7402d77 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -72,6 +72,7 @@ struct Q_CORE_EXPORT QVectorData #else uint sharable : 1; uint capacity : 1; + uint reserved : 30; #endif static QVectorData shared_null; @@ -79,6 +80,9 @@ struct Q_CORE_EXPORT QVectorData // some debugges when the QVector is member of a class within an unnamed namespace. // ### Qt 5: can be removed completely. (Ralf) static QVectorData *malloc(int sizeofTypedData, int size, int sizeofT, QVectorData *init); + static QVectorData *allocate(int size, int alignment); + static QVectorData *reallocate(QVectorData *old, int newsize, int oldsize, int alignment); + static void free(QVectorData *data, int alignment); static int grow(int sizeofTypedData, int size, int sizeofT, bool excessive); }; @@ -87,6 +91,8 @@ struct QVectorTypedData : private QVectorData { // private inheritance as we must not access QVectorData member thought QVectorTypedData // as this would break strict aliasing rules. (in the case of shared_null) T array[1]; + + static inline void free(QVectorTypedData *x, int alignment) { QVectorData::free(x, alignment); } }; class QRegion; @@ -302,6 +308,14 @@ private: // count the padding at the end return reinterpret_cast<const char *>(&(reinterpret_cast<const Data *>(this))->array[1]) - reinterpret_cast<const char *>(this); } + inline int alignOfTypedData() const + { +#ifdef Q_ALIGNOF + return qMax<int>(sizeof(void*), Q_ALIGNOF(Data)); +#else + return 0; +#endif + } }; template <typename T> @@ -373,7 +387,7 @@ QVector<T> &QVector<T>::operator=(const QVector<T> &v) template <typename T> inline QVectorData *QVector<T>::malloc(int aalloc) { - QVectorData *vectordata = static_cast<QVectorData *>(qMalloc(sizeOfTypedData() + (aalloc - 1) * sizeof(T))); + QVectorData *vectordata = QVectorData::allocate(sizeOfTypedData() + (aalloc - 1) * sizeof(T), alignOfTypedData()); Q_CHECK_PTR(vectordata); return vectordata; } @@ -420,7 +434,7 @@ void QVector<T>::free(Data *x) while (i-- != b) i->~T(); } - qFree(x); + x->free(x, alignOfTypedData()); } template <typename T> @@ -459,7 +473,8 @@ void QVector<T>::realloc(int asize, int aalloc) } } else { QT_TRY { - QVectorData *mem = static_cast<QVectorData *>(qRealloc(p, sizeOfTypedData() + (aalloc - 1) * sizeof(T))); + QVectorData *mem = QVectorData::reallocate(d, sizeOfTypedData() + (aalloc - 1) * sizeof(T), + sizeOfTypedData() + (d->alloc - 1) * sizeof(T), alignOfTypedData()); Q_CHECK_PTR(mem); x.d = d = mem; x.d->size = d->size; @@ -472,6 +487,7 @@ void QVector<T>::realloc(int asize, int aalloc) x.d->alloc = aalloc; x.d->sharable = true; x.d->capacity = d->capacity; + x.d->reserved = 0; } if (QTypeInfo<T>::isComplex) { |