diff --git a/gobject/gobject.c b/gobject/gobject.c index 3079d5df1..cf9d908cb 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -213,14 +213,14 @@ static void object_interface_check_properties (gpointer check_d gpointer g_iface); /* --- typedefs --- */ -typedef struct _GObjectNotifyQueue GObjectNotifyQueue; -struct _GObjectNotifyQueue +typedef struct { - GSList *pspecs; - guint16 n_pspecs; - guint16 freeze_count; -}; + guint16 freeze_count; + guint16 len; + guint16 alloc; + GParamSpec *pspecs[]; +} GObjectNotifyQueue; /* --- variables --- */ static GQuark quark_closure_array = 0; @@ -656,13 +656,11 @@ object_bit_unlock (GObject *object, guint lock_bit) } /* --- functions --- */ -static void -g_object_notify_queue_free (gpointer data) -{ - GObjectNotifyQueue *nqueue = data; - g_slist_free (nqueue->pspecs); - g_free_sized (nqueue, sizeof (GObjectNotifyQueue)); +G_ALWAYS_INLINE static inline gsize +g_object_notify_queue_alloc_size (gsize alloc) +{ + return G_STRUCT_OFFSET (GObjectNotifyQueue, pspecs) + (alloc * sizeof (GParamSpec *)); } static GObjectNotifyQueue * @@ -670,10 +668,11 @@ g_object_notify_queue_new_frozen (void) { GObjectNotifyQueue *nqueue; - nqueue = g_new (GObjectNotifyQueue, 1); - *nqueue = (GObjectNotifyQueue){ - .freeze_count = 1, - }; + nqueue = g_malloc (g_object_notify_queue_alloc_size (4)); + + nqueue->freeze_count = 1; + nqueue->alloc = 4; + nqueue->len = 0; return nqueue; } @@ -691,11 +690,11 @@ g_object_notify_queue_freeze_cb (gpointer *data, /* The nqueue doesn't exist yet. We create it, and freeze thus 1 time. */ nqueue = g_object_notify_queue_new_frozen (); *data = nqueue; - *destroy_notify = g_object_notify_queue_free; + *destroy_notify = g_free; } else { - if (G_UNLIKELY (nqueue->freeze_count >= 65535)) + if (G_UNLIKELY (nqueue->freeze_count == G_MAXUINT16)) { g_critical ("Free queue for %s (%p) is larger than 65535," " called g_object_freeze_notify() too often." @@ -723,15 +722,9 @@ g_object_notify_queue_thaw_cb (gpointer *data, GDestroyNotify *destroy_notify, gpointer user_data) { - GObject *object = ((gpointer *) user_data)[0]; - GObjectNotifyQueue *nqueue0 = ((gpointer *) user_data)[1]; + GObject *object = user_data; GObjectNotifyQueue *nqueue = *data; -#if G_ENABLE_DEBUG - g_assert (!nqueue0 || nqueue0 == nqueue); -#endif - (void) nqueue0; - if (G_UNLIKELY (!nqueue || nqueue->freeze_count == 0)) { g_critical ("%s: property-changed notification for %s(%p) is not frozen", @@ -753,74 +746,54 @@ g_object_notify_queue_thaw (GObject *object, GObjectNotifyQueue *nqueue, gboolean take_ref) { - GParamSpec *pspecs_stack[16]; - GParamSpec **pspecs_heap = NULL; - GParamSpec **pspecs = pspecs_stack; - guint n_pspecs; - GSList *slist; - nqueue = _g_datalist_id_update_atomic (&object->qdata, quark_notify_queue, g_object_notify_queue_thaw_cb, - ((gpointer[]){ object, nqueue })); + object); if (!nqueue) return; - if (nqueue->n_pspecs == 0) - goto out; - - if (nqueue->n_pspecs > G_N_ELEMENTS (pspecs_stack)) + if (nqueue->len > 0) { - pspecs_heap = g_new (GParamSpec *, nqueue->n_pspecs); - pspecs = pspecs_heap; + guint16 i; + guint16 j; + + /* Reverse the list. This is the order that we historically had. */ + for (i = 0, j = nqueue->len - 1u; i < j; i++, j--) + { + GParamSpec *tmp; + + tmp = nqueue->pspecs[i]; + nqueue->pspecs[i] = nqueue->pspecs[j]; + nqueue->pspecs[j] = tmp; + } + + if (take_ref) + g_object_ref (object); + + G_OBJECT_GET_CLASS (object)->dispatch_properties_changed (object, nqueue->len, nqueue->pspecs); + + if (take_ref) + g_object_unref (object); } - n_pspecs = 0; - for (slist = nqueue->pspecs; slist; slist = slist->next) - pspecs[n_pspecs++] = slist->data; -#if G_ENABLE_DEBUG - g_assert (n_pspecs == nqueue->n_pspecs); -#endif - - if (take_ref) - g_object_ref (object); - - G_OBJECT_GET_CLASS (object)->dispatch_properties_changed (object, n_pspecs, pspecs); - - if (take_ref) - g_object_unref (object); - - if (pspecs_heap) - g_free (pspecs_heap); - -out: - g_object_notify_queue_free (nqueue); + g_free (nqueue); } -typedef struct -{ - GObject *object; - GObjectNotifyQueue *nqueue; - GParamSpec *pspec; - gboolean in_init; -} NotifyQueueAddData; - static gpointer g_object_notify_queue_add_cb (gpointer *data, GDestroyNotify *destroy_notify, gpointer user_data) { - NotifyQueueAddData *nqdata = user_data; + GParamSpec *pspec = ((gpointer *) user_data)[0]; + gboolean in_init = GPOINTER_TO_INT (((gpointer *) user_data)[1]); GObjectNotifyQueue *nqueue = *data; - -#if G_ENABLE_DEBUG - g_assert (!nqdata->nqueue || nqdata->nqueue == nqueue); -#endif + guint16 i; if (!nqueue) { - if (!nqdata->in_init) + if (!in_init) { /* We are not in-init and are currently not frozen. There is nothing * to do. We return FALSE to the caller, which then will dispatch @@ -838,17 +811,36 @@ g_object_notify_queue_add_cb (gpointer *data, * freeze an additional time. */ nqueue = g_object_notify_queue_new_frozen (); *data = nqueue; - *destroy_notify = g_object_notify_queue_free; + *destroy_notify = g_free; } - - g_assert (nqueue->n_pspecs < 65535); - - if (!g_slist_find (nqueue->pspecs, nqdata->pspec)) + else { - nqueue->pspecs = g_slist_prepend (nqueue->pspecs, nqdata->pspec); - nqueue->n_pspecs++; + for (i = 0; i < nqueue->len; i++) + { + if (nqueue->pspecs[i] == pspec) + goto out; + } + + if (G_UNLIKELY (nqueue->len == nqueue->alloc)) + { + guint32 alloc; + + alloc = ((guint32) nqueue->alloc) * 2u; + if (alloc >= G_MAXUINT16) + { + g_assert (nqueue->len < G_MAXUINT16); + alloc = G_MAXUINT16; + } + nqueue = g_realloc (nqueue, g_object_notify_queue_alloc_size (alloc)); + nqueue->alloc = alloc; + + *data = nqueue; + } } + nqueue->pspecs[nqueue->len++] = pspec; + +out: return GINT_TO_POINTER (TRUE); } @@ -863,12 +855,7 @@ g_object_notify_queue_add (GObject *object, result = _g_datalist_id_update_atomic (&object->qdata, quark_notify_queue, g_object_notify_queue_add_cb, - &((NotifyQueueAddData){ - .object = object, - .nqueue = nqueue, - .pspec = pspec, - .in_init = in_init, - })); + ((gpointer[]){ pspec, GINT_TO_POINTER (!!in_init) })); return GPOINTER_TO_INT (result); }