switch to thread safe hash trie map

Initial implementation of the symbol table allowed us to push symbols
from one thread at a time and required a wonky lock-step and spread out
logic for replacing symbols. And because it was a externally chained
hash table we had to guesstimate optimal capacity for small and big targets.
We erred on the side of larger capacity to prevent degradation and
rehashing, however this meant small targets had to spent unreasonable
amount of time memory allocing slots. With hash trie we can dynamically
scale up to 4 ^ 32 items and atomically replace symbols when needed. Neat!
This commit is contained in:
Nikita Smith committed 2024-10-30 15:43:53 -07:00
1 parent ee65ea3692
commit 4a2e1dd8d0
14 files changed
+877 -1049

No files matched your search

+48 -82
View File
@@ -90,27 +90,22 @@ typedef enum
LNK_Symbol_Undefined,
} LNK_SymbolType;
#define LNK_DEBUG_SYMBOLS 1
typedef struct LNK_Symbol
{
String8 name;
LNK_SymbolType type;
String8 name;
LNK_SymbolType type;
struct LNK_Obj *obj;
union {
LNK_DefinedSymbol defined;
LNK_WeakSymbol weak;
LNK_UndefinedSymbol undefined;
LNK_LazySymbol lazy;
} u;
#if LNK_DEBUG_SYMBOLS
String8 debug;
#endif
} LNK_Symbol;
typedef struct LNK_SymbolNode
{
struct LNK_SymbolNode *next;
struct LNK_SymbolNode *prev;
U64 hash;
LNK_Symbol *data;
} LNK_SymbolNode;
@@ -133,55 +128,45 @@ typedef struct LNK_SymbolArray
LNK_Symbol *v;
} LNK_SymbolArray;
typedef struct LNK_SymbolHashTrie
{
String8 *name;
LNK_Symbol *symbol;
struct LNK_SymbolHashTrie *child[4];
} LNK_SymbolHashTrie;
typedef struct LNK_SymbolHashTrieChunk
{
struct LNK_SymbolHashTrieChunk *next;
U64 count;
U64 cap;
LNK_SymbolHashTrie *v;
} LNK_SymbolHashTrieChunk;
typedef struct LNK_SymbolHashTrieChunkList
{
U64 count;
LNK_SymbolHashTrieChunk *first;
LNK_SymbolHashTrieChunk *last;
} LNK_SymbolHashTrieChunkList;
typedef struct LNK_SymbolTable
{
Arena *arena;
U64 bucket_count[LNK_SymbolScopeIndex_Count];
LNK_SymbolList *buckets[LNK_SymbolScopeIndex_Count];
TP_Arena *arena;
LNK_SymbolHashTrie *scopes[LNK_SymbolScopeIndex_Count];
LNK_SymbolHashTrieChunkList *chunk_lists[LNK_SymbolScopeIndex_Count];
} LNK_SymbolTable;
////////////////////////////////
// parallel for wrappers
typedef struct
{
LNK_Symbol *symbol_arr;
Rng1U64 *range_arr;
U64 *hash_arr;
} LNK_SymbolNameHasher;
typedef struct
{
LNK_SymbolNode **input_arr;
Rng1U64 *range_arr;
} LNK_SymbolNodePtrHasher;
typedef struct
{
LNK_SymbolNode *input_arr;
Rng1U64 *range_arr;
} LNK_SymbolNodeHasher;
typedef struct
{
LNK_SymbolTable *symtab;
LNK_SymbolList *bucket_arr;
Rng1U64 *range_arr;
} LNK_DefinedSymbolInserter;
typedef struct
{
LNK_SymbolTable *symtab;
LNK_SymbolList *bucket_arr;
Rng1U64 *range_arr;
Rng1U64 *ranges;
LNK_Symbol *arr;
} LNK_LazySymbolInserter;
typedef struct
{
LNK_SymbolTable *symtab;
Rng1U64 *range_arr;
} LNK_ComdatFolder;
////////////////////////////////
extern LNK_Symbol g_null_symbol;
@@ -201,53 +186,34 @@ internal LNK_Symbol * lnk_make_undefined_symbol(Arena *arena, String8 name, LNK_
internal LNK_Symbol * lnk_make_weak_symbol(Arena *arena, String8 name, COFF_WeakExtType lookup, LNK_Symbol *fallback);
internal LNK_Symbol * lnk_make_lazy_symbol(Arena *arena, String8 name, struct LNK_Lib *lib, U64 member_offset);
#if LNK_DEBUG_SYMBOLS
#define lnk_symbol_set_debugf(a, s, fmt, ...) do { (s)->debug = push_str8f((a), fmt, __VA_ARGS__); } while (0)
#define lnk_symbol_set_debug(s, str) do { (s)->debug = str; } while (0)
#else
#define lnk_symbol_set_debugf(...)
#define lnk_symbol_set_debug(...)
#endif
internal LNK_Chunk * lnk_chunk_from_symbol(LNK_Symbol *symbol);
internal LNK_Chunk * lnk_defined_symbol_get_chunk(LNK_DefinedSymbol *symbol);
internal void lnk_symbol_update_chunk_ref(LNK_Symbol *symbol, U64 src_sect_id, U64 dst_sect_id, U64 *id_map, U64 id_count);
////////////////////////////////
internal void lnk_symbol_list_push_node(LNK_SymbolList *list, LNK_SymbolNode *node);
internal LNK_SymbolNode * lnk_symbol_list_push(Arena *arena, LNK_SymbolList *list, LNK_Symbol *symbol);
internal void lnk_symbol_list_push_list(LNK_SymbolList *list, LNK_SymbolList *to_push);
internal void lnk_symbol_list_insert_after(LNK_SymbolList *list, LNK_SymbolNode *node, LNK_SymbolNode *insert);
internal LNK_SymbolNode * lnk_symbol_list_pop_node(LNK_SymbolList *list);
internal LNK_Symbol * lnk_symbol_list_pop(LNK_SymbolList *list);
internal void lnk_symbol_list_remove(LNK_SymbolList *list, LNK_SymbolNode *node);
internal void lnk_symbol_list_concat_in_place(LNK_SymbolList *list, LNK_SymbolList *to_concat);
internal LNK_SymbolNodeArray lnk_symbol_node_array_from_list(Arena *arena, LNK_SymbolList list);
internal LNK_SymbolList lnk_symbol_list_from_array(Arena *arena, LNK_SymbolArray arr);
internal LNK_SymbolNodeArray lnk_symbol_node_array_from_list(Arena *arena, LNK_SymbolList list);
internal LNK_SymbolArray lnk_symbol_array_from_list(Arena *arena, LNK_SymbolList list);
internal LNK_Symbol * lnk_symbol_array_search(LNK_SymbolArray symarr, String8 name, StringMatchFlags flags);
internal U64 * lnk_symbol_array_hash(TP_Context *tp, Arena *arena, LNK_Symbol *arr, U64 count);
internal LNK_SymbolTable * lnk_symbol_table_alloc(void);
internal LNK_SymbolTable * lnk_symbol_table_alloc_ex(U64 defined_cap, U64 internal_cap, U64 weak_cap, U64 lib_cap);
internal void lnk_symbol_table_release(LNK_SymbolTable **symtab);
internal U64 lnk_symbol_table_hash(String8 string);
internal LNK_SymbolNode * lnk_symbol_table_search_bucket(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope_idx, U64 bucket_idx, String8 name, U64 hash);
internal LNK_SymbolNode * lnk_symbol_table_search_node_hash(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, String8 name, U64 hash);
internal LNK_SymbolNode * lnk_symbol_table_search_node(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, String8 name);
internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, String8 name);
internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope_flags, char *fmt, ...);
internal void lnk_symbol_table_push_node_hash(LNK_SymbolTable *symtab, LNK_SymbolNode *node, U64 hash);
internal void lnk_symbol_table_push_node(LNK_SymbolTable *symtab, LNK_SymbolNode *node);
internal LNK_SymbolNode * lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol);
internal void lnk_symbol_table_push_lazy_arr(TP_Context *tp, LNK_SymbolTable *symtab, LNK_Symbol *arr, U64 count);
////////////////////////////////
internal void lnk_symbol_hash_trie_insert_or_replace(Arena *arena, LNK_SymbolHashTrieChunkList *chunk_list, LNK_SymbolHashTrie **trie, U64 hash, LNK_Symbol *new_symbol);
internal LNK_SymbolHashTrie * lnk_symbol_hash_trie_search(LNK_SymbolHashTrie *trie, U64 hash, String8 name);
internal void lnk_symbol_hash_trie_remove(LNK_SymbolHashTrie *trie);
////////////////////////////////
internal U64 lnk_symbol_hash(String8 string);
internal LNK_SymbolTable * lnk_symbol_table_init(TP_Arena *arena);
internal LNK_Symbol * lnk_symbol_table_search_hash(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, U64 hash, String8 name);
internal LNK_Symbol * lnk_symbol_table_search(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, String8 name);
internal LNK_Symbol * lnk_symbol_table_searchf(LNK_SymbolTable *symtab, LNK_SymbolScopeFlags scope, char *fmt, ...);
internal void lnk_symbol_table_push_hash(LNK_SymbolTable *symtab, U64 hash, LNK_Symbol *symbol);
internal void lnk_symbol_table_push(LNK_SymbolTable *symtab, LNK_Symbol *symbol);
internal void lnk_symbol_table_remove(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex scope, String8 name);
internal void lnk_symbol_table_replace(LNK_SymbolTable *symtab, LNK_SymbolScopeIndex iscope, LNK_Symbol *symbol);
internal LNK_Symbol * lnk_resolve_symbol(LNK_SymbolTable *symtab, LNK_Symbol *resolve_symbol);
internal LNK_SymbolList lnk_pop_comdat_chain(LNK_SymbolList *bucket, LNK_SymbolNode **cursor);
internal LNK_SymbolNode * lnk_fold_comdat_chain(LNK_SymbolList chain_list);
internal void lnk_fold_comdat_chunks(TP_Context *tp, LNK_SymbolTable *symtab);