[glib/gobject-speedups4] gobject: Speed up property lookup




commit fafae7885373d38ea62c2b02fd26b0b9172c5f80
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri May 20 20:49:05 2022 -0400

    gobject: Speed up property lookup
    
    When the param specs are provided as an array
    with g_object_class_install_properties, keep
    a copy of that array around and use it for
    looking up properties without the param spec
    pool.

 gobject/gobject.c | 152 +++++++++++++++++++++++++++++++++++++-----------------
 gobject/gobject.h |   6 ++-
 2 files changed, 111 insertions(+), 47 deletions(-)
---
diff --git a/gobject/gobject.c b/gobject/gobject.c
index bbf5164570..0871107969 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -483,6 +483,8 @@ g_object_base_class_init (GObjectClass *class)
   class->n_construct_properties = g_slist_length (class->construct_properties);
   class->get_property = NULL;
   class->set_property = NULL;
+  class->pspecs = NULL;
+  class->n_pspecs = 0;
 }
 
 static void
@@ -694,6 +696,61 @@ g_object_class_install_property (GObjectClass *class,
                                               pspec);
 }
 
+typedef struct {
+  const char *name;
+  GParamSpec *pspec;
+} PspecEntry;
+
+static int
+compare_pspec_entry (const void *a,
+                     const void *b)
+{
+  const PspecEntry *ae = a;
+  const PspecEntry *be = b;
+
+  return ae->name < be->name ? -1 : (ae->name > be->name ? 1 : 0);
+}
+
+static inline GParamSpec *
+find_pspec (GObjectClass *class,
+            const char   *property_name)
+{
+  PspecEntry *pspecs = (PspecEntry *)class->pspecs;
+  guint n_pspecs = class->n_pspecs;
+
+  if (n_pspecs < 10)
+    {
+      for (guint i = 0; i < n_pspecs; i++)
+        {
+          if (pspecs[i].name == property_name)
+            return pspecs[i].pspec;
+        }
+    }
+  else
+    {
+      int lower = 0;
+      int upper = (int)class->n_pspecs - 1;
+      int mid;
+
+      while (lower <= upper)
+        {
+          mid = (lower + upper) / 2;
+
+          if (property_name < pspecs[mid].name)
+            upper = mid - 1;
+          else if (property_name > pspecs[mid].name)
+            lower = mid + 1;
+          else
+            return pspecs[mid].pspec;
+        }
+    }
+
+  return g_param_spec_pool_lookup (pspec_pool,
+                                   property_name,
+                                   ((GTypeClass *)class)->g_type,
+                                   TRUE);
+}
+
 /**
  * g_object_class_install_properties:
  * @oclass: a #GObjectClass
@@ -800,6 +857,21 @@ g_object_class_install_properties (GObjectClass  *oclass,
           break;
         }
     }
+
+  if (oclass->pspecs == NULL)
+    {
+      PspecEntry *entries = g_new (PspecEntry, n_pspecs - 1);
+      for (i = 1; i < n_pspecs; i++)
+        {
+          entries[i - 1].name = pspecs[i]->name;
+          entries[i - 1].pspec = pspecs[i];
+        }
+
+      qsort (entries, n_pspecs - 1, sizeof (PspecEntry), compare_pspec_entry);
+
+      oclass->pspecs = entries;
+      oclass->n_pspecs = n_pspecs - 1;
+    }
 }
 
 /**
@@ -858,25 +930,16 @@ g_object_class_find_property (GObjectClass *class,
                              const gchar  *property_name)
 {
   GParamSpec *pspec;
-  GParamSpec *redirect;
-       
+
   g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL);
   g_return_val_if_fail (property_name != NULL, NULL);
-  
-  pspec = g_param_spec_pool_lookup (pspec_pool,
-                                   property_name,
-                                   G_OBJECT_CLASS_TYPE (class),
-                                   TRUE);
-  if (pspec)
-    {
-      redirect = g_param_spec_get_redirect_target (pspec);
-      if (redirect)
-       return redirect;
-      else
-       return pspec;
-    }
-  else
-    return NULL;
+
+  pspec = find_pspec (class, property_name);
+
+  if (pspec && ((GTypeInstance *)pspec)->g_class->g_type == G_TYPE_PARAM_OVERRIDE)
+    pspec = ((GParamSpecOverride *)pspec)->overridden;
+
+  return pspec;
 }
 
 /**
@@ -2198,8 +2261,8 @@ g_object_new_with_properties (GType          object_type,
       params = g_newa (GObjectConstructParam, n_properties);
       for (i = 0; i < n_properties; i++)
         {
-          GParamSpec *pspec;
-          pspec = g_param_spec_pool_lookup (pspec_pool, names[i], object_type, TRUE);
+          GParamSpec *pspec = find_pspec (class, names[i]);
+
           if (!g_object_new_is_valid_property (object_type, pspec, names[i], params, count))
             continue;
           params[count].pspec = pspec;
@@ -2264,9 +2327,8 @@ g_object_newv (GType       object_type,
 
       for (i = 0; i < n_parameters; i++)
         {
-          GParamSpec *pspec;
+          GParamSpec *pspec = find_pspec (class, parameters[i].name);
 
-          pspec = g_param_spec_pool_lookup (pspec_pool, parameters[i].name, object_type, TRUE);
           if (!g_object_new_is_valid_property (object_type, pspec, parameters[i].name, cparams, j))
             continue;
 
@@ -2337,9 +2399,7 @@ g_object_new_valist (GType        object_type,
       do
         {
           gchar *error = NULL;
-          GParamSpec *pspec;
-
-          pspec = g_param_spec_pool_lookup (pspec_pool, name, object_type, TRUE);
+          GParamSpec *pspec = find_pspec (class, name);
 
           if (!g_object_new_is_valid_property (object_type, pspec, name, params, n_params))
             break;
@@ -2505,7 +2565,7 @@ g_object_setv (GObject       *object,
   guint i;
   GObjectNotifyQueue *nqueue = NULL;
   GParamSpec *pspec;
-  GType obj_type;
+  GObjectClass *class;
 
   g_return_if_fail (G_IS_OBJECT (object));
 
@@ -2513,14 +2573,15 @@ g_object_setv (GObject       *object,
     return;
 
   g_object_ref (object);
-  obj_type = G_OBJECT_TYPE (object);
+
+  class = G_OBJECT_GET_CLASS (object);
 
   if (_g_object_has_notify_handler (object))
     nqueue = g_object_notify_queue_freeze (object, FALSE);
 
   for (i = 0; i < n_properties; i++)
     {
-      pspec = g_param_spec_pool_lookup (pspec_pool, names[i], obj_type, TRUE);
+      pspec = find_pspec (class, names[i]);
 
       if (!g_object_set_is_valid_property (object, pspec, names[i]))
         break;
@@ -2550,6 +2611,7 @@ g_object_set_valist (GObject       *object,
 {
   GObjectNotifyQueue *nqueue = NULL;
   const gchar *name;
+  GObjectClass *class;
   
   g_return_if_fail (G_IS_OBJECT (object));
 
@@ -2557,7 +2619,9 @@ g_object_set_valist (GObject       *object,
 
   if (_g_object_has_notify_handler (object))
     nqueue = g_object_notify_queue_freeze (object, FALSE);
-  
+
+  class = G_OBJECT_GET_CLASS (object);
+
   name = first_property_name;
   while (name)
     {
@@ -2566,10 +2630,7 @@ g_object_set_valist (GObject      *object,
       gchar *error = NULL;
       GTypeValueTable *vtab;
       
-      pspec = g_param_spec_pool_lookup (pspec_pool,
-                                       name,
-                                       G_OBJECT_TYPE (object),
-                                       TRUE);
+      pspec = find_pspec (class, name);
 
       if (!g_object_set_is_valid_property (object, pspec, name))
         break;
@@ -2642,7 +2703,7 @@ g_object_getv (GObject      *object,
 {
   guint i;
   GParamSpec *pspec;
-  GType obj_type;
+  GObjectClass *class;
 
   g_return_if_fail (G_IS_OBJECT (object));
 
@@ -2651,12 +2712,14 @@ g_object_getv (GObject      *object,
 
   g_object_ref (object);
 
+  class = G_OBJECT_GET_CLASS (object);
+
   memset (values, 0, n_properties * sizeof (GValue));
 
-  obj_type = G_OBJECT_TYPE (object);
   for (i = 0; i < n_properties; i++)
     {
-      pspec = g_param_spec_pool_lookup (pspec_pool, names[i], obj_type, TRUE);
+      pspec = find_pspec (class, names[i]);
+
       if (!g_object_get_is_valid_property (object, pspec, names[i]))
         break;
       g_value_init (&values[i], pspec->value_type);
@@ -2686,23 +2749,23 @@ g_object_get_valist (GObject     *object,
                     va_list      var_args)
 {
   const gchar *name;
+  GObjectClass *class;
   
   g_return_if_fail (G_IS_OBJECT (object));
   
   g_object_ref (object);
-  
+
+  class = G_OBJECT_GET_CLASS (object);
+
   name = first_property_name;
-  
+
   while (name)
     {
       GValue value = G_VALUE_INIT;
       GParamSpec *pspec;
       gchar *error;
-      
-      pspec = g_param_spec_pool_lookup (pspec_pool,
-                                       name,
-                                       G_OBJECT_TYPE (object),
-                                       TRUE);
+
+      pspec = find_pspec (class, name);
 
       if (!g_object_get_is_valid_property (object, pspec, name))
         break;
@@ -2862,10 +2925,7 @@ g_object_get_property (GObject      *object,
   
   g_object_ref (object);
   
-  pspec = g_param_spec_pool_lookup (pspec_pool,
-                                   property_name,
-                                   G_OBJECT_TYPE (object),
-                                   TRUE);
+  pspec = find_pspec (G_OBJECT_GET_CLASS (object), property_name);
 
   if (g_object_get_is_valid_property (object, pspec, property_name))
     {
diff --git a/gobject/gobject.h b/gobject/gobject.h
index c67794ae50..93502b01d6 100644
--- a/gobject/gobject.h
+++ b/gobject/gobject.h
@@ -370,8 +370,12 @@ struct  _GObjectClass
   gsize                flags;
 
   gsize         n_construct_properties;
+
+  gpointer pspecs;
+  guint n_pspecs;
+
   /* padding */
-  gpointer     pdummy[5];
+  gpointer     pdummy[3];
 };
 
 /**


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