From 1339dc6a2f534872c7082ee497210bef079b26e6 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Mon, 11 Oct 2021 13:01:07 -0700 Subject: [PATCH] libdrgn: hash_table: move entry_to_key to DEFINE_HASH_TABLE_FUNCTIONS() DEFINE_HASH_TABLE_TYPE() doesn't actually need to know the key type. Move that argument (and some of the derived constants) to DEFINE_HASH_TABLE_FUNCTIONS(). This will allow recursive hash table types. As a nice side effect, it also reduces the size of common header files. Signed-off-by: Omar Sandoval --- libdrgn/debug_info.c | 24 ++++- libdrgn/debug_info.h | 19 +--- libdrgn/dwarf_index.c | 11 +- libdrgn/dwarf_index.h | 9 +- libdrgn/hash_table.h | 212 ++++++++++++++++++++++----------------- libdrgn/program.c | 2 +- libdrgn/python/program.c | 2 +- libdrgn/type.c | 10 +- 8 files changed, 157 insertions(+), 132 deletions(-) diff --git a/libdrgn/debug_info.c b/libdrgn/debug_info.c index e5f193a8..007b6830 100644 --- a/libdrgn/debug_info.c +++ b/libdrgn/debug_info.c @@ -480,6 +480,23 @@ err: DEFINE_VECTOR_FUNCTIONS(drgn_debug_info_module_vector) +struct drgn_debug_info_module_key { + const void *build_id; + size_t build_id_len; + uint64_t start, end; +}; + +static inline struct drgn_debug_info_module_key +drgn_debug_info_module_key(struct drgn_debug_info_module * const *entry) +{ + return (struct drgn_debug_info_module_key){ + .build_id = (*entry)->build_id, + .build_id_len = (*entry)->build_id_len, + .start = (*entry)->start, + .end = (*entry)->end, + }; +} + static inline struct hash_pair drgn_debug_info_module_key_hash_pair(const struct drgn_debug_info_module_key *key) { @@ -497,11 +514,11 @@ drgn_debug_info_module_key_eq(const struct drgn_debug_info_module_key *a, a->start == b->start && a->end == b->end); } DEFINE_HASH_TABLE_FUNCTIONS(drgn_debug_info_module_table, + drgn_debug_info_module_key, drgn_debug_info_module_key_hash_pair, drgn_debug_info_module_key_eq) -DEFINE_HASH_TABLE_FUNCTIONS(c_string_set, c_string_key_hash_pair, - c_string_key_eq) +DEFINE_HASH_SET_FUNCTIONS(c_string_set, c_string_key_hash_pair, c_string_key_eq) /** * @c Dwfl_Callbacks::find_elf() implementation. @@ -2566,8 +2583,7 @@ out: return err; } -DEFINE_HASH_TABLE_FUNCTIONS(drgn_dwarf_type_map, ptr_key_hash_pair, - scalar_key_eq) +DEFINE_HASH_MAP_FUNCTIONS(drgn_dwarf_type_map, ptr_key_hash_pair, scalar_key_eq) /** * Return whether a DWARF DIE is little-endian. diff --git a/libdrgn/debug_info.h b/libdrgn/debug_info.h index f8476c59..b53ac8ae 100644 --- a/libdrgn/debug_info.h +++ b/libdrgn/debug_info.h @@ -244,25 +244,8 @@ struct drgn_error *drgn_find_die_ancestors(Dwarf_Die *die, Dwarf_Die **dies_ret, size_t *length_ret) __attribute__((__nonnull__(2, 3))); -struct drgn_debug_info_module_key { - const void *build_id; - size_t build_id_len; - uint64_t start, end; -}; - -static inline struct drgn_debug_info_module_key -drgn_debug_info_module_key(struct drgn_debug_info_module * const *entry) -{ - return (struct drgn_debug_info_module_key){ - .build_id = (*entry)->build_id, - .build_id_len = (*entry)->build_id_len, - .start = (*entry)->start, - .end = (*entry)->end, - }; -} DEFINE_HASH_TABLE_TYPE(drgn_debug_info_module_table, - struct drgn_debug_info_module *, - drgn_debug_info_module_key) + struct drgn_debug_info_module *) DEFINE_HASH_SET_TYPE(c_string_set, const char *) diff --git a/libdrgn/dwarf_index.c b/libdrgn/dwarf_index.c index bc200ac4..3e213ce1 100644 --- a/libdrgn/dwarf_index.c +++ b/libdrgn/dwarf_index.c @@ -185,10 +185,17 @@ struct drgn_dwarf_index_pending_die { DEFINE_VECTOR_FUNCTIONS(drgn_dwarf_index_pending_die_vector) -DEFINE_HASH_TABLE_FUNCTIONS(drgn_dwarf_index_die_map, string_hash_pair, - string_eq) +DEFINE_HASH_MAP_FUNCTIONS(drgn_dwarf_index_die_map, string_hash_pair, string_eq) DEFINE_VECTOR_FUNCTIONS(drgn_dwarf_index_die_vector) + +static inline uintptr_t +drgn_dwarf_index_specification_to_key(const struct drgn_dwarf_index_specification *entry) +{ + return entry->declaration; +} + DEFINE_HASH_TABLE_FUNCTIONS(drgn_dwarf_index_specification_map, + drgn_dwarf_index_specification_to_key, int_key_hash_pair, scalar_key_eq) static inline size_t hash_pair_to_shard(struct hash_pair hp) diff --git a/libdrgn/dwarf_index.h b/libdrgn/dwarf_index.h index 7551111d..b82f9412 100644 --- a/libdrgn/dwarf_index.h +++ b/libdrgn/dwarf_index.h @@ -123,15 +123,8 @@ struct drgn_dwarf_index_specification { uintptr_t addr; }; -static inline uintptr_t -drgn_dwarf_index_specification_to_key(const struct drgn_dwarf_index_specification *entry) -{ - return entry->declaration; -} - DEFINE_HASH_TABLE_TYPE(drgn_dwarf_index_specification_map, - struct drgn_dwarf_index_specification, - drgn_dwarf_index_specification_to_key) + struct drgn_dwarf_index_specification) DEFINE_VECTOR_TYPE(drgn_dwarf_index_cu_vector, struct drgn_dwarf_index_cu) diff --git a/libdrgn/hash_table.h b/libdrgn/hash_table.h index 0b9368a9..428a7806 100644 --- a/libdrgn/hash_table.h +++ b/libdrgn/hash_table.h @@ -375,15 +375,8 @@ static inline unsigned int table##_chunk_occupied(struct table##_chunk *chunk) \ * * @sa DEFINE_HASH_TABLE() */ -#define DEFINE_HASH_TABLE_TYPE(table, entry_type, entry_to_key) \ +#define DEFINE_HASH_TABLE_TYPE(table, entry_type) \ typedef typeof(entry_type) table##_entry_type; \ -typedef typeof(entry_to_key((table##_entry_type *)0)) table##_key_type; \ - \ -static inline table##_key_type \ -table##_entry_to_key(const table##_entry_type *entry) \ -{ \ - return entry_to_key(entry); \ -} \ \ enum { \ /* \ @@ -395,6 +388,79 @@ enum { \ table##_vector_policy = sizeof(table##_entry_type) >= 24, \ }; \ \ +struct table { \ + struct table##_chunk *chunks; \ + struct { \ + /* \ + * The vector storage policy stores 32-bit indices, so we only \ + * need 32-bit sizes. \ + */ \ + uint32_t chunk_mask; \ + uint32_t size; \ + /* Allocated together with chunks. */ \ + table##_entry_type *entries; \ + } vector[table##_vector_policy]; \ + struct { \ + size_t chunk_mask; \ + size_t size; \ + uintptr_t first_packed; \ + } basic[!table##_vector_policy]; \ +}; + +/* + * Common search function implementation returning an item iterator. This is + * shared by key lookups and index lookups. + */ +#define HASH_TABLE_SEARCH_IMPL(table, func, key_type, item_to_key, eq_func) \ +static struct table##_iterator table##_##func(struct table *table, \ + const key_type *key, \ + struct hash_pair hp) \ +{ \ + const size_t delta = hash_table_probe_delta(hp); \ + size_t index = hp.first; \ + for (size_t tries = 0; tries <= table##_chunk_mask(table); tries++) { \ + struct table##_chunk *chunk = \ + &table->chunks[index & table##_chunk_mask(table)]; \ + if (sizeof(*chunk) > 64) \ + __builtin_prefetch(&chunk->items[8]); \ + unsigned int mask = table##_chunk_match(chunk, hp.second), i; \ + for_each_bit(i, mask) { \ + table##_item_type *item = &chunk->items[i]; \ + key_type item_key = item_to_key(table, item); \ + if (likely(eq_func(key, &item_key))) { \ + return (struct table##_iterator){ \ + .item = item, \ + .index = i, \ + }; \ + } \ + } \ + if (likely(chunk->outbound_overflow_count == 0)) \ + break; \ + index += delta; \ + } \ + return (struct table##_iterator){}; \ +} + +#define HASH_TABLE_SEARCH_BY_INDEX_ITEM_TO_KEY(table, item) (*(item)->index) + +/** + * Define the functions for a hash table. + * + * The hash table type must have already been defined with @ref + * DEFINE_HASH_TABLE_TYPE(). + * + * Unless the type and function definitions must be in separate places, use @ref + * DEFINE_HASH_TABLE() instead. + */ +#define DEFINE_HASH_TABLE_FUNCTIONS(table, entry_to_key, hash_func, eq_func) \ +typedef typeof(entry_to_key((table##_entry_type *)0)) table##_key_type; \ + \ +static inline table##_key_type \ +table##_entry_to_key(const table##_entry_type *entry) \ +{ \ + return entry_to_key(entry); \ +} \ + \ /* \ * Item stored in a chunk. \ * \ @@ -489,73 +555,6 @@ struct table##_iterator { \ }; \ }; \ \ -struct table { \ - struct table##_chunk *chunks; \ - struct { \ - /* \ - * The vector storage policy stores 32-bit indices, so we only \ - * need 32-bit sizes. \ - */ \ - uint32_t chunk_mask; \ - uint32_t size; \ - /* Allocated together with chunks. */ \ - table##_entry_type *entries; \ - } vector[table##_vector_policy]; \ - struct { \ - size_t chunk_mask; \ - size_t size; \ - uintptr_t first_packed; \ - } basic[!table##_vector_policy]; \ -}; - -/* - * Common search function implementation returning an item iterator. This is - * shared by key lookups and index lookups. - */ -#define HASH_TABLE_SEARCH_IMPL(table, func, key_type, item_to_key, eq_func) \ -static struct table##_iterator table##_##func(struct table *table, \ - const key_type *key, \ - struct hash_pair hp) \ -{ \ - const size_t delta = hash_table_probe_delta(hp); \ - size_t index = hp.first; \ - for (size_t tries = 0; tries <= table##_chunk_mask(table); tries++) { \ - struct table##_chunk *chunk = \ - &table->chunks[index & table##_chunk_mask(table)]; \ - if (sizeof(*chunk) > 64) \ - __builtin_prefetch(&chunk->items[8]); \ - unsigned int mask = table##_chunk_match(chunk, hp.second), i; \ - for_each_bit(i, mask) { \ - table##_item_type *item = &chunk->items[i]; \ - key_type item_key = item_to_key(table, item); \ - if (likely(eq_func(key, &item_key))) { \ - return (struct table##_iterator){ \ - .item = item, \ - .index = i, \ - }; \ - } \ - } \ - if (likely(chunk->outbound_overflow_count == 0)) \ - break; \ - index += delta; \ - } \ - return (struct table##_iterator){}; \ -} - -#define HASH_TABLE_SEARCH_BY_INDEX_ITEM_TO_KEY(table, item) (*(item)->index) - -/** - * Define the functions for a hash table. - * - * The hash table type must have already been defined with @ref - * DEFINE_HASH_TABLE_TYPE(). - * - * Unless the type and function definitions must be in separate places, use @ref - * DEFINE_HASH_TABLE() instead. - * - * @sa DEFINE_HASH_TABLE() - */ -#define DEFINE_HASH_TABLE_FUNCTIONS(table, hash_func, eq_func) \ static inline struct hash_pair table##_hash(const table##_key_type *key) \ { \ return hash_func(key); \ @@ -1425,24 +1424,38 @@ static struct table##_iterator table##_next(struct table##_iterator it) \ * * and returns a @c bool. */ #define DEFINE_HASH_TABLE(table, entry_type, entry_to_key, hash_func, eq_func) \ -DEFINE_HASH_TABLE_TYPE(table, entry_type, entry_to_key) \ -DEFINE_HASH_TABLE_FUNCTIONS(table, hash_func, eq_func) - -#define HASH_MAP_ENTRY_TO_KEY(entry) ((entry)->key) +DEFINE_HASH_TABLE_TYPE(table, entry_type) \ +DEFINE_HASH_TABLE_FUNCTIONS(table, entry_to_key, hash_func, eq_func) /** * Define a hash map type without defining its functions. * - * The functions are defined with @ref DEFINE_HASH_TABLE_FUNCTIONS(). + * The functions are defined with @ref DEFINE_HASH_MAP_FUNCTIONS(). * * @sa DEFINE_HASH_MAP(), DEFINE_HASH_TABLE_TYPE() */ -#define DEFINE_HASH_MAP_TYPE(table, key_type, value_type) \ -struct table##_entry { \ - typeof(key_type) key; \ - typeof(value_type) value; \ -}; \ -DEFINE_HASH_TABLE_TYPE(table, struct table##_entry, HASH_MAP_ENTRY_TO_KEY) +#define DEFINE_HASH_MAP_TYPE(table, key_type, value_type) \ +struct table##_entry { \ + typeof(key_type) key; \ + typeof(value_type) value; \ +}; \ +DEFINE_HASH_TABLE_TYPE(table, struct table##_entry) + +#define HASH_MAP_ENTRY_TO_KEY(entry) ((entry)->key) + +/** + * Define the functions for a hash map. + * + * The hash map type must have already been defined with @ref + * DEFINE_HASH_MAP_TYPE(). + * + * Unless the type and function definitions must be in separate places, use @ref + * DEFINE_HASH_MAP() instead. + * + * @sa DEFINE_HASH_TABLE_FUNCTIONS + */ +#define DEFINE_HASH_MAP_FUNCTIONS(table, hash_func, eq_func) \ +DEFINE_HASH_TABLE_FUNCTIONS(table, HASH_MAP_ENTRY_TO_KEY, hash_func, eq_func) /** * Define a hash map interface. @@ -1466,19 +1479,32 @@ DEFINE_HASH_TABLE_TYPE(table, struct table##_entry, HASH_MAP_ENTRY_TO_KEY) */ #define DEFINE_HASH_MAP(table, key_type, value_type, hash_func, eq_func) \ DEFINE_HASH_MAP_TYPE(table, key_type, value_type) \ -DEFINE_HASH_TABLE_FUNCTIONS(table, hash_func, eq_func) - -#define HASH_SET_ENTRY_TO_KEY(entry) (*(entry)) +DEFINE_HASH_MAP_FUNCTIONS(table, hash_func, eq_func) /** * Define a hash set type without defining its functions. * - * The functions are defined with @ref DEFINE_HASH_TABLE_FUNCTIONS(). + * The functions are defined with @ref DEFINE_HASH_SET_FUNCTIONS(). * * @sa DEFINE_HASH_SET(), DEFINE_HASH_TABLE_TYPE() */ -#define DEFINE_HASH_SET_TYPE(table, key_type) \ - DEFINE_HASH_TABLE_TYPE(table, key_type, HASH_SET_ENTRY_TO_KEY) +#define DEFINE_HASH_SET_TYPE DEFINE_HASH_TABLE_TYPE + +#define HASH_SET_ENTRY_TO_KEY(entry) (*(entry)) + +/** + * Define the functions for a hash set. + * + * The hash set type must have already been defined with @ref + * DEFINE_HASH_SET_TYPE(). + * + * Unless the type and function definitions must be in separate places, use @ref + * DEFINE_HASH_SET() instead. + * + * @sa DEFINE_HASH_TABLE_FUNCTIONS + */ +#define DEFINE_HASH_SET_FUNCTIONS(table, hash_func, eq_func) \ +DEFINE_HASH_TABLE_FUNCTIONS(table, HASH_SET_ENTRY_TO_KEY, hash_func, eq_func) /** * Define a hash set interface. @@ -1494,7 +1520,7 @@ DEFINE_HASH_TABLE_FUNCTIONS(table, hash_func, eq_func) */ #define DEFINE_HASH_SET(table, key_type, hash_func, eq_func) \ DEFINE_HASH_SET_TYPE(table, key_type) \ -DEFINE_HASH_TABLE_FUNCTIONS(table, hash_func, eq_func) +DEFINE_HASH_SET_FUNCTIONS(table, hash_func, eq_func) /** * Empty hash table initializer. diff --git a/libdrgn/program.c b/libdrgn/program.c index b17dec1a..7e18157f 100644 --- a/libdrgn/program.c +++ b/libdrgn/program.c @@ -32,7 +32,7 @@ #include "util.h" DEFINE_VECTOR_FUNCTIONS(drgn_prstatus_vector) -DEFINE_HASH_TABLE_FUNCTIONS(drgn_prstatus_map, int_key_hash_pair, scalar_key_eq) +DEFINE_HASH_MAP_FUNCTIONS(drgn_prstatus_map, int_key_hash_pair, scalar_key_eq) static Elf_Type note_header_type(GElf_Phdr *phdr) { diff --git a/libdrgn/python/program.c b/libdrgn/python/program.c index 70a20f24..06d6ce36 100644 --- a/libdrgn/python/program.c +++ b/libdrgn/python/program.c @@ -7,7 +7,7 @@ #include "../vector.h" #include "../util.h" -DEFINE_HASH_TABLE_FUNCTIONS(pyobjectp_set, ptr_key_hash_pair, scalar_key_eq) +DEFINE_HASH_SET_FUNCTIONS(pyobjectp_set, ptr_key_hash_pair, scalar_key_eq) int Program_hold_object(Program *prog, PyObject *obj) { diff --git a/libdrgn/type.c b/libdrgn/type.c index 7492c42a..cd91f686 100644 --- a/libdrgn/type.c +++ b/libdrgn/type.c @@ -170,10 +170,10 @@ static bool drgn_member_key_eq(const struct drgn_member_key *a, (!a->name_len || memcmp(a->name, b->name, a->name_len) == 0)); } -DEFINE_HASH_TABLE_FUNCTIONS(drgn_member_map, drgn_member_key_hash_pair, - drgn_member_key_eq) +DEFINE_HASH_MAP_FUNCTIONS(drgn_member_map, drgn_member_key_hash_pair, + drgn_member_key_eq) -DEFINE_HASH_TABLE_FUNCTIONS(drgn_type_set, ptr_key_hash_pair, scalar_key_eq) +DEFINE_HASH_SET_FUNCTIONS(drgn_type_set, ptr_key_hash_pair, scalar_key_eq) LIBDRGN_PUBLIC struct drgn_error * drgn_member_object(struct drgn_type_member *member, @@ -329,8 +329,8 @@ static bool drgn_type_dedupe_eq(struct drgn_type * const *entry_a, * We don't deduplicate types with members, parameters, template parameters, or * enumerators, so the hash and comparison functions ignore those. */ -DEFINE_HASH_TABLE_FUNCTIONS(drgn_dedupe_type_set, drgn_type_dedupe_hash_pair, - drgn_type_dedupe_eq) +DEFINE_HASH_SET_FUNCTIONS(drgn_dedupe_type_set, drgn_type_dedupe_hash_pair, + drgn_type_dedupe_eq) DEFINE_VECTOR_FUNCTIONS(drgn_typep_vector)