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




commit 45e1aedfef42c14d767895ac26c0a77f66ae19d3
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 c822b0eba2..eef6c4ebe5 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -485,6 +485,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
@@ -696,6 +698,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
@@ -802,6 +859,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;
+    }
 }
 
 /**
@@ -860,25 +932,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;
 }
 
 /**
@@ -2212,8 +2275,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;
@@ -2278,9 +2341,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;
 
@@ -2351,9 +2413,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;
@@ -2519,7 +2579,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));
 
@@ -2527,14 +2587,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;
@@ -2564,6 +2625,7 @@ g_object_set_valist (GObject       *object,
 {
   GObjectNotifyQueue *nqueue = NULL;
   const gchar *name;
+  GObjectClass *class;
   
   g_return_if_fail (G_IS_OBJECT (object));
 
@@ -2571,7 +2633,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)
     {
@@ -2580,10 +2644,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;
@@ -2656,7 +2717,7 @@ g_object_getv (GObject      *object,
 {
   guint i;
   GParamSpec *pspec;
-  GType obj_type;
+  GObjectClass *class;
 
   g_return_if_fail (G_IS_OBJECT (object));
 
@@ -2665,12 +2726,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);
@@ -2700,23 +2763,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;
@@ -2876,10 +2939,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]