| /* GNU Objective C Runtime initialization |
| Copyright (C) 1993, 1995, 1996, 1997, 2002 Free Software Foundation, Inc. |
| Contributed by Kresten Krab Thorup |
| +load support contributed by Ovidiu Predescu <ovidiu@net-community.com> |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under the |
| terms of the GNU General Public License as published by the Free Software |
| Foundation; either version 2, or (at your option) any later version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
| details. |
| |
| You should have received a copy of the GNU General Public License along with |
| GCC; see the file COPYING. If not, write to the Free Software |
| Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
| |
| /* As a special exception, if you link this library with files compiled with |
| GCC to produce an executable, this does not cause the resulting executable |
| to be covered by the GNU General Public License. This exception does not |
| however invalidate any other reasons why the executable file might be |
| covered by the GNU General Public License. */ |
| |
| #include "runtime.h" |
| |
| /* The version number of this runtime. This must match the number |
| defined in gcc (objc-act.c). */ |
| #define OBJC_VERSION 8 |
| #define PROTOCOL_VERSION 2 |
| |
| /* This list contains all modules currently loaded into the runtime. */ |
| static struct objc_list *__objc_module_list = 0; /* !T:MUTEX */ |
| |
| /* This list contains all proto_list's not yet assigned class links. */ |
| static struct objc_list *unclaimed_proto_list = 0; /* !T:MUTEX */ |
| |
| /* List of unresolved static instances. */ |
| static struct objc_list *uninitialized_statics = 0; /* !T:MUTEX */ |
| |
| /* Global runtime "write" mutex. */ |
| objc_mutex_t __objc_runtime_mutex = 0; |
| |
| /* Number of threads that are alive. */ |
| int __objc_runtime_threads_alive = 1; /* !T:MUTEX */ |
| |
| /* 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); |
| |
| /* 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 */ |
| |
| extern SEL |
| __sel_register_typed_name (const char *name, const char *types, |
| struct objc_selector *orig, BOOL is_const); |
| |
| /* 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); |
| |
| 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", |
| 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) |
| && ! hash_is_key_in_hash (__objc_load_methods, mth->method_imp)) |
| { |
| /* Add this method into the +load hash table */ |
| 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. */ |
| |
| extern void __objc_force_linking (void); |
| |
| void |
| __objc_force_linking (void) |
| { |
| extern void __objc_linking (void); |
| __objc_linking (); |
| } |
| |
| /* Run through the statics list, removing modules as soon as all its |
| statics have been initialized. */ |
| |
| static void |
| objc_init_statics (void) |
| { |
| struct objc_list **cell = &uninitialized_statics; |
| struct objc_static_instances **statics_in_module; |
| |
| objc_mutex_lock (__objc_runtime_mutex); |
| |
| while (*cell) |
| { |
| int module_initialized = 1; |
| |
| for (statics_in_module = (*cell)->head; |
| *statics_in_module; statics_in_module++) |
| { |
| struct objc_static_instances *statics = *statics_in_module; |
| Class class = objc_lookup_class (statics->class_name); |
| |
| if (! class) |
| module_initialized = 0; |
| /* Actually, the static's class_pointer will be NULL when we |
| haven't been here before. However, the comparison is to be |
| reminded of taking into account class posing and to think about |
| possible semantics... */ |
| else if (class != statics->instances[0]->class_pointer) |
| { |
| id *inst; |
| |
| for (inst = &statics->instances[0]; *inst; inst++) |
| { |
| (*inst)->class_pointer = class; |
| |
| /* ??? Make sure the object will not be freed. With |
| refcounting, invoke `-retain'. Without refcounting, do |
| nothing and hope that `-free' will never be invoked. */ |
| |
| /* ??? Send the object an `-initStatic' or something to |
| that effect now or later on? What are the semantics of |
| statically allocated instances, besides the trivial |
| NXConstantString, anyway? */ |
| } |
| } |
| } |
| if (module_initialized) |
| { |
| /* Remove this module from the uninitialized list. */ |
| struct objc_list *this = *cell; |
| *cell = this->tail; |
| objc_free (this); |
| } |
| else |
| cell = &(*cell)->tail; |
| } |
| |
| objc_mutex_unlock (__objc_runtime_mutex); |
| } /* objc_init_statics */ |
| |
| /* This function is called by constructor functions generated for each |
| module compiled. (_GLOBAL_$I$...) The purpose of this function is |
| to gather the module pointers so that they may be processed by the |
| initialization routines as soon as possible. */ |
| |
| void |
| __objc_exec_class (Module_t module) |
| { |
| /* Have we processed any constructors previously? This flag is used to |
| indicate that some global data structures need to be built. */ |
| static BOOL previous_constructors = 0; |
| |
| static struct objc_list *unclaimed_categories = 0; |
| |
| /* The symbol table (defined in objc-api.h) generated by gcc */ |
| Symtab_t symtab = module->symtab; |
| |
| /* The statics in this module */ |
| struct objc_static_instances **statics |
| = symtab->defs[symtab->cls_def_cnt + symtab->cat_def_cnt]; |
| |
| /* Entry used to traverse hash lists */ |
| struct objc_list **cell; |
| |
| /* The table of selector references for this module */ |
| SEL selectors = symtab->refs; |
| |
| /* dummy counter */ |
| int i; |
| |
| DEBUG_PRINTF ("received module: %s\n", module->name); |
| |
| /* check gcc version */ |
| init_check_module_version (module); |
| |
| /* On the first call of this routine, initialize some data structures. */ |
| if (! previous_constructors) |
| { |
| /* Initialize thread-safe system */ |
| __objc_init_thread_system (); |
| __objc_runtime_threads_alive = 1; |
| __objc_runtime_mutex = objc_mutex_allocate (); |
| |
| __objc_init_selector_tables (); |
| __objc_init_class_tables (); |
| __objc_init_dispatch_tables (); |
| __objc_class_tree_list = list_cons (NULL, __objc_class_tree_list); |
| __objc_load_methods |
| = hash_new (128, (hash_func_type)hash_ptr, compare_ptrs); |
| previous_constructors = 1; |
| } |
| |
| /* Save the module pointer for later processing. (not currently used) */ |
| objc_mutex_lock (__objc_runtime_mutex); |
| __objc_module_list = list_cons (module, __objc_module_list); |
| |
| /* Replace referenced selectors from names to SEL's. */ |
| if (selectors) |
| { |
| for (i = 0; selectors[i].sel_id; ++i) |
| { |
| const char *name, *type; |
| name = (char *) selectors[i].sel_id; |
| type = (char *) selectors[i].sel_types; |
| /* Constructors are constant static data so we can safely store |
| pointers to them in the runtime structures. is_const == YES */ |
| __sel_register_typed_name (name, type, |
| (struct objc_selector *) &(selectors[i]), |
| YES); |
| } |
| } |
| |
| /* Parse the classes in the load module and gather selector information. */ |
| 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 */ |
| __objc_install_premature_dtable (class); |
| __objc_install_premature_dtable (class->class_pointer); |
| |
| /* 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); |
| } |
| |
| /* Process category information from the module. */ |
| 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 the class for the category exists then append its methods. */ |
| if (class) |
| { |
| |
| DEBUG_PRINTF ("processing categories from (module,object): %s, %s\n", |
| module->name, |
| class->name); |
| |
| /* Do instance methods. */ |
| if (category->instance_methods) |
| class_add_method_list (class, category->instance_methods); |
| |
| /* Do class methods. */ |
| if (category->class_methods) |
| class_add_method_list ((Class) class->class_pointer, |
| category->class_methods); |
| |
| if (category->protocols) |
| { |
| __objc_init_protocols (category->protocols); |
| __objc_class_add_protocols (class, category->protocols); |
| } |
| |
| /* Register the instance methods as class methods, this is |
| only done for root classes. */ |
| __objc_register_instance_methods_to_class (class); |
| } |
| else |
| { |
| /* The object to which the category methods belong can't be found. |
| Save the information. */ |
| unclaimed_categories = list_cons (category, unclaimed_categories); |
| } |
| } |
| |
| if (statics) |
| uninitialized_statics = list_cons (statics, uninitialized_statics); |
| if (uninitialized_statics) |
| objc_init_statics (); |
| |
| /* Scan the unclaimed category hash. Attempt to attach any unclaimed |
| categories to objects. */ |
| for (cell = &unclaimed_categories; *cell; ) |
| { |
| Category_t category = (*cell)->head; |
| Class class = objc_lookup_class (category->class_name); |
| |
| if (class) |
| { |
| DEBUG_PRINTF ("attaching stored categories to object: %s\n", |
| class->name); |
| |
| list_remove_head (cell); |
| |
| if (category->instance_methods) |
| class_add_method_list (class, category->instance_methods); |
| |
| if (category->class_methods) |
| class_add_method_list ((Class) class->class_pointer, |
| category->class_methods); |
| |
| if (category->protocols) |
| { |
| __objc_init_protocols (category->protocols); |
| __objc_class_add_protocols (class, category->protocols); |
| } |
| |
| /* Register the instance methods as class methods, this is |
| only done for root classes. */ |
| __objc_register_instance_methods_to_class (class); |
| } |
| else |
| cell = &(*cell)->tail; |
| } |
| |
| if (unclaimed_proto_list && objc_lookup_class ("Protocol")) |
| { |
| list_mapcar (unclaimed_proto_list, |
| (void (*) (void *))__objc_init_protocols); |
| list_free (unclaimed_proto_list); |
| unclaimed_proto_list = 0; |
| } |
| |
| objc_send_load (); |
| |
| objc_mutex_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 ("NXConstantString") || |
| ! objc_lookup_class ("Object")) |
| 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; |
| } |
| |
| 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); |
| } |
| } |
| |
| 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 |
| init_check_module_version (Module_t module) |
| { |
| if ((module->version != OBJC_VERSION) || (module->size != sizeof (Module))) |
| { |
| int code; |
| |
| if (module->version > OBJC_VERSION) |
| code = OBJC_ERR_OBJC_VERSION; |
| else if (module->version < OBJC_VERSION) |
| code = OBJC_ERR_GCC_VERSION; |
| else |
| code = OBJC_ERR_MODULE_SIZE; |
| |
| objc_error (nil, code, "Module %s version %d doesn't match runtime %d\n", |
| module->name, (int)module->version, OBJC_VERSION); |
| } |
| } |
| |
| static void |
| __objc_init_protocols (struct objc_protocol_list *protos) |
| { |
| size_t i; |
| static Class proto_class = 0; |
| |
| if (! protos) |
| return; |
| |
| objc_mutex_lock (__objc_runtime_mutex); |
| |
| if (! proto_class) |
| proto_class = objc_lookup_class ("Protocol"); |
| |
| if (! proto_class) |
| { |
| unclaimed_proto_list = list_cons (protos, unclaimed_proto_list); |
| objc_mutex_unlock (__objc_runtime_mutex); |
| return; |
| } |
| |
| #if 0 |
| assert (protos->next == 0); /* only single ones allowed */ |
| #endif |
| |
| for (i = 0; i < protos->count; i++) |
| { |
| struct objc_protocol *aProto = protos->list[i]; |
| if (((size_t)aProto->class_pointer) == PROTOCOL_VERSION) |
| { |
| /* assign class pointer */ |
| aProto->class_pointer = proto_class; |
| |
| /* init super protocols */ |
| __objc_init_protocols (aProto->protocol_list); |
| } |
| else if (protos->list[i]->class_pointer != proto_class) |
| { |
| objc_error (nil, OBJC_ERR_PROTOCOL_VERSION, |
| "Version %d doesn't match runtime protocol version %d\n", |
| (int) ((char *) protos->list[i]->class_pointer |
| - (char *) 0), |
| PROTOCOL_VERSION); |
| } |
| } |
| |
| objc_mutex_unlock (__objc_runtime_mutex); |
| } |
| |
| static void |
| __objc_class_add_protocols (Class class, struct objc_protocol_list *protos) |
| { |
| /* Well... */ |
| if (! protos) |
| return; |
| |
| /* Add it... */ |
| protos->next = class->protocols; |
| class->protocols = protos; |
| } |