From 9002dd7becd255a0630935c66457fbe23ea2e45a Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Tue, 9 Jun 2020 10:02:24 -0500 Subject: [PATCH] Changed implementation for bh_hash --- docs/new_hash_plan | 50 +++++++++++ include/bh.h | 201 +++++++++++++++++++++++++++++---------------- onyx | Bin 103056 -> 103256 bytes src/onyxparser.c | 2 +- src/onyxwasm.c | 4 +- 5 files changed, 183 insertions(+), 74 deletions(-) create mode 100644 docs/new_hash_plan diff --git a/docs/new_hash_plan b/docs/new_hash_plan new file mode 100644 index 00000000..d12fc1d1 --- /dev/null +++ b/docs/new_hash_plan @@ -0,0 +1,50 @@ +The state of the hash implementation right now: + + (allocator + 1021 ptrs = 8192 bytes (HUGE)) + +--------------------------------------------------------- +table ----> | allocator | ptr | ptr | ptr | ptr | ptr | ptr | ptr ... + +-------------||------------------------------------------ + \/ + +--------------+------------------------------------------------------ + | Array header | key (64-bytes) | value | key (64-bytes) | value | ... + +--------------+------------------------------------------------------ + +There are a couple of issues with this implementation: + * The table of pointers is absolutely huge. + It takes up about 2 pages of memory and we are randomly accessing it + so it will not be cache efficient. + * The keys are always the same size. + They are normally way too large, but also they would cut off if you + needed a large key. + + + +THIS WORKED VERY WELL! +Attempt 1 to fix these issues: + + (user defined number of ptrs) + +----------------------------------------------------------- +table ----> | allocator | hash size | ptr | ptr | ptr | ptr | ptr | ... + +-------------------------||-------------------------------- + \/ + +--------------+---------------------------------------------------------------------------- + | Array header | value | key_length | key (null terminated) | v | kl | k | v | kl | k | ... + +--------------+---------------------------------------------------------------------------- + +GOOD: + * This implementation would allow for any size of key. + Initial thoughts: + - Alignment is going to be very important. + - Alignment will need to be by hand. + - Aligning to 8 bytes should be sufficient. + - The array would just be considered as a u8 array, since each element + wouldn't be the same size. + - Random access into the array would not be allowed for the same reason. + - Random access will not be needed however. + * This implementation still allows for easy iterator traversal, which is + important for the immediate use case. + +BAD: + * The fact that the number of pointers is user defined, the hashing algorithm could + be drastically slowed / crippled if they choose a bad number of pointers. + * This implementation still takes a very large number of allocations. diff --git a/include/bh.h b/include/bh.h index eb459326..a3854e78 100644 --- a/include/bh.h +++ b/include/bh.h @@ -508,66 +508,59 @@ void bh__arr_deleten(void **arr, i32 elemsize, i32 index, i32 numelems); //------------------------------------------------------------------------------------- #ifndef BH_NO_HASHTABLE -#define BH__HASH_STORED_KEY_SIZE 64 -typedef struct bh__hash_entry { - char key[BH__HASH_STORED_KEY_SIZE]; - i32 value; // NOTE: Not actually an i32, just used as a placeholder for offset -} bh__hash_entry; - -#define BH__HASH_MODULUS 1021 -#define BH__HASH_KEYSIZE 64 #ifdef BH_DEFINE -u64 bh__hash_function(const char* str, i32 len) { +u64 bh__hash_function(const char* str, i32 len, i32 mod) { u64 hash = 5381; i32 c, l = 0; - if (len == 0) len = BH__HASH_KEYSIZE; + if (len == 0) len = ((u32) 1 << 31) - 1; // TODO: Verify this is right while ((c = *str++) && l++ < len) { hash = (hash << 5) + hash + c; } - return hash % BH__HASH_MODULUS; + return hash % mod; } #endif typedef struct bh_hash_iterator { ptr *tab, *endtab; i32 elemsize, arrlen; - bh__hash_entry* entry; + ptr entry; } bh_hash_iterator; typedef struct bh__hash { bh_allocator allocator; - ptr arrs[BH__HASH_MODULUS]; + u64 hash_size; // NOTE: u64 since padding will make it 8-bytes no matter what + ptr arrs[]; } bh__hash; #define bh_hash(T) T* #ifdef BH_HASH_SIZE_SAFE - #define bh_hash_init(allocator_, tab) bh__hash_init(allocator_, (bh__hash **)&(tab)) - #define bh_hash_free(tab) bh__hash_free((bh__hash **)&(tab)) - #define bh_hash_put(T, tab, key, value) (assert(sizeof(T) == sizeof(*(tab))), (*((T *) bh__hash_put((bh__hash *) tab, sizeof(T), key)) = (T) value)) - #define bh_hash_has(T, tab, key) (assert(sizeof(T) == sizeof(*(tab))), (bh__hash_has((bh__hash *) tab, sizeof(T), key))) - #define bh_hash_get(T, tab, key) (assert(sizeof(T) == sizeof(*(tab))), (*((T *) bh__hash_get((bh__hash *) tab, sizeof(T), key)))) - #define bh_hash_delete(T, tab, key) (assert(sizeof(T) == sizeof(*(tab))), bh__hash_delete((bh__hash *) tab, sizeof(T), key)) + #define bh_hash_init(allocator_, tab, hs) bh__hash_init(allocator_, (bh__hash **)&(tab), hs) + #define bh_hash_free(tab) bh__hash_free((bh__hash **)&(tab)) + #define bh_hash_put(T, tab, key, value) (assert(sizeof(T) == sizeof(*(tab))), (*((T *) bh__hash_put((bh__hash *) tab, sizeof(T), key)) = (T) value)) + #define bh_hash_has(T, tab, key) (assert(sizeof(T) == sizeof(*(tab))), (bh__hash_has((bh__hash *) tab, sizeof(T), key))) + #define bh_hash_get(T, tab, key) (assert(sizeof(T) == sizeof(*(tab))), (*((T *) bh__hash_get((bh__hash *) tab, sizeof(T), key)))) + #define bh_hash_delete(T, tab, key) (assert(sizeof(T) == sizeof(*(tab))), bh__hash_delete((bh__hash *) tab, sizeof(T), key)) #define bh_hash_iter_setup(T, tab) (assert(sizeof(T) == sizeof(*(tab))), bh__hash_iter_setup((bh__hash *) tab, sizeof(T))) - #define bh_hash_iter_key(it) (it.entry->key) - #define bh_hash_iter_value(T, it) (assert(sizeof(T) == it.elemsize), *(T *)&(it.entry->value)) + #define bh_hash_iter_key(it) ((char *)(bh_pointer_add(it.entry, it.elemsize + sizeof(u16)))) + #define bh_hash_iter_value(T, it) (assert(sizeof(T) == it.elemsize), *(T *)it.entry) #else - #define bh_hash_init(allocator_, tab) bh__hash_init(allocator_, (bh__hash **)&(tab)) - #define bh_hash_free(tab) bh__hash_free((bh__hash **)&(tab)) - #define bh_hash_put(T, tab, key, value) (*((T *) bh__hash_put((bh__hash *) tab, sizeof(T), key)) = value) - #define bh_hash_has(T, tab, key) (bh__hash_has((bh__hash *) tab, sizeof(T), key)) - #define bh_hash_get(T, tab, key) (*((T *) bh__hash_get((bh__hash *) tab, sizeof(T), key))) - #define bh_hash_delete(T, tab, key) (bh__hash_delete((bh__hash *) tab, sizeof(T), key)) + #define bh_hash_init(allocator_, tab, hs) bh__hash_init(allocator_, (bh__hash **)&(tab), hs) + #define bh_hash_free(tab) bh__hash_free((bh__hash **)&(tab)) + #define bh_hash_put(T, tab, key, value) (*((T *) bh__hash_put((bh__hash *) tab, sizeof(T), key)) = value) + #define bh_hash_has(T, tab, key) (bh__hash_has((bh__hash *) tab, sizeof(T), key)) + #define bh_hash_get(T, tab, key) (*((T *) bh__hash_get((bh__hash *) tab, sizeof(T), key))) + #define bh_hash_delete(T, tab, key) (bh__hash_delete((bh__hash *) tab, sizeof(T), key)) #define bh_hash_iter_setup(T, tab) (bh__hash_iter_setup((bh__hash *) tab, sizeof(T))) - #define bh_hash_iter_key(it) (it.entry->key) - #define bh_hash_iter_value(T, it) (*(T *)&(it.entry->value)) + #define bh_hash_iter_key(it) ((char *)(bh_pointer_add(it.entry, it.elemsize + sizeof(u16)))) + #define bh_hash_iter_value(T, it) (*(T *)it.entry) #endif -b32 bh__hash_init(bh_allocator allocator, bh__hash **table); +b32 bh__hash_init(bh_allocator allocator, bh__hash **table, i32 hash_size); b32 bh__hash_free(bh__hash **table); ptr bh__hash_put(bh__hash *table, i32 elemsize, char *key); b32 bh__hash_has(bh__hash *table, i32 elemsize, char *key); @@ -1594,13 +1587,14 @@ void bh__arr_insertn(void **arr, i32 elemsize, i32 index, i32 numelems) { //------------------------------------------------------------------------------------- #ifndef BH_NO_HASHTABLE -b32 bh__hash_init(bh_allocator allocator, bh__hash **table) { - *table = bh_alloc(allocator, sizeof(bh__hash)); +b32 bh__hash_init(bh_allocator allocator, bh__hash **table, i32 hash_size) { + *table = bh_alloc(allocator, sizeof(bh__hash) + sizeof(ptr) * hash_size); if (*table == NULL) return 0; (*table)->allocator = allocator; + (*table)->hash_size = hash_size; - for (i32 i = 0; i < BH__HASH_MODULUS; i++) { + for (i32 i = 0; i < hash_size; i++) { (*table)->arrs[i] = NULL; } @@ -1608,7 +1602,7 @@ b32 bh__hash_init(bh_allocator allocator, bh__hash **table) { } b32 bh__hash_free(bh__hash **table) { - for (i32 i = 0; i < BH__HASH_MODULUS; i++) { + for (i32 i = 0; i < (*table)->hash_size; i++) { if ((*table)->arrs[i] != NULL) { bh_arr_free((*table)->arrs[i]); } @@ -1620,95 +1614,158 @@ b32 bh__hash_free(bh__hash **table) { // Assumes NULL terminated string for key ptr bh__hash_put(bh__hash *table, i32 elemsize, char *key) { - u64 index = bh__hash_function(key, 0); - - elemsize += BH__HASH_STORED_KEY_SIZE; + u64 index = bh__hash_function(key, 0, table->hash_size); ptr arrptr = table->arrs[index]; - i32 len = bh_arr_length(arrptr); + if (arrptr == NULL) goto add_new_element; + u64 len = *(u64 *) arrptr; + arrptr = bh_pointer_add(arrptr, sizeof(u64)); + u16 key_length = 0; while (len--) { - if (strncmp(key, (char *) arrptr, BH__HASH_STORED_KEY_SIZE) == 0) goto found_matching; arrptr = bh_pointer_add(arrptr, elemsize); + key_length = *(u16 *) arrptr; + arrptr = bh_pointer_add(arrptr, sizeof(u16)); + if (strncmp(key, (char *) arrptr, key_length) == 0) goto found_matching; + arrptr = bh_pointer_add(arrptr, key_length); } - // Didn't find it in the array, make a new one +add_new_element: arrptr = table->arrs[index]; - len = bh_arr_length(arrptr); - bh__arr_grow(table->allocator, &arrptr, elemsize, len + 1); - bh__arrhead(arrptr)->length++; + i32 byte_len = bh_arr_length(arrptr); + if (byte_len == 0) byte_len = sizeof(u64); + key_length = strlen(key) + 1; + bh__arr_grow(table->allocator, &arrptr, 1, byte_len + elemsize + sizeof(u16) + key_length); + bh__arrhead(arrptr)->length = byte_len + elemsize + sizeof(u16) + key_length; table->arrs[index] = arrptr; - arrptr = bh_pointer_add(arrptr, elemsize * len); - strncpy(arrptr, key, BH__HASH_STORED_KEY_SIZE); + (*(u64 *) arrptr)++; + + arrptr = bh_pointer_add(arrptr, byte_len + elemsize); + *(u16 *) arrptr = key_length; + arrptr = bh_pointer_add(arrptr, sizeof(u16)); + strncpy(arrptr, key, key_length); found_matching: - return bh_pointer_add(arrptr, BH__HASH_STORED_KEY_SIZE); + return bh_pointer_add(arrptr, -(sizeof(u16) + elemsize)); + +// OLD: +// elemsize += BH__HASH_STORED_KEY_SIZE; +// +// ptr arrptr = table->arrs[index]; +// i32 len = bh_arr_length(arrptr); +// +// while (len--) { +// if (strncmp(key, (char *) arrptr, BH__HASH_STORED_KEY_SIZE) == 0) goto found_matching; +// arrptr = bh_pointer_add(arrptr, elemsize); +// } +// +// // Didn't find it in the array, make a new one +// arrptr = table->arrs[index]; +// len = bh_arr_length(arrptr); +// bh__arr_grow(table->allocator, &arrptr, elemsize, len + 1); +// bh__arrhead(arrptr)->length++; +// table->arrs[index] = arrptr; +// +// arrptr = bh_pointer_add(arrptr, elemsize * len); +// strncpy(arrptr, key, BH__HASH_STORED_KEY_SIZE); +// +//found_matching: +// return bh_pointer_add(arrptr, BH__HASH_STORED_KEY_SIZE); } b32 bh__hash_has(bh__hash *table, i32 elemsize, char *key) { - u64 index = bh__hash_function(key, 0); + u64 index = bh__hash_function(key, 0, table->hash_size); ptr arrptr = table->arrs[index]; if (arrptr == NULL) return 0; - i32 len = bh_arr_length(arrptr); - i32 stride = elemsize + BH__HASH_STORED_KEY_SIZE; + u64 len = *(u64 *) arrptr; + arrptr = bh_pointer_add(arrptr, sizeof(u64)); + u16 key_length = 0; while (len--) { - if (strncmp(key, (char *) arrptr, BH__HASH_STORED_KEY_SIZE) == 0) return 1; - arrptr = bh_pointer_add(arrptr, stride); + arrptr = bh_pointer_add(arrptr, elemsize); + key_length = *(u16 *) arrptr; + arrptr = bh_pointer_add(arrptr, sizeof(u16)); + if (strncmp(key, (char *) arrptr, key_length) == 0) return 1; + arrptr = bh_pointer_add(arrptr, key_length); } return 0; } ptr bh__hash_get(bh__hash *table, i32 elemsize, char *key) { - u64 index = bh__hash_function(key, 0); + u64 index = bh__hash_function(key, 0, table->hash_size); ptr arrptr = table->arrs[index]; - if (arrptr == NULL) return NULL; + if (arrptr == NULL) return 0; - i32 stride = elemsize + BH__HASH_STORED_KEY_SIZE; + u64 len = *(u64 *) arrptr; + arrptr = bh_pointer_add(arrptr, sizeof(u64)); - i32 len = bh_arr_length(arrptr); + u16 key_length = 0; while (len--) { - if (strncmp(key, (char *) arrptr, BH__HASH_STORED_KEY_SIZE) == 0) { - return bh_pointer_add(arrptr, BH__HASH_STORED_KEY_SIZE); + arrptr = bh_pointer_add(arrptr, elemsize); + key_length = *(u16 *) arrptr; + arrptr = bh_pointer_add(arrptr, sizeof(u16)); + if (strncmp(key, (char *) arrptr, key_length) == 0) { + return bh_pointer_add(arrptr, -(sizeof(u16) + elemsize)); } - - arrptr = bh_pointer_add(arrptr, stride); + arrptr = bh_pointer_add(arrptr, key_length); } return NULL; } void bh__hash_delete(bh__hash *table, i32 elemsize, char *key) { - u64 index = bh__hash_function(key, 0); + u64 index = bh__hash_function(key, 0, table->hash_size); ptr arrptr = table->arrs[index], walker; if (arrptr == NULL) return; // Didn't exist walker = arrptr; - i32 stride = elemsize + BH__HASH_STORED_KEY_SIZE; - i32 i = 0; + i32 byte_offset = 8; + i32 delete_len = 0; - i32 len = bh_arr_length(arrptr); - while (len && strncmp(key, (char *) walker, BH__HASH_STORED_KEY_SIZE) != 0) { - walker = bh_pointer_add(walker, stride); - i++, len--; + u64 len = *(u64 *) walker; + walker = bh_pointer_add(walker, sizeof(u64)); + + u16 key_length = 0; + while (len--) { + walker = bh_pointer_add(walker, elemsize); + key_length = *(u16 *) walker; + walker = bh_pointer_add(walker, sizeof(u16)); + if (strncmp(key, (char *) walker, key_length) == 0) { + delete_len = elemsize + sizeof(u16) + key_length; + goto found_matching; + } + byte_offset += elemsize + sizeof(u16) + key_length; } - if (len == 0) return; // Didn't exist + // NOTE: Already didn't exist + return; - bh__arr_deleten((void **) &arrptr, stride, i, 1); +found_matching: + bh__arr_deleten((void **) &arrptr, 1, byte_offset, delete_len); table->arrs[index] = arrptr; + +// OLD: +// while (len && strncmp(key, (char *) walker, BH__HASH_STORED_KEY_SIZE) != 0) { +// walker = bh_pointer_add(walker, stride); +// i++, len--; +// } +// +// if (len == 0) return; // Didn't exist +// +// bh__arr_deleten((void **) &arrptr, stride, i, 1); +// table->arrs[index] = arrptr; } bh_hash_iterator bh__hash_iter_setup(bh__hash *table, i32 elemsize) { bh_hash_iterator it = { .tab = table->arrs, - .endtab = table->arrs + BH__HASH_MODULUS, + .endtab = table->arrs + table->hash_size, .elemsize = elemsize, .entry = NULL }; @@ -1725,7 +1782,8 @@ b32 bh_hash_iter_next(bh_hash_iterator* it) { goto step_to_next; } - it->entry = (bh__hash_entry *)bh_pointer_add(it->entry, BH__HASH_STORED_KEY_SIZE + it->elemsize); + it->entry = bh_pointer_add(it->entry, it->elemsize); + it->entry = bh_pointer_add(it->entry, sizeof(u16) + (*(u16 *) it->entry)); return 1; } @@ -1738,7 +1796,8 @@ step_to_next: if (it->tab == it->endtab) return 0; it->entry = *it->tab; - it->arrlen = bh_arr_length(it->entry); + it->arrlen = *(u64 *) it->entry; + it->entry = bh_pointer_add(it->entry, sizeof(u64)); if (it->arrlen <= 0) { it->tab++; goto step_to_next; diff --git a/onyx b/onyx index 4aeca7028e2e568d81dccda14301128053fa197c..748853508d9d1f96d96160e1680a28f3a3db523c 100755 GIT binary patch delta 36327 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 delta 35462 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 diff --git a/src/onyxparser.c b/src/onyxparser.c index 646e6e06..0fbfc267 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -689,7 +689,7 @@ OnyxAstNode* onyx_ast_node_new(bh_allocator alloc, OnyxAstNodeKind kind) {\ OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, OnyxMessages* msgs) { OnyxParser parser; - bh_hash_init(bh_heap_allocator(), parser.identifiers); + bh_hash_init(bh_heap_allocator(), parser.identifiers, 61); OnyxTypeInfo* it = &builtin_types[0]; while (it->kind != 0xffffffff) { diff --git a/src/onyxwasm.c b/src/onyxwasm.c index c0b91ad2..11226d43 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -104,8 +104,8 @@ OnyxWasmModule onyx_wasm_generate_module(bh_allocator alloc, OnyxAstNode* progra bh_arr_new(alloc, module.functypes, 4); bh_arr_new(alloc, module.funcs, 4); - bh_hash_init(bh_heap_allocator(), module.type_map); - bh_hash_init(bh_heap_allocator(), module.exports); + bh_hash_init(bh_heap_allocator(), module.type_map, 61); + bh_hash_init(bh_heap_allocator(), module.exports, 61); OnyxAstNode* walker = program; while (walker) { -- 2.25.1