[glib: 1/2] Use the GObject hole on 64bit arches for some flags to improve performance



commit 5afd574e9186ea80f4445b454fa8cfef0a0e134f
Author: Alexander Larsson <alexl redhat com>
Date:   Mon Sep 2 15:48:32 2019 +0200

    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.

 gobject/gobject.c       | 100 +++++++++++++++++++++++++++++++++++++++++++++++-
 gobject/gsignal.c       |  30 +++++++++++++--
 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:
  *


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]