summaryrefslogtreecommitdiff
path: root/gobject
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2019-09-02 15:48:32 +0200
committerAlexander Larsson <alexl@redhat.com>2019-09-02 15:48:32 +0200
commit5afd574e9186ea80f4445b454fa8cfef0a0e134f (patch)
tree3ac5babe254a90700ac0192e4accb896cc390b8e /gobject
parentcf990faae5f4fcdf7e35a931b2b3013b37161d54 (diff)
downloadglib-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.c100
-rw-r--r--gobject/gsignal.c30
-rw-r--r--gobject/gtype-private.h4
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:
*