From aaef7f30b35464956a478b5c07abbaedd42e4664 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 20 May 2022 07:53:42 -0400 Subject: [PATCH 1/2] value: Add G_VALUE_COLLECT_INIT2 Add a variant of the G_VALUE_COLLECT_INIT() macro that provides the GTypeValueTable to the caller. --- docs/reference/gobject/gobject-sections.txt | 1 + gobject/gvaluecollector.h | 31 ++++++++++++++++++--- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/docs/reference/gobject/gobject-sections.txt b/docs/reference/gobject/gobject-sections.txt index 278c75610..c742de9f6 100644 --- a/docs/reference/gobject/gobject-sections.txt +++ b/docs/reference/gobject/gobject-sections.txt @@ -813,6 +813,7 @@ g_param_spec_types glib-object.h,gobject/gvaluecollector.h GTypeCValue G_VALUE_COLLECT_INIT +G_VALUE_COLLECT_INIT2 G_VALUE_COLLECT G_VALUE_COLLECT_SKIP G_VALUE_LCOPY diff --git a/gobject/gvaluecollector.h b/gobject/gvaluecollector.h index 82e675cdd..5846d77a7 100644 --- a/gobject/gvaluecollector.h +++ b/gobject/gvaluecollector.h @@ -87,15 +87,38 @@ union _GTypeCValue * * Since: 2.24 */ -#define G_VALUE_COLLECT_INIT(value, _value_type, var_args, flags, __error) \ +#define G_VALUE_COLLECT_INIT(value, _value_type, var_args, flags, __error) \ + G_STMT_START { \ + GTypeValueTable *g_vci_vtab; \ + G_VALUE_COLLECT_INIT2(value, g_vci_vtab, _value_type, var_args, flags, __error); \ +} G_STMT_END + +/** + * G_VALUE_COLLECT_INIT2: + * @value: a #GValue return location. @value must contain only 0 bytes. + * @g_vci_vtab: a #GTypeValueTable pointer that will be set to the value table + * for @_value_type + * @_value_type: the #GType to use for @value. + * @var_args: the va_list variable; it may be evaluated multiple times + * @flags: flags which are passed on to the collect_value() function of + * the #GTypeValueTable of @value. + * @__error: a #gchar** variable that will be modified to hold a g_new() + * allocated error messages if something fails + * + * A variant of G_VALUE_COLLECT_INIT() that provides the #GTypeValueTable + * to the caller. + * + * Since: 2.74 + */ +#define G_VALUE_COLLECT_INIT2(value, g_vci_vtab, _value_type, var_args, flags, __error) \ G_STMT_START { \ GValue *g_vci_val = (value); \ guint g_vci_flags = (flags); \ - GTypeValueTable *g_vci_vtab = g_type_value_table_peek (_value_type); \ - const gchar *g_vci_collect_format = g_vci_vtab->collect_format; \ + const gchar *g_vci_collect_format; \ GTypeCValue g_vci_cvalues[G_VALUE_COLLECT_FORMAT_MAX_LENGTH] = { { 0, }, }; \ guint g_vci_n_values = 0; \ - \ + g_vci_vtab = g_type_value_table_peek (_value_type); \ + g_vci_collect_format = g_vci_vtab->collect_format; \ g_vci_val->g_type = _value_type; /* value_meminit() from gvalue.c */ \ while (*g_vci_collect_format) \ { \ From f2a085d8ead7d2e92533b9ee262716d56e830fc6 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 20 May 2022 07:54:35 -0400 Subject: [PATCH 2/2] Avoid g_type_peek_value_table In several places we do paired calls of g_value_init and g_value_unset, both of which peek the value table. We can avoid half of that cost by remembering the value table, instead of looking it up again. This uses the new G_VALUE_COLLECT_INIT2 macro. --- gobject/gobject.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/gobject/gobject.c b/gobject/gobject.c index a7a1d3032..4c992d361 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -2294,9 +2294,11 @@ g_object_new_valist (GType object_type, { GObjectConstructParam params_stack[16]; GValue values_stack[G_N_ELEMENTS (params_stack)]; + GTypeValueTable *vtabs_stack[G_N_ELEMENTS (params_stack)]; const gchar *name; GObjectConstructParam *params = params_stack; GValue *values = values_stack; + GTypeValueTable **vtabs = vtabs_stack; guint n_params = 0; guint n_params_alloc = G_N_ELEMENTS (params_stack); @@ -2321,14 +2323,17 @@ g_object_new_valist (GType object_type, n_params_alloc = G_N_ELEMENTS (params_stack) * 2u; params = g_new (GObjectConstructParam, n_params_alloc); values = g_new (GValue, n_params_alloc); + vtabs = g_new (GTypeValueTable *, n_params_alloc); memcpy (params, params_stack, sizeof (GObjectConstructParam) * n_params); memcpy (values, values_stack, sizeof (GValue) * n_params); + memcpy (vtabs, vtabs_stack, sizeof (GTypeValueTable *) * n_params); } else { n_params_alloc *= 2u; params = g_realloc (params, sizeof (GObjectConstructParam) * n_params_alloc); values = g_realloc (values, sizeof (GValue) * n_params_alloc); + vtabs = g_realloc (vtabs, sizeof (GTypeValueTable *) * n_params_alloc); } for (i = 0; i < n_params; i++) @@ -2339,7 +2344,7 @@ g_object_new_valist (GType object_type, params[n_params].value = &values[n_params]; memset (&values[n_params], 0, sizeof (GValue)); - G_VALUE_COLLECT_INIT (&values[n_params], pspec->value_type, var_args, 0, &error); + G_VALUE_COLLECT_INIT2 (&values[n_params], vtabs[n_params], pspec->value_type, var_args, 0, &error); if (error) { @@ -2356,12 +2361,19 @@ g_object_new_valist (GType object_type, object = g_object_new_internal (class, params, n_params); while (n_params--) - g_value_unset (params[n_params].value); + { + /* We open-code g_value_unset() here to avoid the + * cost of looking up the GTypeValueTable again. + */ + if (vtabs[n_params]->value_free) + vtabs[n_params]->value_free (params[n_params].value); + } if (G_UNLIKELY (n_params_alloc != G_N_ELEMENTS (params_stack))) { g_free (params); g_free (values); + g_free (vtabs); } } else @@ -2516,6 +2528,7 @@ g_object_set_valist (GObject *object, GValue value = G_VALUE_INIT; GParamSpec *pspec; gchar *error = NULL; + GTypeValueTable *vtab; pspec = g_param_spec_pool_lookup (pspec_pool, name, @@ -2525,8 +2538,7 @@ g_object_set_valist (GObject *object, if (!g_object_set_is_valid_property (object, pspec, name)) break; - G_VALUE_COLLECT_INIT (&value, pspec->value_type, var_args, - 0, &error); + G_VALUE_COLLECT_INIT2 (&value, vtab, pspec->value_type, var_args, 0, &error); if (error) { g_warning ("%s: %s", G_STRFUNC, error); @@ -2537,7 +2549,12 @@ g_object_set_valist (GObject *object, consider_issuing_property_deprecation_warning (pspec); object_set_property (object, pspec, &value, nqueue); - g_value_unset (&value); + + /* We open-code g_value_unset() here to avoid the + * cost of looking up the GTypeValueTable again. + */ + if (vtab->value_free) + vtab->value_free (&value); name = va_arg (var_args, gchar*); }