diff --git a/class.h b/class.h index ddadb39..c80e5a4 100644 --- a/class.h +++ b/class.h @@ -7,29 +7,28 @@ struct objc_class * methods use when a message is sent to the class, rather than an * instance. */ - struct objc_class *isa; + struct objc_class *isa; /** * Pointer to the superclass. The compiler will set this to the name of * the superclass, the runtime will initialize it to point to the real * class. */ - struct objc_class *super_class; + struct objc_class *super_class; /** * The name of this class. Set to the same value for both the class and * its associated metaclass. */ - const char* name; + const char *name; /** * The version of this class. This is not used by the language, but may be * set explicitly at class load time. */ - long version; + long version; /** * A bitfield containing various flags. See the objc_class_flags - * enumerated type for possible values. The top half of this value - * contains the class number. + * enumerated type for possible values. */ - unsigned long info; + unsigned long info; /** * The size of this class. For classes using the non-fragile ABI, the * compiler will set this to a negative value The absolute value will be @@ -40,33 +39,33 @@ struct objc_class * In both cases, this will be set to the size of an instance of the class * after the class is registered with the runtime. */ - long instance_size; + long instance_size; /** * Metadata describing the instance variables in this class. */ - struct objc_ivar_list* ivars; + struct objc_ivar_list *ivars; /** * Metadata for for defining the mappings from selectors to IMPs. Linked * list of method list structures, one per class and one per category. */ - struct objc_method_list* methods; + struct objc_method_list *methods; /** * The dispatch table for this class. Intialized and maintained by the * runtime. */ - struct sarray * dtable; + void *dtable; /** * A pointer to the first subclass for this class. Filled in by the * runtime. */ - struct objc_class* subclass_list; + struct objc_class *subclass_list; /** * A pointer to the next sibling class to this. You may find all * subclasses of a given class by following the subclass_list pointer and * then subsequently following the sibling_class pointers in the * subclasses. */ - struct objc_class* sibling_class; + struct objc_class *sibling_class; /** * Metadata describing the protocols adopted by this class. Not used by @@ -76,7 +75,7 @@ struct objc_class /** * Pointer used by the Boehm GC. */ - void* gc_object_type; + void *gc_object_type; /** * New ABI. The following fields are only available with classes compiled to * support the new ABI. You may test whether any given class supports this @@ -86,7 +85,7 @@ struct objc_class /** * The version of the ABI used for this class. This is currently always zero. */ - long abi_version; + long abi_version; /** * Array of pointers to variables where the runtime will store the ivar @@ -103,7 +102,7 @@ struct objc_class * where they are used. The legacy-compatible ABI uses these with a double * layer of indirection. */ - int **ivar_offsets; + int **ivar_offsets; /** * List of declared properties on this class (NULL if none). This contains * the accessor methods for each property. diff --git a/class_table.c b/class_table.c index 90f5a4f..7c6d150 100644 --- a/class_table.c +++ b/class_table.c @@ -2,10 +2,63 @@ #include "objc/runtime.h" #include "objc/hooks.h" #include "class.h" +#include "method_list.h" +#include "selector.h" #include "lock.h" #include #include +void __objc_register_selectors_from_class(Class class); +void *__objc_uninstalled_dtable; +void __objc_init_protocols(struct objc_protocol_list *protos); +void __objc_compute_ivar_offsets(Class class); + +//////////////////////////////////////////////////////////////////////////////// +// +load method hash table +//////////////////////////////////////////////////////////////////////////////// +static int imp_compare(IMP i1, IMP i2) +{ + return i1 == i2; +} +static int imp_hash(const IMP imp) +{ + return ((int)imp) >> 4; +} +#define MAP_TABLE_NAME load_messages +#define MAP_TABLE_COMPARE_FUNCTION imp_compare +#define MAP_TABLE_HASH_KEY imp_hash +#define MAP_TABLE_HASH_VALUE imp_hash +#include "hash_table.h" + +static load_messages_table *load_table; + +SEL loadSel; + +void objc_init_load_messages_table(void) +{ + load_table = load_messages_create(4096); + loadSel = sel_registerName("load"); +} + +void objc_send_load_message(Class class) +{ + for (struct objc_method_list *l=class->methods ; NULL!=l ; l=l->next) + { + for (int i=0 ; icount ; i++) + { + Method m = &l->methods[i]; + if (m->selector->name == loadSel->name) + { + if (load_messages_table_get(load_table, m->imp) == 0) + { + m->imp((id)class, loadSel); + load_messages_insert(load_table, m->imp); + } + } + } + } +} + // Get the functions for string hashing #include "string_hash.h" @@ -38,6 +91,10 @@ static class_table_internal_table *class_table; */ static Class unresolved_class_list; +//////////////////////////////////////////////////////////////////////////////// +// Class table manipulation +//////////////////////////////////////////////////////////////////////////////// + void class_table_insert(Class class) { if (!objc_test_class_flag(class, objc_class_flag_resolved)) @@ -65,13 +122,50 @@ Class class_table_next(void **e) void __objc_init_class_tables(void) { - class_table = class_table_internal_create(16); + class_table = class_table_internal_create(4096); + objc_init_load_messages_table(); } -void objc_resolve_class(Class cls) +//////////////////////////////////////////////////////////////////////////////// +// Loader functions +//////////////////////////////////////////////////////////////////////////////// + +BOOL objc_resolve_class(Class cls) { // Skip this if the class is already resolved. - if (objc_test_class_flag(cls, objc_class_flag_resolved)) { return; } + if (objc_test_class_flag(cls, objc_class_flag_resolved)) { return YES; } + + // We can only resolve the class if its superclass is resolved. + if (cls->super_class) + { + Class super = (Class)objc_getClass((char*)cls->super_class); + if (Nil == super) { return NO; } + + if (!objc_test_class_flag(cls, objc_class_flag_resolved)) + { + if (!objc_resolve_class(super)) + { + return NO; + } + } + } + + + // Give up if we can't resolve the root class yet... + static Class root_class = Nil; + if (Nil == root_class) + { + root_class = (Class)objc_getClass(ROOT_OBJECT_CLASS_NAME); + if (Nil == root_class) { return NO; } + + if (!objc_test_class_flag(root_class, objc_class_flag_resolved)) + { + objc_resolve_class(root_class); + } + assert(root_class); + } + + // Remove the class from the unresolved class list if (Nil == cls->unresolved_class_prev) { @@ -90,17 +184,6 @@ void objc_resolve_class(Class cls) cls->unresolved_class_prev = Nil; cls->unresolved_class_next = Nil; - static Class root_class = Nil; - if (Nil == root_class) - { - root_class = (Class)objc_getClass(ROOT_OBJECT_CLASS_NAME); - if (!objc_test_class_flag(root_class, objc_class_flag_resolved)) - { - objc_resolve_class(root_class); - } - assert(root_class); - } - // Resolve the superclass pointer // If this class has no superclass, use [NS]Object @@ -132,18 +215,30 @@ void objc_resolve_class(Class cls) // Mark this class (and its metaclass) as resolved objc_set_class_flag(cls, objc_class_flag_resolved); objc_set_class_flag(cls->isa, objc_class_flag_resolved); + // Fix up the ivar offsets + __objc_compute_ivar_offsets(cls); + // Send the +load message, if required + objc_send_load_message(cls->isa); + if (_objc_load_callback) + { + _objc_load_callback(cls, 0); + } + return YES; } void __objc_resolve_class_links(void) { LOCK_UNTIL_RETURN(__objc_runtime_mutex); - Class class; - while ((class = unresolved_class_list)) + Class class = unresolved_class_list; + while ((Nil != class)) { + Class next = class->unresolved_class_next; objc_resolve_class(class); + class = next; } } +// FIXME: Remove this once all uses of it in the runtime have been removed void __objc_add_class_to_hash(Class class) { Class old_class = class_table_get_safe(class->name); @@ -156,7 +251,49 @@ void __objc_add_class_to_hash(Class class) class_table_insert (class); } +/** + * Loads a class. This function assumes that the runtime mutex is locked. + */ +void objc_load_class(struct objc_class *class) +{ + // The compiler initialises the super class pointer to the name of the + // superclass, not the superclass pointer. + // Note: With the new ABI, the class pointer is public. We could, + // therefore, directly reference the superclass from the compiler and make + // the linker resolve it. This should be done in the GCC-incompatible ABI. + const char *superclassName = (char*)class->super_class; + + // Work around a bug in some versions of GCC that don't initialize the + // class structure correctly. + class->subclass_list = NULL; + + // Insert the class into the class table + class_table_insert (class); + + // Register all of the selectors used by this class and its metaclass + __objc_register_selectors_from_class(class); + __objc_register_selectors_from_class(class->isa); + + // Set the uninstalled dtable. The compiler could do this as well. + class->dtable = __objc_uninstalled_dtable; + class->isa->dtable = __objc_uninstalled_dtable; + + // If this is a root class, make the class into the metaclass's superclass. + // This means that all instance methods will be available to the class. + if (NULL == superclassName) + { + class->isa->super_class = class; + } + + if (class->protocols) + { + __objc_init_protocols (class->protocols); + } +} + +//////////////////////////////////////////////////////////////////////////////// // Public API +//////////////////////////////////////////////////////////////////////////////// int objc_getClassList(Class *buffer, int bufferLen) { @@ -175,6 +312,16 @@ int objc_getClassList(Class *buffer, int bufferLen) return count; } +Class class_getSuperclass(Class cls) +{ + if (!objc_test_class_flag(cls, objc_class_flag_resolved)) + { + objc_resolve_class(cls); + } + return cls->super_class; +} + + id objc_getClass(const char *name) { id class = (id)class_table_get_safe(name); diff --git a/init.c b/init.c index cac07b9..6973a82 100644 --- a/init.c +++ b/init.c @@ -38,9 +38,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define OBJC2_PROTOCOL_VERSION 3 void __objc_sync_init(void); - -/* This list contains all modules currently loaded into the runtime. */ -static struct objc_list *__objc_module_list = 0; /* !T:MUTEX */ +void __objc_resolve_class_links(void); +void objc_load_class(struct objc_class *class); /* This list contains all proto_list's not yet assigned class links. */ static struct objc_list *unclaimed_proto_list = 0; /* !T:MUTEX */ @@ -55,381 +54,20 @@ objc_mutex_t __objc_runtime_mutex = &objc_runtime_mutex; /* Number of threads that are alive. */ int __objc_runtime_threads_alive = 1; /* !T:MUTEX */ +void __objc_register_selector_array(SEL selectors, unsigned long count); + /* Check compiler vs runtime version. */ static void init_check_module_version (Module_t); /* Assign isa links to protos. */ -static void __objc_init_protocols (struct objc_protocol_list *protos); +void __objc_init_protocols (struct objc_protocol_list *protos); /* Add protocol to class. */ static void __objc_class_add_protocols (Class, struct objc_protocol_list *); -/* This is a hook which is called by __objc_exec_class every time a - class or a category is loaded into the runtime. This may e.g. help - a dynamic loader determine the classes that have been loaded when - an object file is dynamically linked in. */ -void (*_objc_load_callback) (Class class, Category *category); /* !T:SAFE */ - /* Is all categories/classes resolved? */ BOOL __objc_dangling_categories = NO; /* !T:UNUSED */ -void __objc_register_selector_array(SEL selectors, unsigned long count); - -/* Sends +load to all classes and categories in certain situations. */ -static void objc_send_load (void); - -/* Inserts all the classes defined in module in a tree of classes that - resembles the class hierarchy. This tree is traversed in preorder - and the classes in its nodes receive the +load message if these - methods were not executed before. The algorithm ensures that when - the +load method of a class is executed all the superclasses have - been already received the +load message. */ -static void __objc_create_classes_tree (Module_t module); - -static void __objc_call_callback (Module_t module); - -/* A special version that works only before the classes are completely - installed in the runtime. */ -static BOOL class_is_subclass_of_class (Class class, Class superclass); - -extern void *__objc_uninstalled_dtable; - -typedef struct objc_class_tree { - Class class; - struct objc_list *subclasses; /* `head' is pointer to an objc_class_tree */ -} objc_class_tree; - -/* This is a linked list of objc_class_tree trees. The head of these - trees are root classes (their super class is Nil). These different - trees represent different class hierarchies. */ -static struct objc_list *__objc_class_tree_list = NULL; - -/* Keeps the +load methods who have been already executed. This hash - should not be destroyed during the execution of the program. */ -static cache_ptr __objc_load_methods = NULL; - -/* This function is used when building the class tree used to send - ordinately the +load message to all classes needing it. The tree - is really needed so that superclasses will get the message before - subclasses. - - This tree will contain classes which are being loaded (or have just - being loaded), and whose super_class pointers have not yet been - resolved. This implies that their super_class pointers point to a - string with the name of the superclass; when the first message is - sent to the class (/an object of that class) the class links will - be resolved, which will replace the super_class pointers with - pointers to the actual superclasses. - - Unfortunately, the tree might also contain classes which had been - loaded previously, and whose class links have already been - resolved. - - This function returns the superclass of a class in both cases, and - can be used to build the determine the class relationships while - building the tree. -*/ -static Class class_superclass_of_class (Class class) -{ - char *super_class_name; - - /* If the class links have been resolved, use the resolved - * links. */ - if (CLS_ISRESOLV (class)) - return class->super_class; - - /* Else, 'class' has not yet been resolved. This means that its - * super_class pointer is really the name of the super class (rather - * than a pointer to the actual superclass). */ - super_class_name = (char *)class->super_class; - - /* Return Nil for a root class. */ - if (super_class_name == NULL) - return Nil; - - /* Lookup the superclass of non-root classes. */ - return objc_lookup_class (super_class_name); -} - - -/* Creates a tree of classes whose topmost class is directly inherited - from `upper' and the bottom class in this tree is - `bottom_class'. The classes in this tree are super classes of - `bottom_class'. `subclasses' member of each tree node point to the - next subclass tree node. */ - -static objc_class_tree * -create_tree_of_subclasses_inherited_from (Class bottom_class, Class upper) -{ - Class superclass = bottom_class->super_class ? - objc_lookup_class ((char *) bottom_class->super_class) - : Nil; - - objc_class_tree *tree, *prev; - - DEBUG_PRINTF ("create_tree_of_subclasses_inherited_from:"); - DEBUG_PRINTF ("bottom_class = %s, upper = %s\n", - (bottom_class ? bottom_class->name : NULL), - (upper ? upper->name : NULL)); - - tree = prev = objc_calloc (1, sizeof (objc_class_tree)); - prev->class = bottom_class; - - while (superclass != upper) - { - tree = objc_calloc (1, sizeof (objc_class_tree)); - tree->class = superclass; - tree->subclasses = list_cons (prev, tree->subclasses); - superclass = class_superclass_of_class (superclass); - prev = tree; - } - - return tree; -} - -/* Insert the `class' into the proper place in the `tree' class - hierarchy. This function returns a new tree if the class has been - successfully inserted into the tree or NULL if the class is not - part of the classes hierarchy described by `tree'. This function is - private to objc_tree_insert_class (), you should not call it - directly. */ - -static objc_class_tree * -__objc_tree_insert_class (objc_class_tree *tree, Class class) -{ - DEBUG_PRINTF ("__objc_tree_insert_class: tree = %x, class = %s\n", - (int)tree, class->name); - - if (tree == NULL) - return create_tree_of_subclasses_inherited_from (class, NULL); - else if (class == tree->class) - { - /* `class' has been already inserted */ - DEBUG_PRINTF ("1. class %s was previously inserted\n", class->name); - return tree; - } - else if (class_superclass_of_class (class) == tree->class) - { - /* If class is a direct subclass of tree->class then add class to the - list of subclasses. First check to see if it wasn't already - inserted. */ - struct objc_list *list = tree->subclasses; - objc_class_tree *node; - - while (list) - { - /* Class has been already inserted; do nothing just return - the tree. */ - if (((objc_class_tree *) list->head)->class == class) - { - DEBUG_PRINTF ("2. class %s was previously inserted\n", - class->name); - return tree; - } - list = list->tail; - } - - /* Create a new node class and insert it into the list of subclasses */ - node = objc_calloc (1, sizeof (objc_class_tree)); - node->class = class; - tree->subclasses = list_cons (node, tree->subclasses); - DEBUG_PRINTF ("3. class %s inserted\n", class->name); - return tree; - } - else - { - /* The class is not a direct subclass of tree->class. Search for - class's superclasses in the list of subclasses. */ - struct objc_list *subclasses = tree->subclasses; - - /* Precondition: the class must be a subclass of tree->class; - otherwise return NULL to indicate our caller that it must - take the next tree. */ - if (! class_is_subclass_of_class (class, tree->class)) - return NULL; - - for (; subclasses != NULL; subclasses = subclasses->tail) - { - Class aClass = ((objc_class_tree *) (subclasses->head))->class; - - if (class_is_subclass_of_class (class, aClass)) - { - /* If we found one of class's superclasses we insert the - class into its subtree and return the original tree - since nothing has been changed. */ - subclasses->head - = __objc_tree_insert_class (subclasses->head, class); - DEBUG_PRINTF ("4. class %s inserted\n", class->name); - return tree; - } - } - - /* We haven't found a subclass of `class' in the `subclasses' - list. Create a new tree of classes whose topmost class is a - direct subclass of tree->class. */ - { - objc_class_tree *new_tree - = create_tree_of_subclasses_inherited_from (class, tree->class); - tree->subclasses = list_cons (new_tree, tree->subclasses); - DEBUG_PRINTF ("5. class %s inserted\n", class->name); - return tree; - } - } -} - -/* This function inserts `class' in the right tree hierarchy classes. */ - -static void -objc_tree_insert_class (Class class) -{ - struct objc_list *list_node; - objc_class_tree *tree; - - list_node = __objc_class_tree_list; - while (list_node) - { - tree = __objc_tree_insert_class (list_node->head, class); - if (tree) - { - list_node->head = tree; - break; - } - else - list_node = list_node->tail; - } - - /* If the list was finished but the class hasn't been inserted, - insert it here. */ - if (! list_node) - { - __objc_class_tree_list = list_cons (NULL, __objc_class_tree_list); - __objc_class_tree_list->head = __objc_tree_insert_class (NULL, class); - } -} - -/* Traverse tree in preorder. Used to send +load. */ - -static void -objc_preorder_traverse (objc_class_tree *tree, - int level, - void (*function) (objc_class_tree *, int)) -{ - struct objc_list *node; - - (*function) (tree, level); - for (node = tree->subclasses; node; node = node->tail) - objc_preorder_traverse (node->head, level + 1, function); -} - -/* Traverse tree in postorder. Used to destroy a tree. */ - -static void -objc_postorder_traverse (objc_class_tree *tree, - int level, - void (*function) (objc_class_tree *, int)) -{ - struct objc_list *node; - - for (node = tree->subclasses; node; node = node->tail) - objc_postorder_traverse (node->head, level + 1, function); - (*function) (tree, level); -} - -/* Used to print a tree class hierarchy. */ - -#ifdef DEBUG -static void -__objc_tree_print (objc_class_tree *tree, int level) -{ - int i; - - for (i = 0; i < level; i++) - printf (" "); - printf ("%s\n", tree->class->name); -} -#endif - -/* Walks on a linked list of methods in the reverse order and executes - all the methods corresponding to `op' selector. Walking in the - reverse order assures the +load of class is executed first and then - +load of categories because of the way in which categories are - added to the class methods. */ - -static void -__objc_send_message_in_list (MethodList_t method_list, Class class, SEL op) -{ - int i; - - if (! method_list) - return; - - /* First execute the `op' message in the following method lists */ - __objc_send_message_in_list (method_list->method_next, class, op); - - /* Search the method list. */ - for (i = 0; i < method_list->method_count; i++) - { - Method_t mth = &method_list->method_list[i]; - - if (mth->method_name && sel_eq (mth->method_name, op) - && ! objc_hash_is_key_in_hash (__objc_load_methods, mth->method_imp)) - { - /* Add this method into the +load hash table */ - objc_hash_add (&__objc_load_methods, - mth->method_imp, - mth->method_imp); - - DEBUG_PRINTF ("sending +load in class: %s\n", class->name); - - /* The method was found and wasn't previously executed. */ - (*mth->method_imp) ((id)class, mth->method_name); - - break; - } - } -} - -static void -__objc_send_load (objc_class_tree *tree, - int level __attribute__ ((__unused__))) -{ - static SEL load_sel = 0; - Class class = tree->class; - MethodList_t method_list = class->class_pointer->methods; - - if (! load_sel) - load_sel = sel_register_name ("load"); - - __objc_send_message_in_list (method_list, class, load_sel); -} - -static void -__objc_destroy_class_tree_node (objc_class_tree *tree, - int level __attribute__ ((__unused__))) -{ - objc_free (tree); -} - -/* This is used to check if the relationship between two classes - before the runtime completely installs the classes. */ - -static BOOL -class_is_subclass_of_class (Class class, Class superclass) -{ - for (; class != Nil;) - { - if (class == superclass) - return YES; - class = class_superclass_of_class (class); - } - - return NO; -} - -/* This list contains all the classes in the runtime system for whom - their superclasses are not yet known to the runtime. */ -static struct objc_list *unresolved_classes = 0; - /* Extern function used to reference the Object and NXConstantString classes. */ @@ -557,16 +195,11 @@ __objc_exec_class (Module_t module) __objc_init_protocol_table (); __objc_init_class_tables (); __objc_init_dispatch_tables (); - __objc_class_tree_list = list_cons (NULL, __objc_class_tree_list); - __objc_load_methods = objc_hash_new (128, - (hash_func_type)objc_hash_ptr, - objc_compare_ptrs); previous_constructors = 1; } /* Save the module pointer for later processing. (not currently used) */ LOCK(__objc_runtime_mutex); - __objc_module_list = list_cons (module, __objc_module_list); /* Replace referenced selectors from names to SEL's. */ if (symtab->refs) @@ -578,40 +211,7 @@ __objc_exec_class (Module_t module) DEBUG_PRINTF ("gathering selectors from module: %s\n", module->name); for (i = 0; i < symtab->cls_def_cnt; ++i) { - Class class = (Class) symtab->defs[i]; - const char *superclass = (char *) class->super_class; - - /* Make sure we have what we think. */ - assert (CLS_ISCLASS (class)); - assert (CLS_ISMETA (class->class_pointer)); - DEBUG_PRINTF ("phase 1, processing class: %s\n", class->name); - - /* Initialize the subclass list to be NULL. - In some cases it isn't and this crashes the program. */ - class->subclass_list = NULL; - - /* Store the class in the class table and assign class numbers. */ - __objc_add_class_to_hash (class); - - /* Register all of the selectors in the class and meta class. */ - __objc_register_selectors_from_class (class); - __objc_register_selectors_from_class ((Class) class->class_pointer); - - /* Install the fake dispatch tables */ - class->dtable = __objc_uninstalled_dtable; - class->class_pointer->dtable = __objc_uninstalled_dtable; - - /* Register the instance methods as class methods, this is - only done for root classes. */ - __objc_register_instance_methods_to_class (class); - - if (class->protocols) - __objc_init_protocols (class->protocols); - - /* Check to see if the superclass is known in this point. If it's not - add the class to the unresolved_classes list. */ - if (superclass && ! objc_lookup_class (superclass)) - unresolved_classes = list_cons (class, unresolved_classes); + objc_load_class((Class) symtab->defs[i]); } /* Process category information from the module. */ @@ -703,126 +303,13 @@ __objc_exec_class (Module_t module) unclaimed_proto_list = 0; } - objc_send_load (); + __objc_resolve_class_links(); UNLOCK(__objc_runtime_mutex); } - -static void -objc_send_load (void) -{ - if (! __objc_module_list) - return; - - /* Try to find out if all the classes loaded so far also have their - superclasses known to the runtime. We suppose that the objects - that are allocated in the +load method are in general of a class - declared in the same module. */ - if (unresolved_classes) - { - Class class = unresolved_classes->head; - - while (objc_lookup_class ((char *) class->super_class)) - { - list_remove_head (&unresolved_classes); - if (unresolved_classes) - class = unresolved_classes->head; - else - break; - } - - /* If we still have classes for whom we don't have yet their - super classes known to the runtime we don't send the +load - messages. */ - if (unresolved_classes) - return; - } - - /* Special check to allow creating and sending messages to constant - strings in +load methods. If these classes are not yet known, - even if all the other classes are known, delay sending of +load. */ - if (! objc_lookup_class (CONSTANT_STRING_CLASS) || - ! objc_lookup_class (ROOT_OBJECT_CLASS_NAME)) - return; - - /* Iterate over all modules in the __objc_module_list and call on - them the __objc_create_classes_tree function. This function - creates a tree of classes that resembles the class hierarchy. */ - list_mapcar (__objc_module_list, - (void (*) (void *)) __objc_create_classes_tree); - - while (__objc_class_tree_list) - { -#ifdef DEBUG - objc_preorder_traverse (__objc_class_tree_list->head, - 0, __objc_tree_print); -#endif - objc_preorder_traverse (__objc_class_tree_list->head, - 0, __objc_send_load); - objc_postorder_traverse (__objc_class_tree_list->head, - 0, __objc_destroy_class_tree_node); - list_remove_head (&__objc_class_tree_list); - } - - list_mapcar (__objc_module_list, (void (*) (void *)) __objc_call_callback); - list_free (__objc_module_list); - __objc_module_list = NULL; -} - void __objc_compute_ivar_offsets(Class class); -static void -__objc_create_classes_tree (Module_t module) -{ - /* The runtime mutex is locked in this point */ - - Symtab_t symtab = module->symtab; - int i; - - /* Iterate thru classes defined in this module and insert them in - the classes tree hierarchy. */ - for (i = 0; i < symtab->cls_def_cnt; i++) - { - Class class = (Class) symtab->defs[i]; - - objc_tree_insert_class (class); - __objc_compute_ivar_offsets (class); - } -} - -static void -__objc_call_callback (Module_t module) -{ - /* The runtime mutex is locked in this point. */ - - Symtab_t symtab = module->symtab; - int i; - - /* Iterate thru classes defined in this module and call the callback - for each one. */ - for (i = 0; i < symtab->cls_def_cnt; i++) - { - Class class = (Class) symtab->defs[i]; - - /* Call the _objc_load_callback for this class. */ - if (_objc_load_callback) - _objc_load_callback (class, 0); - } - - /* Call the _objc_load_callback for categories. Don't register the - instance methods as class methods for categories to root classes - since they were already added in the class. */ - for (i = 0; i < symtab->cat_def_cnt; i++) - { - Category_t category = symtab->defs[i + symtab->cls_def_cnt]; - Class class = objc_lookup_class (category->class_name); - - if (_objc_load_callback) - _objc_load_callback (class, category); - } -} - /* Sanity check the version of gcc used to compile `module'. */ static void @@ -846,8 +333,7 @@ init_check_module_version (Module_t module) } struct objc_protocol *__objc_unique_protocol(struct objc_protocol*); -static void -__objc_init_protocols (struct objc_protocol_list *protos) +void __objc_init_protocols (struct objc_protocol_list *protos) { size_t i; static Class proto_class = 0; diff --git a/objc/hooks.h b/objc/hooks.h index b3d9ce5..e071049 100644 --- a/objc/hooks.h +++ b/objc/hooks.h @@ -7,7 +7,7 @@ #ifndef OBJC_HOOK #define OBJC_HOOK extern #endif - +struct objc_category; /** * Class lookup hook. Set this to provide a mechanism for resolving classes * that have not been registered with the runtime. This can be used for lazy @@ -18,3 +18,7 @@ * for lazy loading of categories. */ OBJC_HOOK Class (*_objc_lookup_class)(const char *name); +/** + * Class load callback. + */ +OBJC_HOOK void (*_objc_load_callback)(Class class, struct objc_category *category); diff --git a/runtime.c b/runtime.c index 08e94a6..e3ce5ec 100644 --- a/runtime.c +++ b/runtime.c @@ -418,11 +418,6 @@ const char * class_getName(Class cls) return cls->name; } -Class class_getSuperclass(Class cls) -{ - return class_get_super_class(cls); -} - int class_getVersion(Class theClass) { return class_get_version(theClass);