From cba3378732049a943e044039bde3aab1707ccca1 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 22 Jun 2016 22:00:08 -0700 Subject: Make QDateTime's default constructor not allocate memory on 32-bit Commit fb498a651990df5e04c75a9076da28e875c43f73 introduced the short datetime optimization, but it accidentally removed the optimization from Qt 5.7 that made QDateTime's default constructor not allocate memory. Instead of bringing back the Q_GLOBAL_STATIC that was used, let's use the short date time optimization on 32-bit too. The CanBeSmall constant remains false on 32-bit systems, but judicious non-use of that constant in a few functions allows 32-bit systems to use the optimization. We still say that any date/time value is "unsmall", as there's no sense in calculating whether the date is between 1970-01-01 and July 14 of the same year. Change-Id: I413d458307aa46469b80fffd145a9db0325c08cc Reviewed-by: Edward Welbourne --- src/corelib/tools/qdatetime.cpp | 72 +++++++++++++++++++++++++---------------- src/corelib/tools/qdatetime.h | 1 + 2 files changed, 46 insertions(+), 27 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 57de7a8f6e..d6b90efb33 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -2487,6 +2487,16 @@ static inline bool specCanBeSmall(Qt::TimeSpec spec) return spec == Qt::LocalTime || spec == Qt::UTC; } +static inline bool msecsCanBeSmall(qint64 msecs) +{ + if (!QDateTimeData::CanBeSmall) + return false; + + ShortData sd; + sd.msecs = qintptr(msecs); + return sd.msecs == msecs; +} + static Q_DECL_CONSTEXPR inline QDateTimePrivate::StatusFlags mergeSpec(QDateTimePrivate::StatusFlags status, Qt::TimeSpec spec) { @@ -2693,9 +2703,9 @@ static void setDateTime(QDateTimeData &d, const QDate &date, const QTime &time) qint64 msecs = (days * MSECS_PER_DAY) + ds; if (d.isShort()) { // let's see if we can keep this short - d.data.msecs = qintptr(msecs); - if (d.data.msecs == msecs) { + if (msecsCanBeSmall(msecs)) { // yes, we can + d.data.msecs = qintptr(msecs); d.data.status &= ~(QDateTimePrivate::ValidityMask | QDateTimePrivate::DaylightMask); d.data.status |= newStatus; } else { @@ -2734,6 +2744,15 @@ static QPair getDateTime(const QDateTimeData &d) QDateTime::Data member functions *****************************************************************************/ +inline QDateTime::Data::Data() +{ + // default-constructed data has a special exception: + // it can be small even if CanBeSmall == false + // (optimization so we don't allocate memory in the default constructor) + quintptr value = quintptr(mergeSpec(QDateTimePrivate::ShortData, Qt::LocalTime)); + d = reinterpret_cast(value); +} + inline QDateTime::Data::Data(Qt::TimeSpec spec) { if (CanBeSmall && Q_LIKELY(specCanBeSmall(spec))) { @@ -2751,9 +2770,9 @@ inline QDateTime::Data::Data(const Data &other) { if (!isShort()) { // check if we could shrink - ShortData sd; - sd.msecs = qintptr(d->m_msecs); - if (CanBeSmall && specCanBeSmall(extractSpec(d->m_status)) && sd.msecs == d->m_msecs) { + if (specCanBeSmall(extractSpec(d->m_status)) && msecsCanBeSmall(d->m_msecs)) { + ShortData sd; + sd.msecs = qintptr(d->m_msecs); sd.status = d->m_status | QDateTimePrivate::ShortData; data = sd; } else { @@ -2766,15 +2785,10 @@ inline QDateTime::Data::Data(const Data &other) inline QDateTime::Data::Data(Data &&other) : d(other.d) { - // reset the other to a short state, if we can - if (CanBeSmall) { - Data dummy(Qt::LocalTime); - Q_ASSERT(dummy.isShort()); - other.d = dummy.d; - } else if (!isShort()) { - // can't be small, so do implicit sharing - d->ref.ref(); - } + // reset the other to a short state + Data dummy; + Q_ASSERT(dummy.isShort()); + other.d = dummy.d; } inline QDateTime::Data &QDateTime::Data::operator=(const Data &other) @@ -2786,9 +2800,9 @@ inline QDateTime::Data &QDateTime::Data::operator=(const Data &other) d = other.d; if (!other.isShort()) { // check if we could shrink - ShortData sd; - sd.msecs = qintptr(other.d->m_msecs); - if (CanBeSmall && specCanBeSmall(extractSpec(other.d->m_status)) && sd.msecs == other.d->m_msecs) { + if (specCanBeSmall(extractSpec(other.d->m_status)) && msecsCanBeSmall(other.d->m_msecs)) { + ShortData sd; + sd.msecs = qintptr(other.d->m_msecs); sd.status = other.d->m_status | QDateTimePrivate::ShortData; data = sd; } else { @@ -2797,7 +2811,7 @@ inline QDateTime::Data &QDateTime::Data::operator=(const Data &other) } } - if (!(CanBeSmall && quintptr(x) & QDateTimePrivate::ShortData) && !x->ref.deref()) + if (!(quintptr(x) & QDateTimePrivate::ShortData) && !x->ref.deref()) delete x; return *this; } @@ -2810,7 +2824,13 @@ inline QDateTime::Data::~Data() inline bool QDateTime::Data::isShort() const { - return CanBeSmall && quintptr(d) & QDateTimePrivate::ShortData; + bool b = quintptr(d) & QDateTimePrivate::ShortData; + + // even if CanBeSmall = false, we have short data for a default-constructed + // QDateTime object. But it's unlikely. + if (CanBeSmall) + return Q_LIKELY(b); + return Q_UNLIKELY(b); } inline void QDateTime::Data::detach() @@ -3030,7 +3050,6 @@ inline qint64 QDateTimePrivate::zoneMSecsToEpochMSecs(qint64 zoneMSecs, const QT \sa isValid() */ QDateTime::QDateTime() Q_DECL_NOEXCEPT_EXPR(Data::CanBeSmall) - : d(Qt::LocalTime) { } @@ -3618,12 +3637,10 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs) } } - ShortData sd; - sd.msecs = msecs; - if (d.isShort() && sd.msecs == msecs) { + if (msecsCanBeSmall(msecs) && d.isShort()) { // we can keep short - sd.status = status; - d.data = sd; + d.data.msecs = qintptr(msecs); + d.data.status = status; } else { d.detach(); d->m_status = status; @@ -4006,8 +4023,9 @@ QDateTime QDateTime::addMSecs(qint64 msecs) const if (d.isShort()) { // need to check if we need to enlarge first msecs += dt.d.data.msecs; - dt.d.data.msecs = qintptr(msecs); - if (dt.d.data.msecs != msecs) { + if (msecsCanBeSmall(msecs)) { + dt.d.data.msecs = qintptr(msecs); + } else { dt.d.detach(); dt.d->m_msecs = msecs; } diff --git a/src/corelib/tools/qdatetime.h b/src/corelib/tools/qdatetime.h index 7111509bcc..ec0eaa1edf 100644 --- a/src/corelib/tools/qdatetime.h +++ b/src/corelib/tools/qdatetime.h @@ -230,6 +230,7 @@ class Q_CORE_EXPORT QDateTime CanBeSmall = sizeof(ShortData) * 8 > 50 }; + Data(); Data(Qt::TimeSpec); Data(const Data &other); Data(Data &&other); -- cgit v1.2.3