Fixed leaking relocation table memory in JIT.
1 #include <KeHashTable.h>
3 using namespace Knight;
22 KeHashGenerator key_gen;
25 ke_allocator_t *node_alloc;
30 KeHashNode *free_list;
35 void *ke_DefHashMalloc(ke_allocator_t *alloc, size_t amt)
40 void ke_DefHashFree(ke_allocator_t *alloc, void *addr)
45 ke_allocator_t s_DefHashAllocator =
52 KeHashTable *Knight::KE_CreateHashTable(
54 KeHashGenerator key_gen,
55 const KeHashMarshal *key_marshal,
56 const KeHashMarshal *val_marshal,
57 ke_allocator_t *nodeAlloc,
71 /* Validate marshals. */
72 if ((key_marshal->bytes != 0
73 && key_marshal->ctor == NULL)
74 || (val_marshal->bytes != 0
75 && val_marshal->ctor == NULL))
80 table = new KeHashTable;
81 table->key_gen = key_gen;
82 table->key_m = *key_marshal;
83 table->val_m = *val_marshal;
84 table->num_entries = 0;
86 table->node_alloc = nodeAlloc == NULL ? &s_DefHashAllocator : nodeAlloc;
87 table->num_buckets = (1 << bits);
88 table->grow_limit = (uint32_t)(0.9f * table->num_buckets);
89 table->keep_free_list = keep_free_list;
90 table->free_list = NULL;
91 table->buckets = (KeHashNode **)malloc(sizeof(KeHashNode *) * table->num_buckets);
92 memset(table->buckets, 0, sizeof(KeHashNode *) * table->num_buckets);
94 table->key_offs = sizeof(KeHashNode);
95 if (table->key_m.bytes != 0 && table->key_m.bytes % 8 != 0)
97 table->key_m.bytes += 8;
98 table->key_m.bytes -= (table->key_m.bytes % 8);
101 table->val_offs = table->key_offs + table->key_m.bytes;
102 table->node_size = table->val_offs + table->val_m.bytes;
107 #define KE_GET_BUCKET(tbl, hsh) (&(tbl)->buckets[((hsh) * 0x9E3779B9) >> (tbl)->shift])
109 KeHashNode **ke_HashInternalFind(KeHashTable *table, uint32_t key_hash, const void *key)
114 bucket = KE_GET_BUCKET(table, key_hash);
116 /* :TODO: move to the front once found? */
118 while ((node = *bucket) != NULL)
120 if (node->key_hash == key_hash
121 && ((table->key_m.cmp != NULL && table->key_m.cmp(node->key, key))
122 || node->key == key))
126 bucket = &node->next;
132 void ke_ResizeHashTable(KeHashTable *table, uint32_t new_shift)
137 KeHashNode **rbucket;
138 KeHashNode **old_buckets;
139 uint32_t old_num_buckets;
142 old_num_buckets = table->num_buckets;
143 old_buckets = table->buckets;
144 entries = table->num_entries;
147 table->num_buckets = (1 << new_shift);
148 table->shift = new_shift;
149 table->grow_limit = (uint32_t)(0.9f * table->num_buckets);
151 table->buckets = (KeHashNode **)malloc(sizeof(KeHashNode *) * table->num_buckets);
152 memset(table->buckets, 0, sizeof(KeHashNode *) * table->num_buckets);
154 /* For each old bucket... */
156 i < old_num_buckets && entries != 0;
159 node = old_buckets[i];
160 /* Get each item in its list... */
165 /* Find the new replacement bucket it needs to go in. */
166 rbucket = KE_GET_BUCKET(table, node->key_hash);
168 /* Link this node to the next node in the new bucket. */
169 if (*rbucket == NULL)
175 node->next = *rbucket;
178 /* Add us to the front of that bucket's list. */
188 void Knight::KE_AddToHashTable(KeHashTable *table, const void *key, void *val)
194 key_hash = table->key_gen(key);
195 bucket = ke_HashInternalFind(table, key_hash, key);
197 if ((node = *bucket) != NULL)
199 /* Already in the table */
200 if ((table->val_m.cmp != NULL && table->val_m.cmp(node->value, val))
201 || node->value == val)
206 /* Destroy old value if it's set. */
207 if (node->value != NULL && table->val_m.dtor != NULL)
209 table->val_m.dtor(node->value);
212 /* Construct or set the new value. */
213 if (table->val_m.bytes != 0)
215 table->val_m.ctor(node->value, val);
225 /* If we're overloaded, we may need to resize.
226 * Right now, we do this if we hit a .9 entry:buckets ratio.
228 if (table->num_entries >= table->grow_limit)
230 ke_ResizeHashTable(table, table->shift << 1);
231 bucket = ke_HashInternalFind(table, key_hash, key);
234 if (table->free_list != NULL)
236 node = table->free_list;
237 table->free_list = node->next;
241 node = (KeHashNode *)table->node_alloc->alloc(table->node_alloc, table->node_size);
244 if (table->key_m.bytes == 0)
250 node->key = (char *)node + table->key_offs;
251 table->key_m.ctor((void *)node->key, key);
254 if (table->val_m.bytes == 0)
260 node->value = (char *)node + table->val_offs;
261 table->val_m.ctor(node->value, val);
264 node->next = *bucket;
265 node->key_hash = key_hash;
269 inline void ke_CleanUpHashNode(KeHashTable *table, KeHashNode *node)
271 /* Destroy old value if it's set. */
272 if (node->value != NULL && table->val_m.dtor != NULL)
274 table->val_m.dtor(node->value);
277 /* Destroy the key. */
278 if (table->key_m.dtor != NULL)
280 table->key_m.dtor(node->key);
283 /* Deallocate us as appropriate. */
284 if (table->keep_free_list)
286 node->next = table->free_list;
287 table->free_list = node;
291 table->node_alloc->dealloc(table->node_alloc, node);
295 void Knight::KE_RemoveFromHashTable(KeHashTable *table, const void *key)
301 key_hash = table->key_gen(key);
302 bucket = ke_HashInternalFind(table, key_hash, key);
304 if ((node = *bucket) == NULL)
309 /* Link the bucket to its next (removing us). */
310 *bucket = node->next;
312 ke_CleanUpHashNode(table, node);
315 bool Knight::KE_FindInHashTable(KeHashTable *table, const void *key, void **value)
321 key_hash = table->key_gen(key);
322 bucket = ke_HashInternalFind(table, key_hash, key);
324 if ((node = *bucket) == NULL)
331 *value = node->value;
337 void Knight::KE_DestroyHashTable(KeHashTable *table)
339 KeHashNode *node, *next;
341 /* Turn off this caching! */
342 table->keep_free_list = false;
344 /* Find entries in buckets that need to be freed. */
345 for (uint32_t i = 0; i < table->num_buckets; i++)
347 node = table->buckets[i];
352 ke_CleanUpHashNode(table, node);
357 /* Free the free list */
358 while (table->free_list != NULL)
360 next = table->free_list->next;
361 ke_CleanUpHashNode(table, table->free_list);
362 table->free_list = next;
365 /* Destroy everything now. */
366 free(table->buckets);
370 void Knight::KE_ClearHashTable(KeHashTable *table)
372 KeHashNode *node, *next;
374 /* Free every entry in the table. */
375 for (uint32_t i = 0; i < table->num_buckets; i++)
377 node = table->buckets[i];
382 ke_CleanUpHashNode(table, node);
388 #if defined _MSC_VER && (defined _M_IX86 || defined _M_AMD64 || defined _M_X64)
389 #pragma intrinsic(_rotl)
392 uint32_t Knight::KE_HashString(const void *str)
395 const unsigned char *us;
399 for (us = (const unsigned char *)str; *us != 0; us++)
401 #if defined _MSC_VER && (defined _M_IX86 || defined _M_AMD64 || defined _M_X64)
402 h = _rotl(h, 4) ^ *us;
404 h = ((h << 4) | (h >> 28)) ^ *us;