@@ -18,18 +18,21 @@ #include #include #include +#include + #import "runtime.h" #import "runtime-private.h" struct sparsearray { void *next[256]; }; static struct objc_hashtable *classes = NULL; +static unsigned classes_cnt = 0; static Class *load_queue = NULL; static size_t load_queue_cnt = 0; static struct objc_sparsearray *empty_dtable = NULL; static unsigned lookups_till_fast_path = 128; static struct sparsearray *sparsearray = NULL; @@ -45,10 +48,13 @@ if (empty_dtable == NULL) empty_dtable = objc_sparsearray_new(); cls->dtable = empty_dtable; cls->metaclass->dtable = empty_dtable; + + if (strcmp(cls->name, "Protocol")) + classes_cnt++; } BOOL class_registerAlias_np(Class cls, const char *name) { @@ -502,10 +508,74 @@ Class objc_get_class(const char *name) { return objc_getRequiredClass(name); } + +unsigned int +objc_getClassList(Class *buf, unsigned int count) +{ + uint32_t i; + unsigned int j; + objc_global_mutex_lock(); + + if (buf == NULL) + return classes_cnt; + + if (classes_cnt < count) + count = classes_cnt; + + for (i = j = 0; i <= classes->last_idx; i++) { + Class cls; + + if (j >= count) { + objc_global_mutex_unlock(); + return j; + } + + if (classes->data[i] == NULL) + continue; + + if (!strcmp(classes->data[i]->key, "Protocol")) + continue; + + cls = (Class)classes->data[i]->obj; + + if (cls == Nil || (uintptr_t)cls & 1) + continue; + + buf[j++] = cls; + } + + objc_global_mutex_unlock(); + + return j; +} + +Class* +objc_copyClassList(unsigned int *len) +{ + Class *ret; + unsigned int count; + + objc_global_mutex_lock(); + + if ((ret = malloc((classes_cnt + 1) * sizeof(Class))) == NULL) + OBJC_ERROR("Failed to allocate memory for class list!"); + + count = objc_getClassList(ret, classes_cnt); + assert(count == classes_cnt); + + ret[count] = Nil; + + if (len != NULL) + *len = count; + + objc_global_mutex_unlock(); + + return ret; +} bool class_isMetaClass(Class cls) { return (cls->info & OBJC_CLASS_INFO_METACLASS); @@ -701,17 +771,20 @@ rcls->dtable = NULL; if (rcls->superclass != Nil) cls->superclass = rcls->superclass->name; - - objc_hashtable_set(classes, cls->name, NULL); } void objc_unregister_class(Class cls) { + objc_hashtable_set(classes, cls->name, NULL); + + if (strcmp(cls->name, "Protocol")) + classes_cnt--; + unregister_class(cls); unregister_class(cls->isa); } static void @@ -744,10 +817,12 @@ continue; objc_unregister_class(cls); } } + + assert(classes_cnt == 0); if (empty_dtable != NULL) { objc_sparsearray_free(empty_dtable); empty_dtable = NULL; }