Index: gdb-6.5-prof/gdb/symtab.c =================================================================== --- gdb-6.5-prof.orig/gdb/symtab.c 2006-11-27 03:01:22.000000000 +0100 +++ gdb-6.5-prof/gdb/symtab.c 2006-11-28 01:21:28.000000000 +0100 @@ -94,6 +94,20 @@ struct symtab **symtab); static +int symcache_lookup (const char *name, + const char *linkage_name, + const domain_enum domain, + struct symbol **sym, + struct symtab **symtab); + +static +void symcache_add (struct symbol *sym, + const char *name, + const char *linkage_name, + const domain_enum domain, + struct symtab **symtab); + +static struct symbol *lookup_symbol_aux_symtabs (int block_index, const char *name, const char *linkage_name, @@ -1113,6 +1127,9 @@ } } + if (symcache_lookup (name, linkage_name, domain, &sym, symtab)) + return sym; + /* Now do whatever is appropriate for the current language to look up static and global variables. */ @@ -1120,7 +1137,7 @@ block, domain, symtab); if (sym != NULL) - return sym; + goto out; /* Now search all static file-level symbols. Not strictly correct, but more useful than an error. Do the symtabs first, then check @@ -1131,16 +1148,19 @@ sym = lookup_symbol_aux_symtabs (STATIC_BLOCK, name, linkage_name, domain, symtab); if (sym != NULL) - return sym; - + goto out; + sym = lookup_symbol_aux_psymtabs (STATIC_BLOCK, name, linkage_name, domain, symtab); if (sym != NULL) - return sym; + goto out; if (symtab != NULL) *symtab = NULL; - return NULL; + + out: + symcache_add (sym, name, linkage_name, domain, symtab); + return sym; } /* Check to see if the symbol is defined in BLOCK or its superiors. @@ -1215,6 +1235,177 @@ return NULL; } +/* Check for a cached symbol lookup. + */ + +struct symcache_entry { + const char *name; + const char *linkage_name; + domain_enum domain; + struct symbol *sym; + struct symtab *symtab; + struct symcache_entry *next, *prev; /* mru list */ +}; + +/* max number of entries in symcache */ +#define SYMCACHE_SIZE 256 + +/* fixed-size hash table of symcache entries */ +static htab_t symcache_hashtab; + +/* most recently accessed symcache entry */ +static struct symcache_entry *symcache_newest; + +static hashval_t +symcache_hash(const void *e) +{ + struct symcache_entry *entry = (struct symcache_entry *)e; + + return htab_hash_string (entry->name) + entry->domain; +} + +static int +symcache_eq(const void *e, const void *f) +{ + struct symcache_entry *a = (struct symcache_entry *)e; + struct symcache_entry *b = (struct symcache_entry *)f; + + return ! strcmp (a->name, b->name) + // FIXME && !strcmp(a->linkage_name, b->linkage_name) + && (a->domain == b->domain); +} + +static void +symcache_list_add(struct symcache_entry *entry) +{ + if (symcache_newest == NULL) + { + /* init mru */ + entry->prev = entry; + entry->next = entry; + symcache_newest = entry; + } + else + { + /* add entry at head of mru */ + entry->next = symcache_newest; + entry->prev = symcache_newest->prev; + entry->prev->next = entry; + entry->next->prev = entry; + symcache_newest = entry; + } +} + +static void +symcache_list_del(struct symcache_entry *entry) +{ + /* remove entry from mru */ + entry->prev->next = entry->next; + entry->next->prev = entry->prev; +} + +static void +symcache_del(void *e) +{ + struct symcache_entry *entry = (struct symcache_entry *)e; + + symcache_list_del (entry); + free (entry->name); + free (entry->linkage_name); + free (entry); +} + +static void +symcache_add (struct symbol *sym, + const char *name, + const char *linkage_name, + const domain_enum domain, + struct symtab **symtab) +{ + struct symcache_entry request, *entry, **slot; + + /* initialize on first use */ + if (!symcache_hashtab) + symcache_hashtab = htab_create_alloc (SYMCACHE_SIZE, + symcache_hash, + symcache_eq, + symcache_del, + xcalloc, + free); + + /* sym can be known, but with unknown symtab: add it if possible */ + request.name = name; + request.linkage_name = linkage_name; + request.domain = domain; + entry = htab_find (symcache_hashtab, &request); + if (entry != HTAB_EMPTY_ENTRY) + { + if (symtab != NULL) + entry->symtab = *symtab; + return; + } + + /* when cache is full, remove oldest element */ + if (htab_elements (symcache_hashtab) == SYMCACHE_SIZE) + { + struct symcache_entry *oldest; + + oldest = symcache_newest->prev; + htab_remove_elt (symcache_hashtab, oldest); + } + + /* this is really a new entry */ + entry = xcalloc (1, sizeof(*entry)); + entry->name = strdup (name); + entry->linkage_name = linkage_name ? strdup (linkage_name) : NULL; + entry->domain = domain; + entry->sym = sym; + if (symtab != NULL) + entry->symtab = *symtab; + symcache_list_add (entry); + + slot = htab_find_slot (symcache_hashtab, entry, INSERT); + *slot = entry; +} + +static int +symcache_lookup (const char *name, + const char *linkage_name, + const domain_enum domain, + struct symbol **sym, + struct symtab **symtab) +{ + struct symcache_entry request, *entry; + + if (!symcache_hashtab) + return 0; + + request.name = name; + request.linkage_name = linkage_name; + request.domain = domain; + entry = htab_find (symcache_hashtab, &request); + if (entry == HTAB_EMPTY_ENTRY) + return 0; + + if (symtab != NULL) + { + if (entry->symtab == NULL) + /* symtab is requested, but cached entry does not have it */ + return 0; + *symtab = entry->symtab; + } + *sym = entry->sym; + + /* keep mru list sorted */ + if (entry != symcache_newest) + { + symcache_list_del (entry); + symcache_list_add (entry); + } + + return 1; +} + /* Check to see if the symbol is defined in one of the symtabs. BLOCK_INDEX should be either GLOBAL_BLOCK or STATIC_BLOCK, depending on whether or not we want to search global symbols or