Reduce size of QQmlNotifierEndpoint
authorAaron Kennedy <aaron.kennedy@nokia.com>
Fri, 18 May 2012 10:11:40 +0000 (11:11 +0100)
committerQt by Nokia <qt-info@nokia.com>
Thu, 24 May 2012 15:49:58 +0000 (17:49 +0200)
Change-Id: I4d4a22f5f3d88d4ad2fcd738753fd8da2d8a9263
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
src/qml/qml/qqmlboundsignal.cpp
src/qml/qml/qqmlboundsignal_p.h
src/qml/qml/qqmlengine_p.h
src/qml/qml/qqmljavascriptexpression.cpp
src/qml/qml/qqmljavascriptexpression_p.h
src/qml/qml/qqmlnotifier.cpp
src/qml/qml/qqmlnotifier_p.h
src/qml/qml/qqmlvmemetaobject.cpp
src/qml/qml/v4/qv4bindings.cpp
src/qml/qml/v4/qv4bindings_p.h

index 1a16c07..bc8ce07 100644 (file)
@@ -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<QQmlBoundSignal*>(e);
     if (!s->m_expression)
index b7f3e5f..81bcb0b 100644 (file)
@@ -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.
index 0631fe0..4518ba8 100644 (file)
@@ -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();
index 5b1261b..d021882 100644 (file)
@@ -368,4 +368,12 @@ void QQmlJavaScriptExpression::clearGuards()
         g->Delete();
 }
 
+void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *e, void **)
+{
+    QQmlJavaScriptExpression *expression =
+        static_cast<QQmlJavaScriptExpressionGuard *>(e)->expression;
+
+    expression->m_vtable->expressionChanged(expression);
+}
+
 QT_END_NAMESPACE
index 12be382..4208584 100644 (file)
@@ -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<QQmlJavaScriptExpressionGuard *>(e)->expression;
-
-    expression->m_vtable->expressionChanged(expression);
+    setCallback(QQmlNotifierEndpoint::QQmlJavaScriptExpressionGuard);
 }
 
 QQmlJavaScriptExpressionGuard *
index 2bae7f6..7cbc5e6 100644 (file)
 
 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);
index e942861..49bf9ed 100644 (file)
@@ -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 = &notifier->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
index e0d7972..50fda6d 100644 (file)
@@ -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<QQmlVMEMetaObjectEndpoint*>(e);
     vmee->tryConnect();
index 95eb0b9..39b571f 100644 (file)
@@ -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<Subscription *>(e);
+    setCallback(QQmlNotifierEndpoint::QV4BindingsSubscription);
+}
+
+void QV4BindingsSubscription_callback(QQmlNotifierEndpoint *e, void **)
+{
+    QV4Bindings::Subscription *s = static_cast<QV4Bindings::Subscription *>(e);
     s->bindings->subscriptionNotify(s->method);
 }
 
index be58e02..d2d8520 100644 (file)
@@ -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;