Index: src/runtime/category.m ================================================================== --- src/runtime/category.m +++ src/runtime/category.m @@ -47,11 +47,12 @@ { struct objc_abi_category **cats; Class cls = objc_classname_to_class(cat->class_name, false); if (categories == NULL) - categories = objc_hashtable_new(2); + categories = objc_hashtable_new( + objc_hash_string, objc_equal_string, 2); cats = (struct objc_abi_category**)objc_hashtable_get(categories, cat->class_name); if (cats != NULL) { @@ -121,12 +122,12 @@ uint32_t i; if (categories == NULL) return; - for (i = 0; i <= categories->last_idx; i++) + for (i = 0; i < categories->size; i++) if (categories->data[i] != NULL) free((void*)categories->data[i]->obj); objc_hashtable_free(categories); categories = NULL; } Index: src/runtime/class.m ================================================================== --- src/runtime/class.m +++ src/runtime/class.m @@ -39,11 +39,12 @@ static void register_class(struct objc_abi_class *cls) { if (classes == NULL) - classes = objc_hashtable_new(2); + classes = objc_hashtable_new( + objc_hash_string, objc_equal_string, 2); objc_hashtable_set(classes, cls->name, cls); if (empty_dtable == NULL) empty_dtable = objc_sparsearray_new(); @@ -522,11 +523,11 @@ return classes_cnt; if (classes_cnt < count) count = classes_cnt; - for (i = j = 0; i <= classes->last_idx; i++) { + for (i = j = 0; i < classes->size; i++) { Class cls; if (j >= count) { objc_global_mutex_unlock(); return j; @@ -856,11 +857,11 @@ uint_fast32_t i; if (classes == NULL) return; - for (i = 0; i <= classes->last_idx; i++) { + for (i = 0; i < classes->size; i++) { if (classes->data[i] != NULL) { Class cls = (Class)classes->data[i]->obj; if (cls == Nil || (uintptr_t)cls & 1) continue; Index: src/runtime/hashtable.m ================================================================== --- src/runtime/hashtable.m +++ src/runtime/hashtable.m @@ -23,12 +23,13 @@ #import "runtime.h" #import "runtime-private.h" uint32_t -objc_hash_string(const char *str) +objc_hash_string(const void *str_) { + const char *str = str_; uint32_t hash = 0; while (*str != 0) { hash += *str; hash += (hash << 10); @@ -41,94 +42,101 @@ hash += (hash << 15); return hash; } -struct objc_hashtable* -objc_hashtable_new(uint32_t size) -{ - struct objc_hashtable *h; - uint32_t i; - - if ((h = malloc(sizeof(struct objc_hashtable))) == NULL) - OBJC_ERROR("Not enough memory to allocate hash table!"); - - h->count = 0; - h->last_idx = size - 1; - h->data = malloc(size * sizeof(struct objc_hashtable_bucket*)); - - if (h->data == NULL) - OBJC_ERROR("Not enough memory to allocate hash table!"); - - for (i = 0; i < size; i++) - h->data[i] = NULL; - - return h; +bool +objc_equal_string(const void *obj1, const void *obj2) +{ + return !strcmp(obj1, obj2); +} + +struct objc_hashtable* +objc_hashtable_new(uint32_t (*hash)(const void*), + bool (*equal)(const void*, const void*), uint32_t size) +{ + struct objc_hashtable *table; + + if ((table = malloc(sizeof(struct objc_hashtable))) == NULL) + OBJC_ERROR("Not enough memory to allocate hash table!"); + + table->hash = hash; + table->equal = equal; + + table->count = 0; + table->size = size; + table->data = calloc(size, sizeof(struct objc_hashtable_bucket*)); + + if (table->data == NULL) + OBJC_ERROR("Not enough memory to allocate hash table!"); + + return table; } static void -insert(struct objc_hashtable *h, const char *key, const void *obj) +insert(struct objc_hashtable *table, const void *key, const void *obj) { uint32_t i, hash, last; struct objc_hashtable_bucket *bucket; - hash = objc_hash_string(key); + hash = table->hash(key); - if (h->count + 1 > UINT32_MAX / 4) + if (table->count + 1 > UINT32_MAX / 4) OBJC_ERROR("Integer overflow!"); - if ((h->count + 1) * 4 / (h->last_idx + 1) >= 3) { - struct objc_hashtable_bucket **ndata; - uint32_t nsize = (h->last_idx + 1) * 2; + if ((table->count + 1) * 4 / table->size >= 3) { + struct objc_hashtable_bucket **newData; + uint32_t newSize; - if (nsize == 0) + if (table->size > UINT32_MAX / 2) OBJC_ERROR("Integer overflow!"); - ndata = malloc(nsize * sizeof(struct objc_hashtable_bucket*)); - if (ndata == NULL) + newSize = table->size * 2; + + if ((newData = calloc(newSize, + sizeof(struct objc_hashtable_bucket*))) == NULL) OBJC_ERROR("Not enough memory to insert into hash " "table!"); - for (i = 0; i < nsize; i++) - ndata[i] = NULL; - - for (i = 0; i <= h->last_idx; i++) { - if (h->data[i] != NULL) { + for (i = 0; i < table->size; i++) { + if (table->data[i] != NULL) { uint32_t j; - last = nsize; + last = newSize; - for (j = h->data[i]->hash & (nsize - 1); - j < last && ndata[j] != NULL; j++); + for (j = table->data[i]->hash & (newSize - 1); + j < last && newData[j] != NULL; j++); if (j >= last) { - last = h->data[i]->hash & (nsize - 1); + last = table->data[i]->hash & + (newSize - 1); for (j = 0; j < last && - ndata[j] != NULL; j++); + newData[j] != NULL; j++); } if (j >= last) OBJC_ERROR("No free bucket!"); - ndata[j] = h->data[i]; + newData[j] = table->data[i]; } } - free(h->data); - h->data = ndata; - h->last_idx = nsize - 1; + free(table->data); + table->data = newData; + table->size = newSize; } - last = h->last_idx + 1; + last = table->size; - for (i = hash & h->last_idx; i < last && h->data[i] != NULL; i++); + for (i = hash & (table->size - 1); + i < last && table->data[i] != NULL; i++); if (i >= last) { - last = hash & h->last_idx; + last = hash & (table->size - 1); - for (i = 0; i < last && h->data[i] != NULL; i++); + for (i = 0; i < last && table->data[i] != NULL; i++); } if (i >= last) OBJC_ERROR("No free bucket!"); @@ -137,66 +145,67 @@ bucket->key = key; bucket->hash = hash; bucket->obj = obj; - h->data[i] = bucket; - h->count++; + table->data[i] = bucket; + table->count++; } static inline int64_t -index_for_key(struct objc_hashtable *h, const char *key) +index_for_key(struct objc_hashtable *table, const void *key) { uint32_t i, hash; - hash = objc_hash_string(key) & h->last_idx; + hash = table->hash(key) & (table->size - 1); - for (i = hash; i <= h->last_idx && h->data[i] != NULL; i++) - if (!strcmp(h->data[i]->key, key)) + for (i = hash; i < table->size && table->data[i] != NULL; i++) + if (table->equal(table->data[i]->key, key)) return i; - if (i <= h->last_idx) + if (i < table->size) return -1; - for (i = 0; i < hash && h->data[i] != NULL; i++) - if (!strcmp(h->data[i]->key, key)) + for (i = 0; i < hash && table->data[i] != NULL; i++) + if (table->equal(table->data[i]->key, key)) return i; return -1; } void -objc_hashtable_set(struct objc_hashtable *h, const char *key, const void *obj) +objc_hashtable_set(struct objc_hashtable *table, const void *key, + const void *obj) { - int64_t idx = index_for_key(h, key); + int64_t idx = index_for_key(table, key); if (idx < 0) { - insert(h, key, obj); + insert(table, key, obj); return; } - h->data[idx]->obj = obj; + table->data[idx]->obj = obj; } void* -objc_hashtable_get(struct objc_hashtable *h, const char *key) +objc_hashtable_get(struct objc_hashtable *table, const void *key) { - int64_t idx = index_for_key(h, key); + int64_t idx = index_for_key(table, key); if (idx < 0) return NULL; - return (void*)h->data[idx]->obj; + return (void*)table->data[idx]->obj; } void -objc_hashtable_free(struct objc_hashtable *h) +objc_hashtable_free(struct objc_hashtable *table) { uint32_t i; - for (i = 0; i <= h->last_idx; i++) - if (h->data[i] != NULL) - free(h->data[i]); + for (i = 0; i < table->size; i++) + if (table->data[i] != NULL) + free(table->data[i]); - free(h->data); - free(h); + free(table->data); + free(table); } Index: src/runtime/runtime-private.h ================================================================== --- src/runtime/runtime-private.h +++ src/runtime/runtime-private.h @@ -89,18 +89,18 @@ const char *name; struct objc_abi_symtab *symtab; }; struct objc_hashtable_bucket { - const char *key; - const void *obj; + const void *key, *obj; uint32_t hash; }; struct objc_hashtable { - uint32_t count; - uint32_t last_idx; + uint32_t (*hash)(const void *key); + bool (*equal)(const void *key1, const void *key2); + uint32_t count, size; struct objc_hashtable_bucket **data; }; struct objc_sparsearray { struct objc_sparsearray_level2 *buckets[256]; @@ -127,15 +127,17 @@ extern void objc_update_dtable(Class); extern void objc_register_all_classes(struct objc_abi_symtab*); extern Class objc_classname_to_class(const char*, bool); extern void objc_unregister_class(Class); extern void objc_unregister_all_classes(void); -extern uint32_t objc_hash_string(const char*); -extern struct objc_hashtable* objc_hashtable_new(uint32_t); -extern void objc_hashtable_set(struct objc_hashtable*, const char*, +extern uint32_t objc_hash_string(const void*); +extern bool objc_equal_string(const void*, const void*); +extern struct objc_hashtable* objc_hashtable_new(uint32_t (*)(const void*), + bool (*)(const void*, const void*), uint32_t); +extern void objc_hashtable_set(struct objc_hashtable*, const void*, const void*); -extern void* objc_hashtable_get(struct objc_hashtable*, const char*); +extern void* objc_hashtable_get(struct objc_hashtable*, const void*); extern void objc_hashtable_free(struct objc_hashtable *h); extern void objc_register_selector(struct objc_abi_selector*); extern void objc_register_all_selectors(struct objc_abi_symtab*); extern void objc_unregister_all_selectors(void); extern struct objc_sparsearray* objc_sparsearray_new(void); Index: src/runtime/selector.m ================================================================== --- src/runtime/selector.m +++ src/runtime/selector.m @@ -45,11 +45,12 @@ if (selectors_cnt > SEL_MAX) OBJC_ERROR("Out of selector slots!"); if (selectors == NULL) - selectors = objc_hashtable_new(2); + selectors = objc_hashtable_new( + objc_hash_string, objc_equal_string, 2); else if ((rsel = objc_hashtable_get(selectors, sel->name)) != NULL) { ((struct objc_selector*)sel)->uid = rsel->uid; return; }