Index: src/runtime/class.m ================================================================== --- src/runtime/class.m +++ src/runtime/class.m @@ -26,18 +26,25 @@ #import "runtime-private.h" static struct objc_hashtable *classes = NULL; static Class *load_queue = NULL; static size_t load_queue_cnt = 0; +static struct objc_sparsearray *empty_dtable = NULL; static void register_class(struct objc_abi_class *cls) { if (classes == NULL) classes = objc_hashtable_alloc(2); objc_hashtable_set(classes, cls->name, cls); + + if (empty_dtable == NULL) + empty_dtable = objc_sparsearray_new(); + + cls->dtable = empty_dtable; + cls->metaclass->dtable = empty_dtable; } BOOL class_registerAlias_np(Class cls, const char *name) { @@ -128,11 +135,14 @@ { struct objc_method_list *ml; struct objc_category **cats; unsigned int i; - if (cls->dtable == NULL) + if (!(cls->info & OBJC_CLASS_INFO_INITIALIZED)) + return; + + if (cls->dtable == empty_dtable) cls->dtable = objc_sparsearray_new(); if (cls->superclass != Nil) objc_sparsearray_copy(cls->dtable, cls->superclass->dtable); @@ -217,13 +227,10 @@ add_subclass(cls); add_subclass(cls->isa); } else cls->isa->superclass = cls; - objc_update_dtable(cls); - objc_update_dtable(cls->isa); - cls->info |= OBJC_CLASS_INFO_SETUP; cls->isa->info |= OBJC_CLASS_INFO_SETUP; } static void @@ -240,12 +247,45 @@ * in the initialize method */ cls->info |= OBJC_CLASS_INFO_INITIALIZED; cls->isa->info |= OBJC_CLASS_INFO_INITIALIZED; + objc_update_dtable(cls); + objc_update_dtable(cls->isa); + call_method(cls, "initialize"); } + +void +objc_initialize_class(Class cls) +{ + if (cls->info & OBJC_CLASS_INFO_INITIALIZED) + return; + + objc_global_mutex_lock(); + + /* + * It's possible that two threads try to initialize a class at the same + * time. Make sure that the thread which held the lock did not already + * initialize it. + */ + if (cls->info & OBJC_CLASS_INFO_INITIALIZED) { + objc_global_mutex_unlock(); + return; + } + + setup_class(cls); + + if (!(cls->info & OBJC_CLASS_INFO_SETUP)) { + objc_global_mutex_unlock(); + return; + } + + initialize_class(cls); + + objc_global_mutex_unlock(); +} void objc_register_all_classes(struct objc_abi_symtab *symtab) { uint_fast32_t i; @@ -317,35 +357,21 @@ Class cls = objc_classname_to_class(name); if (cls == NULL) return Nil; - if (cls->info & OBJC_CLASS_INFO_INITIALIZED) + if (cls->info & OBJC_CLASS_INFO_SETUP) return cls; objc_global_mutex_lock(); - /* - * It's possible that two threads try to get a class at the same time. - * Make sure that the thread which held the lock did not already - * initialize it. - */ - if (cls->info & OBJC_CLASS_INFO_INITIALIZED) { - objc_global_mutex_unlock(); - return cls; - } - setup_class(cls); - if (!(cls->info & OBJC_CLASS_INFO_SETUP)) { - objc_global_mutex_unlock(); - return Nil; - } - - initialize_class(cls); - - objc_global_mutex_unlock(); + objc_global_mutex_unlock(); + + if (!(cls->info & OBJC_CLASS_INFO_SETUP)) + return Nil; return cls; } Class Index: src/runtime/lookup.m ================================================================== --- src/runtime/lookup.m +++ src/runtime/lookup.m @@ -26,10 +26,33 @@ IMP (*objc_forward_handler)(id, SEL) = NULL; IMP objc_not_found_handler(id obj, SEL sel) { + if (!(obj->isa->info & OBJC_CLASS_INFO_INITIALIZED)) { + BOOL is_class = obj->isa->info & OBJC_CLASS_INFO_METACLASS; + Class cls = (is_class ? (Class)obj : obj->isa); + + objc_initialize_class(cls); + + if (!(cls->info & OBJC_CLASS_INFO_SETUP)) { + if (is_class) + return objc_msg_lookup(nil, sel); + else + ERROR("Could not dispatch message for " + "incomplete class %s!", cls->name); + } + + /* + * We don't need to handle the case that super was called. + * The reason for this is that a call to super is not possible + * before a message to the class has been sent and it thus has + * been initialized together with its superclasses. + */ + return objc_msg_lookup(obj, sel); + } + if (objc_forward_handler != NULL) return objc_forward_handler(obj, sel); ERROR("Selector %s is not implemented for class %s!", sel_getName(sel), obj->isa->name); Index: src/runtime/runtime-private.h ================================================================== --- src/runtime/runtime-private.h +++ src/runtime/runtime-private.h @@ -139,10 +139,11 @@ } objc_mutex_t; extern void objc_register_all_categories(struct objc_abi_symtab*); extern struct objc_category** objc_categories_for_class(Class); extern void objc_free_all_categories(void); +extern void objc_initialize_class(Class); extern void objc_update_dtable(Class); extern void objc_register_all_classes(struct objc_abi_symtab*); extern Class objc_classname_to_class(const char*); extern void objc_free_all_classes(void); extern uint32_t objc_hash_string(const char*);