From 72ac68162e4ab94bb2b62e047a726c119f77df13 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 18 May 2012 11:11:40 +0100 Subject: [PATCH] Reduce size of QQmlNotifierEndpoint Change-Id: I4d4a22f5f3d88d4ad2fcd738753fd8da2d8a9263 Reviewed-by: Roberto Raggi --- src/qml/qml/qqmlboundsignal.cpp | 4 +- src/qml/qml/qqmlboundsignal_p.h | 4 +- src/qml/qml/qqmlengine_p.h | 3 +- src/qml/qml/qqmljavascriptexpression.cpp | 8 ++++ src/qml/qml/qqmljavascriptexpression_p.h | 12 +----- src/qml/qml/qqmlnotifier.cpp | 46 ++++++++++++++------ src/qml/qml/qqmlnotifier_p.h | 73 +++++++++++++++++++++----------- src/qml/qml/qqmlvmemetaobject.cpp | 4 +- src/qml/qml/v4/qv4bindings.cpp | 10 ++++- src/qml/qml/v4/qv4bindings_p.h | 5 +-- 10 files changed, 108 insertions(+), 61 deletions(-) diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 1a16c07..bc8ce07 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -249,7 +249,7 @@ QQmlBoundSignal::QQmlBoundSignal(QObject *scope, int signal, QObject *owner, setParamsValid(false); setIsEvaluating(false); addToObject(owner); - callback = &subscriptionCallback; + setCallback(QQmlNotifierEndpoint::QQmlBoundSignal); /* If this is a cloned method, connect to the 'original'. For example, @@ -318,7 +318,7 @@ QQmlBoundSignalExpressionPointer QQmlBoundSignal::takeExpression(QQmlBoundSignal return rv; } -void QQmlBoundSignal::subscriptionCallback(QQmlNotifierEndpoint *e, void **a) +void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a) { QQmlBoundSignal *s = static_cast(e); if (!s->m_expression) diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h index b7f3e5f..81bcb0b 100644 --- a/src/qml/qml/qqmlboundsignal_p.h +++ b/src/qml/qml/qqmlboundsignal_p.h @@ -147,11 +147,11 @@ public: QQmlBoundSignalExpressionPointer takeExpression(QQmlBoundSignalExpression *); QObject *scope() { return *m_scope; } - static void subscriptionCallback(QQmlNotifierEndpoint *e, void **); - bool isEvaluating() const { return m_scope.flag(); } private: + friend void QQmlBoundSignal_callback(QQmlNotifierEndpoint *, void **); + QQmlBoundSignalExpressionPointer m_expression; QQmlBoundSignalParameters *m_params; // We store some flag bits in the following flag pointer. diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 0631fe0..4518ba8 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -103,13 +103,12 @@ class QDir; class QQmlIncubator; // This needs to be declared here so that the pool for it can live in QQmlEnginePrivate. -// The inline method definitions are in qqmlexpression_p.h +// The inline method definitions are in qqmljavascriptexpression_p.h class QQmlJavaScriptExpressionGuard : public QQmlNotifierEndpoint { public: inline QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *); - static inline void endpointCallback(QQmlNotifierEndpoint *, void **); static inline QQmlJavaScriptExpressionGuard *New(QQmlJavaScriptExpression *e, QQmlEngine *engine); inline void Delete(); diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 5b1261b..d021882 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -368,4 +368,12 @@ void QQmlJavaScriptExpression::clearGuards() g->Delete(); } +void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *e, void **) +{ + QQmlJavaScriptExpression *expression = + static_cast(e)->expression; + + expression->m_vtable->expressionChanged(expression); +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index 12be382..4208584 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -146,7 +146,7 @@ protected: private: typedef QQmlJavaScriptExpressionGuard Guard; - friend class QQmlJavaScriptExpressionGuard; + friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **); struct GuardCapture : public QQmlEnginePrivate::PropertyCapture { GuardCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e) @@ -253,15 +253,7 @@ bool QQmlJavaScriptExpression::hasDelayedError() const QQmlJavaScriptExpressionGuard::QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *e) : expression(e), next(0) { - callback = &endpointCallback; -} - -void QQmlJavaScriptExpressionGuard::endpointCallback(QQmlNotifierEndpoint *e, void **) -{ - QQmlJavaScriptExpression *expression = - static_cast(e)->expression; - - expression->m_vtable->expressionChanged(expression); + setCallback(QQmlNotifierEndpoint::QQmlJavaScriptExpressionGuard); } QQmlJavaScriptExpressionGuard * diff --git a/src/qml/qml/qqmlnotifier.cpp b/src/qml/qml/qqmlnotifier.cpp index 2bae7f6..7cbc5e6 100644 --- a/src/qml/qml/qqmlnotifier.cpp +++ b/src/qml/qml/qqmlnotifier.cpp @@ -46,27 +46,47 @@ QT_BEGIN_NAMESPACE +typedef void (*Callback)(QQmlNotifierEndpoint *, void **); + +void QQmlBoundSignal_callback(QQmlNotifierEndpoint *, void **); +void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **); +void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *, void **); +void QV4BindingsSubscription_callback(QQmlNotifierEndpoint *, void **); + +static Callback QQmlNotifier_callbacks[] = { + 0, + QQmlBoundSignal_callback, + QQmlJavaScriptExpressionGuard_callback, + QQmlVMEMetaObjectEndpoint_callback, + QV4BindingsSubscription_callback +}; + void QQmlNotifier::emitNotify(QQmlNotifierEndpoint *endpoint, void **a) { - QQmlNotifierEndpoint **oldDisconnected = endpoint->disconnected; - endpoint->disconnected = &endpoint; - endpoint->notifying = 1; + intptr_t originalSenderPtr; + intptr_t *disconnectWatch; + + if (!endpoint->isNotifying()) { + originalSenderPtr = endpoint->senderPtr; + disconnectWatch = &originalSenderPtr; + endpoint->senderPtr = intptr_t(disconnectWatch) | 0x1; + } else { + disconnectWatch = (intptr_t *)(endpoint->senderPtr & ~0x1); + } if (endpoint->next) emitNotify(endpoint->next, a); - if (endpoint) { + if (*disconnectWatch) { - Q_ASSERT(endpoint->callback); - - endpoint->callback(endpoint, a); + Q_ASSERT(QQmlNotifier_callbacks[endpoint->callback]); + QQmlNotifier_callbacks[endpoint->callback](endpoint, a); - if (endpoint) - endpoint->disconnected = oldDisconnected; + if (disconnectWatch == &originalSenderPtr && originalSenderPtr) { + // End of notifying, restore values + endpoint->senderPtr = originalSenderPtr; + } } - - if (oldDisconnected) *oldDisconnected = endpoint; - else if (endpoint) endpoint->notifying = 0; } void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine *engine) @@ -89,7 +109,7 @@ void QQmlNotifierEndpoint::connect(QObject *source, int sourceSignal, QQmlEngine qPrintable(engineName)); } - this->source = source; + senderPtr = intptr_t(source); this->sourceSignal = sourceSignal; QQmlPropertyPrivate::flushSignal(source, sourceSignal); QQmlData *ddata = QQmlData::get(source, true); diff --git a/src/qml/qml/qqmlnotifier_p.h b/src/qml/qml/qqmlnotifier_p.h index e942861..49bf9ed 100644 --- a/src/qml/qml/qqmlnotifier_p.h +++ b/src/qml/qml/qqmlnotifier_p.h @@ -70,8 +70,19 @@ public: inline QQmlNotifierEndpoint(); inline ~QQmlNotifierEndpoint(); - typedef void (*Callback)(QQmlNotifierEndpoint *, void **); - Callback callback; + // QQmlNotifierEndpoint can only invoke one of a set of pre-defined callbacks. + // To add another callback, extend this enum and add the callback to the top + // of qqmlnotifier.cpp. Four bits are reserved for the callback, so there can + // be up to 15 of them (0 is reserved). + enum Callback { + None = 0, + QQmlBoundSignal = 1, + QQmlJavaScriptExpressionGuard = 2, + QQmlVMEMetaObjectEndpoint = 3, + QV4BindingsSubscription = 4 + }; + + inline void setCallback(Callback c) { callback = c; } inline bool isConnected(); inline bool isConnected(QObject *source, int sourceSignal); @@ -88,13 +99,16 @@ private: friend class QQmlData; friend class QQmlNotifier; - union { - QQmlNotifier *notifier; - QObject *source; - }; - unsigned int notifying : 1; - signed int sourceSignal : 31; - QQmlNotifierEndpoint **disconnected; + // Contains either the QObject*, or the QQmlNotifier* that this + // endpoint is connected to. While the endpoint is notifying, the + // senderPtr points to another intptr_t that contains this value. + intptr_t senderPtr; + inline QObject *senderAsObject() const; + inline QQmlNotifier *senderAsNotifier() const; + + Callback callback:4; + signed int sourceSignal:28; + QQmlNotifierEndpoint *next; QQmlNotifierEndpoint **prev; }; @@ -111,12 +125,12 @@ QQmlNotifier::~QQmlNotifier() QQmlNotifierEndpoint *n = endpoint; endpoint = n->next; + if (n->isNotifying()) *((intptr_t *)(n->senderPtr & ~0x1)) = 0; + n->next = 0; n->prev = 0; - n->notifier = 0; + n->senderPtr = 0; n->sourceSignal = -1; - if (n->disconnected) *n->disconnected = 0; - n->disconnected = 0; } endpoints = 0; } @@ -128,7 +142,7 @@ void QQmlNotifier::notify() } QQmlNotifierEndpoint::QQmlNotifierEndpoint() -: callback(0), notifier(0), notifying(0), sourceSignal(-1), disconnected(0), next(0), prev(0) +: senderPtr(0), callback(None), sourceSignal(-1), next(0), prev(0) { } @@ -144,12 +158,13 @@ bool QQmlNotifierEndpoint::isConnected() bool QQmlNotifierEndpoint::isConnected(QObject *source, int sourceSignal) { - return this->sourceSignal != -1 && this->source == source && this->sourceSignal == sourceSignal; + return this->sourceSignal != -1 && senderAsObject() == source && + this->sourceSignal == sourceSignal; } bool QQmlNotifierEndpoint::isConnected(QQmlNotifier *notifier) { - return sourceSignal == -1 && this->notifier == notifier; + return sourceSignal == -1 && senderAsNotifier() == notifier; } void QQmlNotifierEndpoint::connect(QQmlNotifier *notifier) @@ -160,19 +175,17 @@ void QQmlNotifierEndpoint::connect(QQmlNotifier *notifier) if (next) { next->prev = &next; } notifier->endpoints = this; prev = ¬ifier->endpoints; - this->notifier = notifier; + senderPtr = intptr_t(notifier); } void QQmlNotifierEndpoint::disconnect() { if (next) next->prev = prev; if (prev) *prev = next; - if (disconnected) *disconnected = 0; + if (isNotifying()) *((intptr_t *)(senderPtr & ~0x1)) = 0; next = 0; prev = 0; - disconnected = 0; - notifier = 0; - notifying = 0; + senderPtr = 0; sourceSignal = -1; } @@ -185,7 +198,7 @@ An in progress notify can be cancelled by calling cancelNotify. */ bool QQmlNotifierEndpoint::isNotifying() const { - return notifying == 1; + return senderPtr & 0x1; } /*! @@ -193,13 +206,23 @@ Cancel any notifies that are in progress. */ void QQmlNotifierEndpoint::cancelNotify() { - notifying = 0; - if (disconnected) { - *disconnected = 0; - disconnected = 0; + if (isNotifying()) { + intptr_t sp = *((intptr_t *)(senderPtr & ~0x1)); + *((intptr_t *)(senderPtr & ~0x1)) = 0; + senderPtr = sp; } } +QObject *QQmlNotifierEndpoint::senderAsObject() const +{ + return isNotifying()?((QObject *)(*((intptr_t *)(senderPtr & ~0x1)))):((QObject *)senderPtr); +} + +QQmlNotifier *QQmlNotifierEndpoint::senderAsNotifier() const +{ + return isNotifying()?((QQmlNotifier *)(*((intptr_t *)(senderPtr & ~0x1)))):((QQmlNotifier *)senderPtr); +} + QT_END_NAMESPACE #endif // QQMLNOTIFIER_P_H diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index e0d7972..50fda6d 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -446,10 +446,10 @@ void QQmlVMEVariant::ensureValueType(int t) QQmlVMEMetaObjectEndpoint::QQmlVMEMetaObjectEndpoint() { - callback = &vmecallback; + setCallback(QQmlNotifierEndpoint::QQmlVMEMetaObjectEndpoint); } -void QQmlVMEMetaObjectEndpoint::vmecallback(QQmlNotifierEndpoint *e, void **) +void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *e, void **) { QQmlVMEMetaObjectEndpoint *vmee = static_cast(e); vmee->tryConnect(); diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp index 95eb0b9..39b571f 100644 --- a/src/qml/qml/v4/qv4bindings.cpp +++ b/src/qml/qml/v4/qv4bindings.cpp @@ -349,9 +349,15 @@ void QV4Bindings::Binding::retargetBinding(QObject *t, int i) target.value().targetProperty = i; } -void QV4Bindings::Subscription::subscriptionCallback(QQmlNotifierEndpoint *e, void **) +QV4Bindings::Subscription::Subscription() +: bindings(0), method(-1) { - Subscription *s = static_cast(e); + setCallback(QQmlNotifierEndpoint::QV4BindingsSubscription); +} + +void QV4BindingsSubscription_callback(QQmlNotifierEndpoint *e, void **) +{ + QV4Bindings::Subscription *s = static_cast(e); s->bindings->subscriptionNotify(s->method); } diff --git a/src/qml/qml/v4/qv4bindings_p.h b/src/qml/qml/v4/qv4bindings_p.h index be58e02..d2d8520 100644 --- a/src/qml/qml/v4/qv4bindings_p.h +++ b/src/qml/qml/v4/qv4bindings_p.h @@ -117,12 +117,11 @@ private: class Subscription : public QQmlNotifierEndpoint { public: - Subscription() : bindings(0), method(-1) { callback = &subscriptionCallback; } - static void subscriptionCallback(QQmlNotifierEndpoint *e, void**); + inline Subscription(); QV4Bindings *bindings; int method; }; - friend class Subscription; + friend void QV4BindingsSubscription_callback(QQmlNotifierEndpoint *e, void **); Subscription *subscriptions; -- 2.7.4