From 880b8135cc6257a87f072e0b3d44f1dd1f66afa4 Mon Sep 17 00:00:00 2001 From: Nikita Smith Date: Mon, 3 Nov 2025 11:37:03 -0800 Subject: [PATCH] add per-item purging to the hash table --- src/coff/coff_lib_writer.c | 5 +- src/linker/hash_table.c | 92 +++++++++++++++++++++++----------- src/linker/hash_table.h | 17 ++++--- src/linker/lnk.c | 2 +- src/linker/lnk_config.c | 14 +++--- src/linker/lnk_debug_info.c | 13 +++-- src/linker/lnk_section_table.c | 4 +- 7 files changed, 89 insertions(+), 58 deletions(-) diff --git a/src/coff/coff_lib_writer.c b/src/coff/coff_lib_writer.c index aeb9a3d2..152e558a 100644 --- a/src/coff/coff_lib_writer.c +++ b/src/coff/coff_lib_writer.c @@ -184,10 +184,7 @@ coff_lib_writer_serialize(Arena *arena, COFF_LibWriter *lib_writer, COFF_TimeSta U64 name_with_slash_size = member->name.size + 1; if (name_with_slash_size > COFF_Archive_MaxShortNameSize) { // have we seen this member name before? - KeyValuePair *is_present = hash_table_search_string(name_ht, member->name); - if (is_present) { - name = is_present->value_string; - } else { + if (!hash_table_search_string_string(name_ht, member->name, &name)) { name = push_str8f(scratch.arena, "/%u", long_names_list.total_size); str8_list_pushf(scratch.arena, &long_names_list, "%S/\n", member->name); hash_table_push_string_string(scratch.arena, name_ht, member->name, name); diff --git a/src/linker/hash_table.c b/src/linker/hash_table.c index 22276591..58c9daea 100644 --- a/src/linker/hash_table.c +++ b/src/linker/hash_table.c @@ -64,8 +64,8 @@ hash_table_push(Arena *arena, HashTable *ht, U64 hash, KeyValuePair v) node->v = v; U64 ibucket = hash % ht->cap; - SLLQueuePush(ht->buckets[ibucket].first, ht->buckets[ibucket].last, node); - ++ht->count; + DLLPushBack(ht->buckets[ibucket].first, ht->buckets[ibucket].last, node); + ht->count += 1; return node; } @@ -162,7 +162,7 @@ hash_table_push_path_raw(Arena *arena, HashTable *ht, String8 path, void *value) //////////////////////////////// -internal KeyValuePair * +internal BucketNode * hash_table_search_string(HashTable *ht, String8 key_string) { U64 hash = hash_table_hasher(key_string); @@ -170,13 +170,13 @@ hash_table_search_string(HashTable *ht, String8 key_string) BucketList *bucket = ht->buckets + ibucket; for (BucketNode *n = bucket->first; n != 0; n = n->next) { if (str8_match(n->v.key_string, key_string, 0)) { - return &n->v; + return n; } } return 0; } -internal KeyValuePair * +internal BucketNode * hash_table_search_u32(HashTable *ht, U32 key_u32) { U64 hash = hash_table_hasher(str8_struct(&key_u32)); @@ -184,13 +184,13 @@ hash_table_search_u32(HashTable *ht, U32 key_u32) BucketList *bucket = ht->buckets + ibucket; for (BucketNode *n = bucket->first; n != 0; n = n->next) { if (n->v.key_u32 == key_u32) { - return &n->v; + return n; } } return 0; } -internal KeyValuePair * +internal BucketNode * hash_table_search_u64(HashTable *ht, U64 key_u64) { U64 hash = hash_table_hasher(str8_struct(&key_u64)); @@ -198,25 +198,25 @@ hash_table_search_u64(HashTable *ht, U64 key_u64) BucketList *bucket = ht->buckets + ibucket; for (BucketNode *n = bucket->first; n != 0; n = n->next) { if (n->v.key_u64 == key_u64) { - return &n->v; + return n; } } return 0; } -internal KeyValuePair * +internal BucketNode * hash_table_search_path(HashTable *ht, String8 path) { Temp scratch = scratch_begin(0,0); String8 path_canon = path; path_canon = lower_from_str8(scratch.arena, path_canon); path_canon = path_convert_slashes(scratch.arena, path_canon, PathStyle_UnixAbsolute); - KeyValuePair *result = hash_table_search_string(ht, path_canon); + BucketNode *result = hash_table_search_string(ht, path_canon); scratch_end(scratch); return result; } -internal KeyValuePair * +internal BucketNode * hash_table_search_raw(HashTable *ht, void *key) { U64 hash = hash_table_hasher(str8_struct(&key)); @@ -224,7 +224,7 @@ hash_table_search_raw(HashTable *ht, void *key) BucketList *bucket = ht->buckets + ibucket; for (BucketNode *n = bucket->first; n != 0; n = n->next) { if (n->v.key_raw == key) { - return &n->v; + return n; } } return 0; @@ -233,10 +233,10 @@ hash_table_search_raw(HashTable *ht, void *key) internal B32 hash_table_search_path_u64(HashTable *ht, String8 key, U64 *value_out) { - KeyValuePair *result = hash_table_search_path(ht, key); + BucketNode *result = hash_table_search_path(ht, key); if (result != 0) { if (value_out != 0) { - *value_out = result->value_u64; + *value_out = result->v.value_u64; } return 1; } @@ -260,10 +260,10 @@ hash_table_push_raw_raw(Arena *arena, HashTable *ht, void *key, void *value) internal B32 hash_table_search_string_u64(HashTable *ht, String8 key, U64 *value_out) { - KeyValuePair *result = hash_table_search_string(ht, key); + BucketNode *result = hash_table_search_string(ht, key); if (result != 0) { if (value_out != 0) { - *value_out = result->value_u64; + *value_out = result->v.value_u64; } return 1; } @@ -273,10 +273,10 @@ hash_table_search_string_u64(HashTable *ht, String8 key, U64 *value_out) internal B32 hash_table_search_string_string(HashTable *ht, String8 key, String8 *value_out) { - KeyValuePair *result = hash_table_search_string(ht, key); + BucketNode *result = hash_table_search_string(ht, key); if (result) { if (value_out) { - *value_out = result->value_string; + *value_out = result->v.value_string; } return 1; } @@ -286,10 +286,10 @@ hash_table_search_string_string(HashTable *ht, String8 key, String8 *value_out) internal B32 hash_table_search_u32_u32(HashTable *ht, U32 key, U32 *value_out) { - KeyValuePair *result = hash_table_search_u32(ht, key); + BucketNode *result = hash_table_search_u32(ht, key); if (result) { if (value_out) { - *value_out = result->value_u32; + *value_out = result->v.value_u32; } return 1; } @@ -299,9 +299,9 @@ hash_table_search_u32_u32(HashTable *ht, U32 key, U32 *value_out) internal void * hash_table_search_string_raw(HashTable *ht, String8 key) { - KeyValuePair *result = hash_table_search_string(ht, key); + BucketNode *result = hash_table_search_string(ht, key); if (result) { - return result->value_raw; + return result->v.value_raw; } return 0; } @@ -309,22 +309,54 @@ hash_table_search_string_raw(HashTable *ht, String8 key) internal void * hash_table_search_u64_raw(HashTable *ht, U64 key_u64) { - KeyValuePair *kv = hash_table_search_u64(ht, key_u64); - return kv ? kv->value_raw : 0; + BucketNode *n = hash_table_search_u64(ht, key_u64); + return n ? n->v.value_raw : 0; } internal void * hash_table_search_path_raw(HashTable *ht, String8 path) { - KeyValuePair *kv = hash_table_search_path(ht, path); - return kv ? kv->value_raw : 0; + BucketNode *n = hash_table_search_path(ht, path); + return n ? n->v.value_raw : 0; } internal void * hash_table_search_raw_raw(HashTable *ht, void *key) { - KeyValuePair *kv = hash_table_search_raw(ht, key); - return kv ? kv->value_raw : 0; + BucketNode *n = hash_table_search_raw(ht, key); + return n ? n->v.value_raw : 0; +} + +internal void +hash_table_purge_item(HashTable *ht, U64 hash, BucketNode *node) +{ + U64 bucket_idx = hash % ht->cap; + DLLRemove(ht->buckets[bucket_idx].first, ht->buckets[bucket_idx].last, node); + ht->count -= 1; +} + +internal B32 +hash_table_purge_u64(HashTable *ht, U64 key) +{ + U64 hash = hash_table_hasher(str8_struct(&key)); + BucketNode *n = hash_table_search_u64(ht, key); + if (n) { + hash_table_purge_item(ht, hash, n); + return 1; + } + return 0; +} + +internal B32 +hash_table_purge_string(HashTable *ht, String8 key) +{ + U64 hash = hash_table_hasher(key); + BucketNode *n = hash_table_search_string(ht, key); + if (n) { + hash_table_purge_item(ht, hash, n); + return 1; + } + return 0; } internal int @@ -451,7 +483,7 @@ remove_duplicates_u64_array(Arena *arena, U64Array arr) HashTable *ht = hash_table_init(scratch.arena, ((U64)(F64)arr.count * 0.5)); for (U64 i = 0; i < arr.count; ++i) { - KeyValuePair *is_present = hash_table_search_u64(ht, arr.v[i]); + BucketNode *is_present = hash_table_search_u64(ht, arr.v[i]); if (!is_present) { hash_table_push_u64_raw(scratch.arena, ht, arr.v[i], 0); } @@ -474,7 +506,7 @@ remove_duplicates_str8_list(Arena *arena, String8List list) HashTable *ht = hash_table_init(scratch.arena, list.node_count); for (String8Node *node = list.first; node != 0; node = node->next) { - KeyValuePair *is_present = hash_table_search_string(ht, node->string); + BucketNode *is_present = hash_table_search_string(ht, node->string); if (!is_present) { hash_table_push_string_raw(scratch.arena, ht, node->string, 0); str8_list_push(arena, &result, node->string); diff --git a/src/linker/hash_table.h b/src/linker/hash_table.h index 67e9e3dd..6498f14b 100644 --- a/src/linker/hash_table.h +++ b/src/linker/hash_table.h @@ -21,8 +21,9 @@ typedef struct KeyValuePair typedef struct BucketNode { - struct BucketNode *next; KeyValuePair v; + struct BucketNode *next; + struct BucketNode *prev; } BucketNode; typedef struct BucketList @@ -64,11 +65,11 @@ internal BucketNode * hash_table_push_path_u64 (Arena *arena, HashTable *ht, internal BucketNode * hash_table_push_u64_u64 (Arena *arena, HashTable *ht, U64 key, U64 value); internal BucketNode * hash_table_push_u32_u32 (Arena *arena, HashTable *ht, U32 key, U32 value); -internal KeyValuePair * hash_table_search_string (HashTable *ht, String8 key); -internal KeyValuePair * hash_table_search_u32 (HashTable *ht, U32 key); -internal KeyValuePair * hash_table_search_u64 (HashTable *ht, U64 key); -internal KeyValuePair * hash_table_search_path (HashTable *ht, String8 key); -internal KeyValuePair * hash_table_search_raw (HashTable *ht, void *key); +internal BucketNode * hash_table_search_string (HashTable *ht, String8 key); +internal BucketNode * hash_table_search_u32 (HashTable *ht, U32 key); +internal BucketNode * hash_table_search_u64 (HashTable *ht, U64 key); +internal BucketNode * hash_table_search_path (HashTable *ht, String8 key); +internal BucketNode * hash_table_search_raw (HashTable *ht, void *key); internal B32 hash_table_search_path_u64 (HashTable *ht, String8 key, U64 *value_out); internal B32 hash_table_search_string_u64 (HashTable *ht, String8 key, U64 *value_out); @@ -80,6 +81,10 @@ internal void * hash_table_search_u64_raw (HashTable *ht, U64 key); internal void * hash_table_search_path_raw (HashTable *ht, String8 key); internal void * hash_table_search_raw_raw (HashTable *ht, void *key); +internal void hash_table_purge_item (HashTable *ht, U64 hash, BucketNode *node); +internal B32 hash_table_purge_u64 (HashTable *ht, U64 key); +internal B32 hash_table_purge_string(HashTable *ht, String8 key); + // --- Key Value Helpers ------------------------------------------------------- internal U32 * keys_from_hash_table_u32 (Arena *arena, HashTable *ht); diff --git a/src/linker/lnk.c b/src/linker/lnk.c index 1a1c9b19..65534ce8 100644 --- a/src/linker/lnk.c +++ b/src/linker/lnk.c @@ -1086,7 +1086,7 @@ lnk_inputer_push_lib_thin(LNK_Inputer *inputer, LNK_Config *config, LNK_InputSou // warn about missing library if (first_match.size == 0) { - KeyValuePair *was_reported = hash_table_search_path(inputer->missing_lib_ht, path); + BucketNode *was_reported = hash_table_search_path(inputer->missing_lib_ht, path); if (was_reported == 0) { hash_table_push_path_u64(inputer->arena, inputer->missing_lib_ht, path, 0); lnk_error(LNK_Warning_FileNotFound, "unable to find library `%S`", path); diff --git a/src/linker/lnk_config.c b/src/linker/lnk_config.c index a06de23b..c47d366c 100644 --- a/src/linker/lnk_config.c +++ b/src/linker/lnk_config.c @@ -1072,10 +1072,10 @@ lnk_expand_env_vars_windows(Arena *arena, HashTable *env_vars, String8 string) i += text.size; if (open < close) { - String8 env_var_name = str8_substr(string, rng_1u64(open+1, close)); - KeyValuePair *match = hash_table_search_path(env_vars, env_var_name); + String8 env_var_name = str8_substr(string, rng_1u64(open+1, close)); + BucketNode *match = hash_table_search_path(env_vars, env_var_name); if (match) { - str8_list_push(scratch.arena, &list, match->value_string); + str8_list_push(scratch.arena, &list, match->v.value_string); i = close+1; } else { str8_list_pushf(scratch.arena, &list, "%%%S", env_var_name); @@ -2277,16 +2277,16 @@ lnk_config_from_cmd_line(String8List raw_cmd_line, LNK_CmdLine cmd_line) // collect LIB and LIBPATH if (config->flags & LNK_ConfigFlag_EnvLib) { - KeyValuePair *lib = hash_table_search_path(env_vars, str8_lit("lib")); + BucketNode *lib = hash_table_search_path(env_vars, str8_lit("lib")); if (lib) { - String8List val_list = str8_split_by_string_chars(scratch.arena, lib->value_string, str8_lit(";"), 0); + String8List val_list = str8_split_by_string_chars(scratch.arena, lib->v.value_string, str8_lit(";"), 0); String8List val_list_copy = str8_list_copy(arena, &val_list); str8_list_concat_in_place(&config->lib_dir_list, &val_list_copy); } - KeyValuePair *lib_path = hash_table_search_path(env_vars, str8_lit("libpath")); + BucketNode *lib_path = hash_table_search_path(env_vars, str8_lit("libpath")); if (lib_path) { - String8List val_list = str8_split_by_string_chars(scratch.arena, lib->value_string, str8_lit(";"), 0); + String8List val_list = str8_split_by_string_chars(scratch.arena, lib->v.value_string, str8_lit(";"), 0); String8List val_list_copy = str8_list_copy(arena, &val_list); str8_list_concat_in_place(&config->lib_dir_list, &val_list_copy); } diff --git a/src/linker/lnk_debug_info.c b/src/linker/lnk_debug_info.c index d277bee8..e546f3f3 100644 --- a/src/linker/lnk_debug_info.c +++ b/src/linker/lnk_debug_info.c @@ -587,9 +587,9 @@ lnk_make_code_view_input(TP_Context *tp, TP_Arena *tp_arena, LNK_IO_Flags io_fla }; // was this type server queued? - KeyValuePair *is_path_queued = hash_table_search_path(type_server_path_ht, type_server_path); + BucketNode *is_path_queued = hash_table_search_path(type_server_path_ht, type_server_path); if (is_path_queued) { - struct HT_Value *present = is_path_queued->value_raw; + struct HT_Value *present = is_path_queued->v.value_raw; // make sure type servers sigs match if (MemoryMatchStruct(&ts.sig, &present->ts.sig)) { @@ -4705,9 +4705,9 @@ THREAD_POOL_TASK_FUNC(lnk_convert_symbols_to_rdi_task) // get link name through virtual offset look up String8 link_name = {0}; if (symbol.kind == CV_SymKind_GDATA32) { - KeyValuePair *pair = hash_table_search_u64(task->extern_symbol_voff_ht, data_voff); + BucketNode *pair = hash_table_search_u64(task->extern_symbol_voff_ht, data_voff); if (pair != 0) { - LNK_Symbol *link_symbol = pair->value_raw; + LNK_Symbol *link_symbol = pair->v.value_raw; link_name = link_symbol->name; } } @@ -4801,9 +4801,8 @@ THREAD_POOL_TASK_FUNC(lnk_convert_symbols_to_rdi_task) // get link name through virtual offset look up String8 link_name = str8(0,0); if (symbol.kind == CV_SymKind_GPROC32) { - KeyValuePair *pair = hash_table_search_u64(task->extern_symbol_voff_ht, virt_range.min); - if (pair != 0) { - LNK_Symbol *link_symbol = pair->value_raw; + LNK_Symbol *link_symbol = hash_table_search_u64_raw(task->extern_symbol_voff_ht, virt_range.min); + if (link_symbol) { link_name = link_symbol->name; } } diff --git a/src/linker/lnk_section_table.c b/src/linker/lnk_section_table.c index 7c3a464e..a095e64e 100644 --- a/src/linker/lnk_section_table.c +++ b/src/linker/lnk_section_table.c @@ -161,9 +161,7 @@ lnk_section_table_purge(LNK_SectionTable *sectab, String8 name) LNK_SectionNode *node = lnk_section_table_remove(sectab, name); String8 name_with_flags = lnk_make_name_with_flags(scratch.arena, name, node->data.flags); - KeyValuePair *kv = hash_table_search_string(sectab->sect_ht, name_with_flags); - kv->key_string = str8_zero(); - kv->value_raw = 0; + hash_table_purge_string(sectab->sect_ht, name_with_flags); scratch_end(scratch); }