[Ada] Add a symbol lookup cache
authorJoel Brobecker <brobecker@adacore.com>
Mon, 10 Feb 2014 05:03:30 +0000 (09:03 +0400)
committerJoel Brobecker <brobecker@adacore.com>
Mon, 10 Feb 2014 07:48:53 +0000 (11:48 +0400)
This patch implements the caching mechanism alluded to in a comment
next to some stubbed functions.

gdb/ChangeLog:

        * ada-lang.c (HASH_SIZE): New macro.
        (struct cache_entry): New type.
        (cache_space, cache): New static globals.
        (ada_clear_symbol_cache, find_entry): New functions.
        (lookup_cached_symbol, cache_symbol): Implement.
        (ada_new_objfile_observer, ada_free_objfile_observer): New.
        (_initialize_ada_language): Attach ada_new_objfile_observer
        and ada_free_objfile_observer.

gdb/ChangeLog
gdb/ada-lang.c

index 940c6a223e7a0c2b6290603c7db2b4b3cc52a86a..828cb6e2b502265f73ba7ea4394cded9e6f24ec5 100644 (file)
@@ -1,3 +1,14 @@
+2014-02-10  Joel Brobecker  <brobecker@adacore.com>
+
+       * ada-lang.c (HASH_SIZE): New macro.
+       (struct cache_entry): New type.
+       (cache_space, cache): New static globals.
+       (ada_clear_symbol_cache, find_entry): New functions.
+       (lookup_cached_symbol, cache_symbol): Implement.
+       (ada_new_objfile_observer, ada_free_objfile_observer): New.
+       (_initialize_ada_language): Attach ada_new_objfile_observer
+       and ada_free_objfile_observer.
+
 2014-02-10  Joel Brobecker  <brobecker@adacore.com>
 
        * ada-lang.c (ada_add_block_symbols, add_defn_to_vec)
index 269112c22c3866ddf1c7afb28a7cb8086b23e427..fc2c83b84cc58a8152404bad7a0b17928b535550 100644 (file)
@@ -4245,20 +4245,129 @@ make_array_descriptor (struct type *type, struct value *arr)
     return descriptor;
 }
 \f
-/* Dummy definitions for an experimental caching module that is not
- * used in the public sources.  */
+                                /* Symbol Cache Module */
+
+/* This section implements a simple, fixed-sized hash table for those
+   Ada-mode symbols that get looked up in the course of executing the user's
+   commands.  The size is fixed on the grounds that there are not
+   likely to be all that many symbols looked up during any given
+   session, regardless of the size of the symbol table.  If we decide
+   to go to a resizable table, let's just use the stuff from libiberty
+   instead.  */
+
+/* Performance measurements made as of 2010-01-15 indicate that
+   this case does bring some noticeable improvements.  Depending
+   on the type of entity being printed, the cache can make it as much
+   as an order of magnitude faster than without it.
+
+   The descriptive type DWARF extension has significantly reduced
+   the need for this cache, at least when DWARF is being used.  However,
+   even in this case, some expensive name-based symbol searches are still
+   sometimes necessary - to find an XVZ variable, mostly.  */
+
+#define HASH_SIZE 1009
+
+/* The result of a symbol lookup to be stored in our cache.  */
+
+struct cache_entry
+{
+  /* The name used to perform the lookup.  */
+  const char *name;
+  /* The namespace used during the lookup.  */
+  domain_enum namespace;
+  /* The symbol returned by the lookup, or NULL if no matching symbol
+     was found.  */
+  struct symbol *sym;
+  /* The block where the symbol was found, or NULL if no matching
+     symbol was found.  */
+  const struct block *block;
+  /* A pointer to the next entry with the same hash.  */
+  struct cache_entry *next;
+};
+
+/* An obstack used to store the entries in our cache.  */
+static struct obstack cache_space;
+
+/* The root of the hash table used to implement our symbol cache.  */
+static struct cache_entry *cache[HASH_SIZE];
+
+/* Clear all entries from the symbol cache.  */
+
+static void
+ada_clear_symbol_cache (void)
+{
+  obstack_free (&cache_space, NULL);
+  obstack_init (&cache_space);
+  memset (cache, '\000', sizeof (cache));
+}
+
+/* Search our cache for an entry matching NAME and NAMESPACE.
+   Return it if found, or NULL otherwise.  */
+
+static struct cache_entry **
+find_entry (const char *name, domain_enum namespace)
+{
+  int h = msymbol_hash (name) % HASH_SIZE;
+  struct cache_entry **e;
+
+  for (e = &cache[h]; *e != NULL; e = &(*e)->next)
+    {
+      if (namespace == (*e)->namespace && strcmp (name, (*e)->name) == 0)
+        return e;
+    }
+  return NULL;
+}
+
+/* Search the symbol cache for an entry matching NAME and NAMESPACE.
+   Return 1 if found, 0 otherwise.
+
+   If an entry was found and SYM is not NULL, set *SYM to the entry's
+   SYM.  Same principle for BLOCK if not NULL.  */
 
 static int
 lookup_cached_symbol (const char *name, domain_enum namespace,
                       struct symbol **sym, const struct block **block)
 {
-  return 0;
+  struct cache_entry **e = find_entry (name, namespace);
+
+  if (e == NULL)
+    return 0;
+  if (sym != NULL)
+    *sym = (*e)->sym;
+  if (block != NULL)
+    *block = (*e)->block;
+  return 1;
 }
 
+/* Assuming that (SYM, BLOCK) is the result of the lookup of NAME
+   in domain NAMESPACE, save this result in our symbol cache.  */
+
 static void
 cache_symbol (const char *name, domain_enum namespace, struct symbol *sym,
               const struct block *block)
 {
+  int h;
+  char *copy;
+  struct cache_entry *e;
+
+  /* If the symbol is a local symbol, then do not cache it, as a search
+     for that symbol depends on the context.  To determine whether
+     the symbol is local or not, we check the block where we found it
+     against the global and static blocks of its associated symtab.  */
+  if (sym
+      && BLOCKVECTOR_BLOCK (BLOCKVECTOR (sym->symtab), GLOBAL_BLOCK) != block
+      && BLOCKVECTOR_BLOCK (BLOCKVECTOR (sym->symtab), STATIC_BLOCK) != block)
+    return;
+
+  h = msymbol_hash (name) % HASH_SIZE;
+  e = (struct cache_entry *) obstack_alloc (&cache_space, sizeof (*e));
+  e->next = cache[h];
+  cache[h] = e;
+  e->name = copy = obstack_alloc (&cache_space, strlen (name) + 1);
+  strcpy (copy, name);
+  e->sym = sym;
+  e->namespace = namespace;
+  e->block = block;
 }
 \f
                                 /* Symbol Lookup */
@@ -13295,6 +13404,22 @@ initialize_ada_catchpoint_ops (void)
   ops->print_recreate = print_recreate_catch_assert;
 }
 
+/* This module's 'new_objfile' observer.  */
+
+static void
+ada_new_objfile_observer (struct objfile *objfile)
+{
+  ada_clear_symbol_cache ();
+}
+
+/* This module's 'free_objfile' observer.  */
+
+static void
+ada_free_objfile_observer (struct objfile *objfile)
+{
+  ada_clear_symbol_cache ();
+}
+
 void
 _initialize_ada_language (void)
 {
@@ -13373,6 +13498,10 @@ DWARF attribute."),
     (256, htab_hash_string, (int (*)(const void *, const void *)) streq,
      NULL, xcalloc, xfree);
 
+  /* The ada-lang observers.  */
+  observer_attach_new_objfile (ada_new_objfile_observer);
+  observer_attach_free_objfile (ada_free_objfile_observer);
+
   /* Setup per-inferior data.  */
   observer_attach_inferior_exit (ada_inferior_exit);
   ada_inferior_data