From f7119a79354d1b55f18b8158573630ab861146f8 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 26 May 2022 09:43:41 -0400 Subject: [PATCH 1/2] Keep a count of construct params This avoids walking the construct params list one extra time just to count when constructing objects, for a small speedup of object construction in the presence of construct params. --- gobject/gobject.c | 20 +++++++++++++------- gobject/gobject.h | 3 ++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/gobject/gobject.c b/gobject/gobject.c index aa1573b1d..e44494b13 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -478,6 +478,7 @@ g_object_base_class_init (GObjectClass *class) /* reset instance specific fields and methods that don't get inherited */ class->construct_properties = pclass ? g_slist_copy (pclass->construct_properties) : NULL; + class->n_construct_properties = g_slist_length (class->construct_properties); class->get_property = NULL; class->set_property = NULL; } @@ -491,6 +492,7 @@ g_object_base_class_finalize (GObjectClass *class) g_slist_free (class->construct_properties); class->construct_properties = NULL; + class->n_construct_properties = 0; list = g_param_spec_pool_list_owned (pspec_pool, G_OBJECT_CLASS_TYPE (class)); for (node = list; node; node = node->next) { @@ -627,14 +629,20 @@ validate_and_install_class_property (GObjectClass *class, if (install_property_internal (oclass_type, property_id, pspec)) { if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) - class->construct_properties = g_slist_append (class->construct_properties, pspec); + { + class->construct_properties = g_slist_append (class->construct_properties, pspec); + class->n_construct_properties += 1; + } /* for property overrides of construct properties, we have to get rid * of the overridden inherited construct property */ pspec = g_param_spec_pool_lookup (pspec_pool, pspec->name, parent_type, TRUE); if (pspec && pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) - class->construct_properties = g_slist_remove (class->construct_properties, pspec); + { + class->construct_properties = g_slist_remove (class->construct_properties, pspec); + class->n_construct_properties -= 1; + } return TRUE; } @@ -1875,7 +1883,6 @@ g_object_new_with_custom_constructor (GObjectClass *class, GObjectConstructParam *cparams; GObject *object; GValue *cvalues; - gint n_cparams; gint cvals_used; GSList *node; guint i; @@ -1891,9 +1898,8 @@ g_object_new_with_custom_constructor (GObjectClass *class, */ /* Create the array of GObjectConstructParams for constructor() */ - n_cparams = g_slist_length (class->construct_properties); - cparams = g_new (GObjectConstructParam, n_cparams); - cvalues = g_new0 (GValue, n_cparams); + cparams = g_new (GObjectConstructParam, class->n_construct_properties); + cvalues = g_new0 (GValue, class->n_construct_properties); cvals_used = 0; i = 0; @@ -1934,7 +1940,7 @@ g_object_new_with_custom_constructor (GObjectClass *class, } /* construct object from construction parameters */ - object = class->constructor (class->g_type_class.g_type, n_cparams, cparams); + object = class->constructor (class->g_type_class.g_type, class->n_construct_properties, cparams); /* free construction values */ g_free (cparams); while (cvals_used--) diff --git a/gobject/gobject.h b/gobject/gobject.h index 3dc4f7f48..c67794ae5 100644 --- a/gobject/gobject.h +++ b/gobject/gobject.h @@ -369,8 +369,9 @@ struct _GObjectClass /*< private >*/ gsize flags; + gsize n_construct_properties; /* padding */ - gpointer pdummy[6]; + gpointer pdummy[5]; }; /** From ecc641de710e226a979e1a3e9e2fe605b480a490 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 26 May 2022 09:47:10 -0400 Subject: [PATCH 2/2] Avoid malloc for construct params Stack-allocate the GObjectConstructParams (except for extreme cases), for a small speedup of object construction. --- gobject/gobject.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/gobject/gobject.c b/gobject/gobject.c index e44494b13..ef62a03fa 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -1881,6 +1881,7 @@ g_object_new_with_custom_constructor (GObjectClass *class, GObjectNotifyQueue *nqueue = NULL; gboolean newly_constructed; GObjectConstructParam *cparams; + gboolean free_cparams = FALSE; GObject *object; GValue *cvalues; gint cvals_used; @@ -1897,9 +1898,21 @@ g_object_new_with_custom_constructor (GObjectClass *class, * while their constructor() is running. */ - /* Create the array of GObjectConstructParams for constructor() */ - cparams = g_new (GObjectConstructParam, class->n_construct_properties); - cvalues = g_new0 (GValue, class->n_construct_properties); + /* Create the array of GObjectConstructParams for constructor(), + * The 1024 here is an arbitrary, high limit that no sane code + * will ever hit, just to avoid the possibility of stack overflow. + */ + if (G_LIKELY (class->n_construct_properties < 1024)) + { + cparams = g_newa0 (GObjectConstructParam, class->n_construct_properties); + cvalues = g_newa0 (GValue, class->n_construct_properties); + } + else + { + cparams = g_new0 (GObjectConstructParam, class->n_construct_properties); + cvalues = g_new0 (GValue, class->n_construct_properties); + free_cparams = TRUE; + } cvals_used = 0; i = 0; @@ -1942,10 +1955,14 @@ g_object_new_with_custom_constructor (GObjectClass *class, /* construct object from construction parameters */ object = class->constructor (class->g_type_class.g_type, class->n_construct_properties, cparams); /* free construction values */ - g_free (cparams); while (cvals_used--) g_value_unset (&cvalues[cvals_used]); - g_free (cvalues); + + if (free_cparams) + { + g_free (cparams); + g_free (cvalues); + } /* There is code in the wild that relies on being able to return NULL * from its custom constructor. This was never a supported operation,