]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
libctf, hash: add support for freeing functions taking an arg
authorNick Alcock <nick.alcock@oracle.com>
Mon, 13 Jan 2025 11:34:56 +0000 (11:34 +0000)
committerNick Alcock <nick.alcock@oracle.com>
Fri, 28 Feb 2025 15:13:23 +0000 (15:13 +0000)
There are a bunch of places in libctf where the code is complicated
by the fact that freeing a hash key or value requires access to the
dict: more generally, they want an arg pointer to *something*.

But for the sake of being able to use free() as a freeing function,
we can't do this at all times.  We also don't want to bloat up the
hash itself with an arg value unless necessary (in the same way we
already avoid storing the key or value freeing functions unless at
least one of them is specified).

So from the outside this change is simple: add a new
ctf_dynhash_create_arg which takes a new sort of freeing function
which takes an argument.  Internally, we store the arg only when
the key or owner is set, and cast from the one freeing function
to the other iff the arg is non-NULL.  This means it's impossible
to pass a value that may or may not be NULL to the freeing
function, but that's harmless for all current uses, and allows
significant simplifications elsewhere.

libctf/ctf-hash.c
libctf/ctf-impl.h
libctf/ctf-open.c

index a11d11e189c92d4543162831af669e6bdc679095..8b5c379bcb3b2e3b78f93c0f394fda76d3da7c8c 100644 (file)
@@ -46,13 +46,54 @@ typedef struct ctf_helem
   ctf_dynhash_t *owner;          /* The hash that owns us.  */
 } ctf_helem_t;
 
-/* Equally, the key_free and value_free may not exist.  */
+/* Equally, the key_free_ and value_free_ may not exist: if neither do, the
+   arg will not exist either.  */
 
 struct ctf_dynhash
 {
   struct htab *htab;
-  ctf_hash_free_fun key_free;
-  ctf_hash_free_fun value_free;
+
+  /* The freeing functions may be of type ctf_hash_free_fun, if arg is NULL,
+     or ctf_hash_free_arg_fun, if it is not.
+
+     Everything from this point on is allocated only if we have at least one
+     freeing function defined.  */
+
+#ifdef __GNUC__
+  __extension__
+  union
+  {
+    ctf_hash_free_fun key_free_;
+    ctf_hash_free_arg_fun key_arg_free_;
+  };
+
+  __extension__
+  union
+  {
+    ctf_hash_free_fun value_free_;
+    ctf_hash_free_arg_fun value_arg_free_;
+  };
+#else
+  union
+  {
+    ctf_hash_free_fun key_free_;
+    ctf_hash_free_arg_fun key_arg_free_;
+  } _k;
+
+  union
+  {
+    ctf_hash_free_fun value_free_;
+    ctf_hash_free_arg_fun value_arg_free_;
+  } _v;
+
+#define key_free_ _k.key_free_
+#define key_arg_free_ _k.key_arg_free_
+#define value_free_ _v.value_free_
+#define value_arg_free_ _v.value_arg_free_
+
+#endif
+
+  void *arg;                   /* arg to freeing functions.  */
 };
 
 /* Hash and eq functions for the dynhash and hash. */
@@ -146,17 +187,30 @@ ctf_dynhash_item_free (void *item)
 {
   ctf_helem_t *helem = item;
 
-  if (helem->owner->key_free && helem->key)
-    helem->owner->key_free (helem->key);
-  if (helem->owner->value_free && helem->value)
-    helem->owner->value_free (helem->value);
+  if (helem->owner->key_free_ && helem->key)
+    {
+      if (!helem->owner->arg)
+       helem->owner->key_free_ (helem->key);
+      else
+       helem->owner->key_arg_free_ (helem->key, helem->owner->arg);
+    }
+  if (helem->owner->value_free_ && helem->value)
+    {
+      if (!helem->owner->arg)
+       helem->owner->value_free_ (helem->value);
+      else
+       {
+         helem->owner->value_arg_free_ (helem->value, helem->owner->arg);
+       }
+    }
   free (helem);
 }
 
 ctf_dynhash_t *
 ctf_dynhash_create_sized (unsigned long nelems, ctf_hash_fun hash_fun,
-                         ctf_hash_eq_fun eq_fun, ctf_hash_free_fun key_free,
-                         ctf_hash_free_fun value_free)
+                         ctf_hash_eq_fun eq_fun,
+                         ctf_hash_free_arg_fun key_free,
+                         ctf_hash_free_arg_fun value_free, void *arg)
 {
   ctf_dynhash_t *dynhash;
   htab_del del = ctf_dynhash_item_free;
@@ -165,7 +219,7 @@ ctf_dynhash_create_sized (unsigned long nelems, ctf_hash_fun hash_fun,
     dynhash = malloc (sizeof (ctf_dynhash_t));
   else
     {
-      void *p = malloc (offsetof (ctf_dynhash_t, key_free));
+      void *p = malloc (offsetof (ctf_dynhash_t, key_free_));
       dynhash = p;
     }
   if (!dynhash)
@@ -183,20 +237,44 @@ ctf_dynhash_create_sized (unsigned long nelems, ctf_hash_fun hash_fun,
 
   if (key_free || value_free)
     {
-      dynhash->key_free = key_free;
-      dynhash->value_free = value_free;
+      dynhash->key_arg_free_ = key_free;
+      dynhash->value_arg_free_ = value_free;
+      dynhash->arg = arg;
     }
 
   return dynhash;
 }
 
+ctf_dynhash_t *
+ctf_dynhash_create_arg (ctf_hash_fun hash_fun, ctf_hash_eq_fun eq_fun,
+                       ctf_hash_free_arg_fun key_free,
+                       ctf_hash_free_arg_fun value_free,
+                       void *arg)
+{
+  /* 7 is arbitrary and not benchmarked yet.  */
+
+  return ctf_dynhash_create_sized (7, hash_fun, eq_fun, key_free, value_free, arg);
+}
+
 ctf_dynhash_t *
 ctf_dynhash_create (ctf_hash_fun hash_fun, ctf_hash_eq_fun eq_fun,
                    ctf_hash_free_fun key_free, ctf_hash_free_fun value_free)
 {
+  union cast
+  {
+    ctf_hash_free_fun in;
+    ctf_hash_free_arg_fun out;
+  };
+  union cast key_arg_free;
+  union cast value_arg_free;
+
+  key_arg_free.in = key_free;
+  value_arg_free.in = value_free;
+
   /* 7 is arbitrary and not benchmarked yet.  */
 
-  return ctf_dynhash_create_sized (7, hash_fun, eq_fun, key_free, value_free);
+  return ctf_dynhash_create_sized (7, hash_fun, eq_fun, key_arg_free.out,
+                                  value_arg_free.out, NULL);
 }
 
 static ctf_helem_t **
@@ -209,7 +287,8 @@ ctf_hashtab_lookup (struct htab *htab, const void *key, enum insert_option inser
 static ctf_helem_t *
 ctf_hashtab_insert (struct htab *htab, void *key, void *value,
                    ctf_hash_free_fun key_free,
-                   ctf_hash_free_fun value_free)
+                   ctf_hash_free_fun value_free,
+                   void *arg)
 {
   ctf_helem_t **slot;
 
@@ -238,10 +317,37 @@ ctf_hashtab_insert (struct htab *htab, void *key, void *value,
     }
   else
     {
+      union cast
+      {
+       ctf_hash_free_fun in;
+       ctf_hash_free_arg_fun out;
+      };
+
       if (key_free)
-         key_free (key);
+       {
+         {if (!arg)
+             key_free (key);
+           else
+             {
+               union cast key_arg_free;
+
+               key_arg_free.in = key_free;
+               key_arg_free.out (key, arg);
+             }
+         }
+       }
       if (value_free)
-         value_free ((*slot)->value);
+       {
+         if (!arg)
+           value_free ((*slot)->value);
+         else
+           {
+             union cast value_arg_free;
+
+             value_arg_free.in = value_free;
+             value_arg_free.out ((*slot)->value, arg);
+           }
+       }
     }
   (*slot)->value = value;
   return *slot;
@@ -252,14 +358,16 @@ ctf_dynhash_insert (ctf_dynhash_t *hp, void *key, void *value)
 {
   ctf_helem_t *slot;
   ctf_hash_free_fun key_free = NULL, value_free = NULL;
+  void *arg = NULL;
 
   if (hp->htab->del_f == ctf_dynhash_item_free)
     {
-      key_free = hp->key_free;
-      value_free = hp->value_free;
+      key_free = hp->key_free_;
+      value_free = hp->value_free_;
+      arg = hp->arg;
     }
   slot = ctf_hashtab_insert (hp->htab, key, value,
-                            key_free, value_free);
+                            key_free, value_free, arg);
 
   if (!slot)
     return -errno;
@@ -579,7 +687,8 @@ ctf_dynhash_destroy (ctf_dynhash_t *hp)
 /* The dynset, used for sets of keys with no value.  The implementation of this
    can be much simpler, because without a value the slot can simply be the
    stored key, which means we don't need to store the freeing functions and the
-   dynset itself is just a htab.  */
+   dynset itself is just a htab.  There is no support for freeing
+   functions with args.  */
 
 ctf_dynset_t *
 ctf_dynset_create (htab_hash hash_fun, htab_eq eq_fun,
index c50f06e3d6fafe6b4fce1a19c569f19dedbd6bac..90b0b95d08c984b923b7a48c38855c2d96d6bd06 100644 (file)
@@ -651,7 +651,12 @@ extern int ctf_hash_eq_string (const void *, const void *);
 extern int ctf_hash_eq_type_key (const void *, const void *);
 extern int ctf_hash_eq_type_id_key (const void *, const void *);
 
+/* Freeing functions.  ctf_hash_free_fun is used unless the arg
+   parameter to ctf_dynhash_create_{arg,sized} is non-NULL.
+   There is no way to pass a NULL arg to ctf_hash_free_arg_fun.  */
+
 typedef void (*ctf_hash_free_fun) (void *);
+typedef void (*ctf_hash_free_arg_fun) (void *, void *);
 
 typedef void (*ctf_hash_iter_f) (void *key, void *value, void *arg);
 typedef int (*ctf_hash_iter_remove_f) (void *key, void *value, void *arg);
@@ -661,10 +666,14 @@ typedef int (*ctf_hash_sort_f) (const ctf_next_hkv_t *, const ctf_next_hkv_t *,
 
 extern ctf_dynhash_t *ctf_dynhash_create (ctf_hash_fun, ctf_hash_eq_fun,
                                          ctf_hash_free_fun, ctf_hash_free_fun);
+extern ctf_dynhash_t *ctf_dynhash_create_arg (ctf_hash_fun, ctf_hash_eq_fun,
+                                             ctf_hash_free_arg_fun,
+                                             ctf_hash_free_arg_fun, void *);
 extern ctf_dynhash_t *ctf_dynhash_create_sized (unsigned long, ctf_hash_fun,
                                                ctf_hash_eq_fun,
-                                               ctf_hash_free_fun,
-                                               ctf_hash_free_fun);
+                                               ctf_hash_free_arg_fun,
+                                               ctf_hash_free_arg_fun,
+                                               void *);
 
 extern int ctf_dynhash_insert (ctf_dynhash_t *, void *, void *);
 extern void ctf_dynhash_remove (ctf_dynhash_t *, const void *);
index 219831be46d90ee6f706ab949cf3065cb7d87448..4cf18f0bced5ed6d2fea1de86cf5378720618c8e 100644 (file)
@@ -791,17 +791,20 @@ init_static_types (ctf_dict_t *fp, ctf_header_t *cth)
 
   if ((fp->ctf_structs
        = ctf_dynhash_create_sized (pop[CTF_K_STRUCT], ctf_hash_string,
-                                  ctf_hash_eq_string, NULL, NULL)) == NULL)
+                                  ctf_hash_eq_string,
+                                  NULL, NULL, NULL)) == NULL)
     return ENOMEM;
 
   if ((fp->ctf_unions
        = ctf_dynhash_create_sized (pop[CTF_K_UNION], ctf_hash_string,
-                                  ctf_hash_eq_string, NULL, NULL)) == NULL)
+                                  ctf_hash_eq_string,
+                                  NULL, NULL, NULL)) == NULL)
     return ENOMEM;
 
   if ((fp->ctf_enums
        = ctf_dynhash_create_sized (pop[CTF_K_ENUM], ctf_hash_string,
-                                  ctf_hash_eq_string, NULL, NULL)) == NULL)
+                                  ctf_hash_eq_string,
+                                  NULL, NULL, NULL)) == NULL)
     return ENOMEM;
 
   if ((fp->ctf_names
@@ -816,7 +819,8 @@ init_static_types (ctf_dict_t *fp, ctf_header_t *cth)
                                   pop[CTF_K_RESTRICT] +
                                   pop_enumerators,
                                   ctf_hash_string,
-                                  ctf_hash_eq_string, NULL, NULL)) == NULL)
+                                  ctf_hash_eq_string,
+                                  NULL, NULL, NULL)) == NULL)
     return ENOMEM;
 
   if ((fp->ctf_conflicting_enums