diff options
author | Alexander Larsson <alexl@redhat.com> | 2019-09-02 15:48:32 +0200 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2019-09-02 15:48:32 +0200 |
commit | 5afd574e9186ea80f4445b454fa8cfef0a0e134f (patch) | |
tree | 3ac5babe254a90700ac0192e4accb896cc390b8e /gobject | |
parent | cf990faae5f4fcdf7e35a931b2b3013b37161d54 (diff) | |
download | glib-5afd574e9186ea80f4445b454fa8cfef0a0e134f.tar.gz |
Use the GObject hole on 64bit arches for some flags to improve performance
This uses a 32bit hole in the GObject structure on 64bit arches
as a flag field which can be optionally used for some preformance hints.
Currently there is a flag that gets set any time you connect to a signal
on a GObject which is used as early bailout for signal emissions, and using
the flags field instead of a user-data for checking if a GObject is
under construction.
Diffstat (limited to 'gobject')
-rw-r--r-- | gobject/gobject.c | 100 | ||||
-rw-r--r-- | gobject/gsignal.c | 30 | ||||
-rw-r--r-- | gobject/gtype-private.h | 4 |
3 files changed, 128 insertions, 6 deletions
diff --git a/gobject/gobject.c b/gobject/gobject.c index df27c36f7..acb365a82 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -162,6 +162,29 @@ enum { PROP_NONE }; +#define OPTIONAL_FLAG_IN_CONSTRUCTION 1<<0 +#define OPTIONAL_FLAG_HAS_SIGNAL_HANDLER 1<<1 /* Set if object ever had a signal handler */ + +#if SIZEOF_INT == 4 && GLIB_SIZEOF_VOID_P == 8 +#define HAVE_OPTIONAL_FLAGS +#endif + +typedef struct +{ + GTypeInstance g_type_instance; + + /*< private >*/ + volatile guint ref_count; +#ifdef HAVE_OPTIONAL_FLAGS + volatile guint optional_flags; +#endif + GData *qdata; +} GObjectReal; + +G_STATIC_ASSERT(sizeof(GObject) == sizeof(GObjectReal)); +G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, ref_count) == G_STRUCT_OFFSET(GObjectReal, ref_count)); +G_STATIC_ASSERT(G_STRUCT_OFFSET(GObject, qdata) == G_STRUCT_OFFSET(GObjectReal, qdata)); + /* --- prototypes --- */ static void g_object_base_class_init (GObjectClass *class); @@ -1008,10 +1031,83 @@ g_object_interface_list_properties (gpointer g_iface, return pspecs; } +static inline guint +object_get_optional_flags (GObject *object) +{ +#ifdef HAVE_OPTIONAL_FLAGS + GObjectReal *real = (GObjectReal *)object; + return (guint)g_atomic_int_get (&real->optional_flags); +#else + return 0; +#endif +} + +static inline void +object_set_optional_flags (GObject *object, + guint flags) +{ +#ifdef HAVE_OPTIONAL_FLAGS + GObjectReal *real = (GObjectReal *)object; + g_atomic_int_or (&real->optional_flags, flags); +#endif +} + +static inline void +object_unset_optional_flags (GObject *object, + guint flags) +{ +#ifdef HAVE_OPTIONAL_FLAGS + GObjectReal *real = (GObjectReal *)object; + g_atomic_int_and (&real->optional_flags, ~flags); +#endif +} + +gboolean +_g_object_has_signal_handler (GObject *object) +{ +#ifdef HAVE_OPTIONAL_FLAGS + return (object_get_optional_flags (object) & OPTIONAL_FLAG_HAS_SIGNAL_HANDLER) != 0; +#else + return TRUE; +#endif +} + +void +_g_object_set_has_signal_handler (GObject *object) +{ +#ifdef HAVE_OPTIONAL_FLAGS + object_set_optional_flags (object, OPTIONAL_FLAG_HAS_SIGNAL_HANDLER); +#endif +} + static inline gboolean object_in_construction (GObject *object) { +#ifdef HAVE_OPTIONAL_FLAGS + return (object_get_optional_flags (object) & OPTIONAL_FLAG_IN_CONSTRUCTION) != 0; +#else return g_datalist_id_get_data (&object->qdata, quark_in_construction) != NULL; +#endif +} + +static inline void +set_object_in_construction (GObject *object) +{ +#ifdef HAVE_OPTIONAL_FLAGS + object_set_optional_flags (object, OPTIONAL_FLAG_IN_CONSTRUCTION); +#else + g_datalist_id_set_data (&object->qdata, quark_in_construction, object); +#endif +} + +static inline void +unset_object_in_construction (GObject *object) +{ +#ifdef HAVE_OPTIONAL_FLAGS + object_unset_optional_flags (object, OPTIONAL_FLAG_IN_CONSTRUCTION); +#else + g_datalist_id_set_data (&object->qdata, quark_in_construction, NULL); +#endif } static void @@ -1030,7 +1126,7 @@ g_object_init (GObject *object, if (CLASS_HAS_CUSTOM_CONSTRUCTOR (class)) { /* mark object in-construction for notify_queue_thaw() and to allow construct-only properties */ - g_datalist_id_set_data (&object->qdata, quark_in_construction, object); + set_object_in_construction (object); } GOBJECT_IF_DEBUG (OBJECTS, @@ -1766,7 +1862,7 @@ g_object_new_with_custom_constructor (GObjectClass *class, */ newly_constructed = object_in_construction (object); if (newly_constructed) - g_datalist_id_set_data (&object->qdata, quark_in_construction, NULL); + unset_object_in_construction (object); if (CLASS_HAS_PROPS (class)) { diff --git a/gobject/gsignal.c b/gobject/gsignal.c index 77d8f211e..fb370fd11 100644 --- a/gobject/gsignal.c +++ b/gobject/gsignal.c @@ -711,7 +711,7 @@ handler_insert (guint signal_id, HandlerList *hlist; g_assert (handler->prev == NULL && handler->next == NULL); /* paranoid */ - + hlist = handler_list_ensure (signal_id, instance); if (!hlist->handlers) { @@ -2345,7 +2345,10 @@ g_signal_connect_closure_by_id (gpointer instance, else { Handler *handler = handler_new (signal_id, instance, after); - + + if (G_TYPE_IS_OBJECT (node->itype)) + _g_object_set_has_signal_handler ((GObject *)instance); + handler_seq_no = handler->sequential_number; handler->detail = detail; handler->closure = g_closure_ref (closure); @@ -2410,6 +2413,9 @@ g_signal_connect_closure (gpointer instance, { Handler *handler = handler_new (signal_id, instance, after); + if (G_TYPE_IS_OBJECT (node->itype)) + _g_object_set_has_signal_handler ((GObject *)instance); + handler_seq_no = handler->sequential_number; handler->detail = detail; handler->closure = g_closure_ref (closure); @@ -2511,6 +2517,9 @@ g_signal_connect_data (gpointer instance, { Handler *handler = handler_new (signal_id, instance, after); + if (G_TYPE_IS_OBJECT (node->itype)) + _g_object_set_has_signal_handler ((GObject *)instance); + handler_seq_no = handler->sequential_number; handler->detail = detail; handler->closure = g_closure_ref ((swapped ? g_cclosure_new_swap : g_cclosure_new) (c_handler, data, destroy_data)); @@ -3121,7 +3130,14 @@ g_signal_emitv (const GValue *instance_and_params, (node->single_va_closure == SINGLE_VA_CLOSURE_EMPTY_MAGIC || _g_closure_is_void (node->single_va_closure, instance))) { - HandlerList* hlist = handler_list_lookup (node->signal_id, instance); + HandlerList* hlist; + + /* single_va_closure is only true for GObjects, so fast path if no handler ever connected to the signal */ + if (_g_object_has_signal_handler ((GObject *)instance)) + hlist = handler_list_lookup (node->signal_id, instance); + else + hlist = NULL; + if (hlist == NULL || hlist->handlers == NULL) { /* nothing to do to emit this signal */ @@ -3204,7 +3220,7 @@ g_signal_emit_valist (gpointer instance, if (node->single_va_closure != NULL) { - HandlerList* hlist = handler_list_lookup (node->signal_id, instance); + HandlerList* hlist; Handler *fastpath_handler = NULL; Handler *l; GClosure *closure = NULL; @@ -3226,6 +3242,12 @@ g_signal_emit_valist (gpointer instance, fastpath = FALSE; } + /* single_va_closure is only true for GObjects, so fast path if no handler ever connected to the signal */ + if (_g_object_has_signal_handler ((GObject *)instance)) + hlist = handler_list_lookup (node->signal_id, instance); + else + hlist = NULL; + for (l = hlist ? hlist->handlers : NULL; fastpath && l != NULL; l = l->next) { if (!l->block_count && diff --git a/gobject/gtype-private.h b/gobject/gtype-private.h index 230dba03a..2e0afdd5d 100644 --- a/gobject/gtype-private.h +++ b/gobject/gtype-private.h @@ -23,6 +23,7 @@ #include "gboxed.h" #include "gclosure.h" +#include "gobject.h" /*< private > * GOBJECT_IF_DEBUG: @@ -92,6 +93,9 @@ void _g_closure_invoke_va (GClosure *closure, int n_params, GType *param_types); +gboolean _g_object_has_signal_handler (GObject *object); +void _g_object_set_has_signal_handler (GObject *object); + /** * _G_DEFINE_TYPE_EXTENDED_WITH_PRELUDE: * |