| /* GNU Objective C Runtime initialization | |
| Copyright (C) 1993-2026 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 3, 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. | |
| Under Section 7 of GPL version 3, you are granted additional | |
| permissions described in the GCC Runtime Library Exception, version | |
| 3.1, as published by the Free Software Foundation. | |
| You should have received a copy of the GNU General Public License and | |
| a copy of the GCC Runtime Library Exception along with this program; | |
| see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
| <http://www.gnu.org/licenses/>. */ | |
| /* Uncommented the following line to enable debug logging. Use this | |
| only while debugging the runtime. */ | |
| /* #define DEBUG 1 */ | |
| #include "objc-private/common.h" | |
| #include "objc-private/error.h" | |
| #include "objc/runtime.h" | |
| #include "objc/thr.h" | |
| #include "objc-private/hash.h" | |
| #include "objc-private/objc-list.h" | |
| #include "objc-private/module-abi-8.h" | |
| #include "objc-private/runtime.h" /* For __objc_resolve_class_links(). */ | |
| #include "objc-private/selector.h" /* For __sel_register_typed_name(). */ | |
| #include "objc-private/objc-sync.h" /* For __objc_sync_init() */ | |
| #include "objc-private/protocols.h" /* For __objc_protocols_init(), | |
| __objc_protocols_add_protocol() | |
| __objc_protocols_register_selectors() */ | |
| #include "objc-private/accessors.h" /* For __objc_accessors_init() */ | |
| /* 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 modules currently loaded into the runtime and | |
| for which the +load method (and the load callback, if any) has not | |
| been called yet. */ | |
| 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 */ | |
| /* List of duplicated classes found while loading modules. If we find | |
| a class twice, we ignore it the second time. On some platforms, | |
| where the order in which modules are loaded is well defined, this | |
| allows you to replace a class in a shared library by linking in a | |
| new implementation which is loaded in the right order, and which | |
| overrides the existing one. | |
| Protected by __objc_runtime_mutex. */ | |
| static cache_ptr duplicate_classes = NULL; | |
| /* Global runtime "write" mutex. Having a single mutex prevents | |
| deadlocks, but reduces concurrency. To improve concurrency, some | |
| groups of functions in the runtime have their own separate mutex | |
| (eg, __class_table_lock in class.c); to avoid deadlocks, these | |
| routines must make sure that they never acquire any other lock | |
| while holding their own local lock. Ie, they should lock, execute | |
| some C code that does not perform any calls to other runtime | |
| functions which may potentially lock different locks, then unlock. | |
| If they need to perform any calls to other runtime functions that | |
| may potentially lock other locks, then they should use the global | |
| __objc_runtime_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 (struct objc_module *); | |
| /* Assign isa links to protos. */ | |
| static void __objc_init_protocols (struct objc_protocol_list *protos); | |
| /* Assign isa link to a protocol, and register it. */ | |
| static void __objc_init_protocol (struct objc_protocol *protocol); | |
| /* Add protocol to class. */ | |
| static void __objc_class_add_protocols (Class, struct objc_protocol_list *); | |
| /* Load callback hook. */ | |
| void (*_objc_load_callback) (Class class, struct objc_category *category) = 0; /* !T:SAFE */ | |
| /* Are all categories/classes resolved ? */ | |
| BOOL __objc_dangling_categories = NO; /* !T:UNUSED */ | |
| /* 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 (struct objc_module *module); | |
| /* Calls the _objc_load_callback for each class and category in the | |
| module (if _objc_load_callback is not NULL). */ | |
| static void __objc_call_load_callback (struct objc_module *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); | |
| /* This is a node in the class tree hierarchy used to send +load | |
| messages. */ | |
| typedef struct objc_class_tree | |
| { | |
| /* The class corresponding to the node. */ | |
| Class class; | |
| /* This is a linked list of all the direct subclasses of this class. | |
| 'head' points to a subclass node; 'tail' points to the next | |
| objc_list node (whose 'head' points to another subclass node, | |
| etc). */ | |
| struct objc_list *subclasses; | |
| } 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 may 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_getClass (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'. | |
| If `upper' is Nil, creates a class hierarchy up to a root class. | |
| The classes in this tree are super classes of `bottom_class'. The | |
| `subclasses' member of each tree node point to the list of | |
| subclasses for the node. */ | |
| static objc_class_tree * | |
| create_tree_of_subclasses_inherited_from (Class bottom_class, Class upper) | |
| { | |
| Class superclass; | |
| 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)); | |
| superclass = class_superclass_of_class (bottom_class); | |
| prev = objc_calloc (1, sizeof (objc_class_tree)); | |
| prev->class = bottom_class; | |
| if (superclass == upper) | |
| return prev; | |
| 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 = %p (root: %s), class = %s\n", | |
| tree, ((tree && tree->class) ? tree->class->name : "Nil"), 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) | |
| { | |
| /* Try to insert the class in this class hierarchy. */ | |
| tree = __objc_tree_insert_class (list_node->head, class); | |
| if (tree) | |
| { | |
| list_node->head = tree; | |
| return; | |
| } | |
| else | |
| list_node = list_node->tail; | |
| } | |
| /* If the list was finished but the class hasn't been inserted, we | |
| don't have an existing class hierarchy that can accommodate it. | |
| Create a new one. */ | |
| __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 the `+load' 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. This function needs to be called with | |
| the objc_runtime_mutex locked. */ | |
| static void | |
| __objc_send_load_using_method_list (struct objc_method_list *method_list, Class class) | |
| { | |
| static SEL load_selector = 0; | |
| int i; | |
| if (!method_list) | |
| return; | |
| /* This needs no lock protection because we are called with the | |
| objc_runtime_mutex locked. */ | |
| if (!load_selector) | |
| load_selector = sel_registerName ("load"); | |
| /* method_list is a linked list of method lists; since we're | |
| executing in reverse order, we need to do the next list before we | |
| do this one. */ | |
| __objc_send_load_using_method_list (method_list->method_next, class); | |
| /* Search the method list. */ | |
| for (i = 0; i < method_list->method_count; i++) | |
| { | |
| struct objc_method *mth = &method_list->method_list[i]; | |
| /* We are searching for +load methods that we haven't executed | |
| yet. */ | |
| if (mth->method_name && sel_eq (mth->method_name, load_selector) | |
| && ! objc_hash_is_key_in_hash (__objc_load_methods, mth->method_imp)) | |
| { | |
| /* Add this method into the +load hash table, so we won't | |
| execute it again next time. */ | |
| objc_hash_add (&__objc_load_methods, | |
| mth->method_imp, | |
| mth->method_imp); | |
| /* Call +load. */ | |
| DEBUG_PRINTF (" begin of [%s +load]\n", class->name); | |
| (*mth->method_imp) ((id)class, mth->method_name); | |
| DEBUG_PRINTF (" end of [%s +load]\n", class->name); | |
| break; | |
| } | |
| } | |
| } | |
| /* This function needs to be called with the objc_runtime_mutex | |
| locked. */ | |
| static void | |
| __objc_send_load (objc_class_tree *tree, | |
| int level __attribute__ ((__unused__))) | |
| { | |
| Class class = tree->class; | |
| struct objc_method_list *method_list = class->class_pointer->methods; | |
| DEBUG_PRINTF ("+load: need to send load to class '%s'\n", class->name); | |
| __objc_send_load_using_method_list (method_list, class); | |
| } | |
| 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 class. */ | |
| 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_getClass (statics->class_name); | |
| if (! class) | |
| { | |
| /* It is unfortunate that this will cause all the | |
| statics initialization to be done again (eg, if we | |
| already initialized constant strings, and are now | |
| initializing protocols, setting module_initialized to | |
| 0 would cause constant strings to be initialized | |
| again). It would be good to be able to track if we | |
| have already initialized some of them. */ | |
| module_initialized = 0; | |
| } | |
| else | |
| { | |
| /* Note that if this is a list of Protocol objects, some | |
| of them may have been initialized already (because | |
| they were attached to classes or categories, and the | |
| class/category loading code automatically fixes them | |
| up), and some of them may not. We really need to go | |
| through the whole list to be sure! Protocols are | |
| also special because we want to register them and | |
| register all their selectors. */ | |
| id *inst; | |
| if (strcmp (statics->class_name, "Protocol") == 0) | |
| { | |
| /* Protocols are special, because not only we want | |
| to fix up their class pointers, but we also want | |
| to register them and their selectors with the | |
| runtime. */ | |
| for (inst = &statics->instances[0]; *inst; inst++) | |
| __objc_init_protocol ((struct objc_protocol *)*inst); | |
| } | |
| else | |
| { | |
| /* Other static instances (typically constant | |
| strings) are easier as we just fix up their class | |
| pointers. */ | |
| for (inst = &statics->instances[0]; *inst; inst++) | |
| (*inst)->class_pointer = class; | |
| } | |
| } | |
| } | |
| 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); | |
| } | |
| /* 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 (struct objc_module *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-private/module-abi-8.h) | |
| generated by gcc. */ | |
| struct objc_symtab *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. */ | |
| struct objc_selector *selectors = symtab->refs; | |
| int i; | |
| DEBUG_PRINTF ("\n__objc_exec_class (%p) - start processing module...\n", module); | |
| /* 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 (); | |
| duplicate_classes = objc_hash_new (8, | |
| (hash_func_type)objc_hash_ptr, | |
| objc_compare_ptrs); | |
| __objc_load_methods = objc_hash_new (128, | |
| (hash_func_type)objc_hash_ptr, | |
| objc_compare_ptrs); | |
| __objc_protocols_init (); | |
| __objc_accessors_init (); | |
| __objc_sync_init (); | |
| previous_constructors = 1; | |
| } | |
| /* Save the module pointer so that later we remember to call +load | |
| on all classes and categories on it. */ | |
| objc_mutex_lock (__objc_runtime_mutex); | |
| __objc_module_list = list_cons (module, __objc_module_list); | |
| /* Replace referenced selectors from names to SELs. */ | |
| if (selectors) | |
| { | |
| DEBUG_PRINTF (" registering selectors\n"); | |
| __objc_register_selectors_from_module (selectors); | |
| } | |
| /* Parse the classes in the load module and gather selector | |
| information. */ | |
| 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 (" installing class '%s'\n", class->name); | |
| /* Workaround for a bug in clang: Clang may set flags other than | |
| _CLS_CLASS and _CLS_META even when compiling for the | |
| traditional ABI (version 8), confusing our runtime. Try to | |
| wipe these flags out. */ | |
| if (CLS_ISCLASS (class)) | |
| __CLS_INFO (class) = _CLS_CLASS; | |
| else | |
| __CLS_INFO (class) = _CLS_META; | |
| /* Initialize the subclass list to be NULL. In some cases it | |
| isn't and this crashes the program. */ | |
| class->subclass_list = NULL; | |
| if (__objc_init_class (class)) | |
| { | |
| /* 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_getClass (superclass)) | |
| unresolved_classes = list_cons (class, unresolved_classes); | |
| } | |
| } | |
| /* Process category information from the module. */ | |
| for (i = 0; i < symtab->cat_def_cnt; ++i) | |
| { | |
| struct objc_category *category = symtab->defs[i + symtab->cls_def_cnt]; | |
| Class class = objc_getClass (category->class_name); | |
| /* If the class for the category exists then append its | |
| methods. */ | |
| if (class) | |
| { | |
| DEBUG_PRINTF (" installing category '%s (%s)'\n", category->class_name, category->category_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 | |
| { | |
| DEBUG_PRINTF (" delaying installation of category '%s (%s)'\n", category->class_name, category->category_name); | |
| /* 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; ) | |
| { | |
| struct objc_category *category = (*cell)->head; | |
| Class class = objc_getClass (category->class_name); | |
| if (class) | |
| { | |
| DEBUG_PRINTF (" installing (delayed) category '%s (%s)'\n", category->class_name, category->category_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_getClass ("Protocol")) | |
| { | |
| list_mapcar (unclaimed_proto_list, | |
| (void (*) (void *))__objc_init_protocols); | |
| list_free (unclaimed_proto_list); | |
| unclaimed_proto_list = 0; | |
| } | |
| objc_send_load (); | |
| /* Check if there are no unresolved classes (ie, classes whose | |
| superclass has not been loaded yet) and that the 'Object' class, | |
| used as the class of classes, exist. If so, it is worth | |
| "resolving the class links" at this point, which will setup all | |
| the class/superclass pointers. */ | |
| if (!unresolved_classes && objc_getClass ("Object")) | |
| { | |
| DEBUG_PRINTF (" resolving class links\n"); | |
| __objc_resolve_class_links (); | |
| } | |
| objc_mutex_unlock (__objc_runtime_mutex); | |
| DEBUG_PRINTF ("__objc_exec_class (%p) - finished processing module...\n\n", module); | |
| } | |
| /* This function needs to be called with the objc_runtime_mutex | |
| locked. */ | |
| 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_getClass ((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 (and call the load callback) yet. */ | |
| if (unresolved_classes) | |
| return; | |
| } | |
| /* Special check. If 'Object', which is used by meta-classes, has | |
| not been loaded yet, delay sending of +load. */ | |
| if (! objc_getClass ("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); | |
| } | |
| /* For each module, call the _objc_load_callback if any is | |
| defined. */ | |
| list_mapcar (__objc_module_list, (void (*) (void *)) __objc_call_load_callback); | |
| /* Empty the list of modules. */ | |
| list_free (__objc_module_list); | |
| __objc_module_list = NULL; | |
| } | |
| static void | |
| __objc_create_classes_tree (struct objc_module *module) | |
| { | |
| /* The runtime mutex is locked at this point */ | |
| struct objc_symtab *symtab = module->symtab; | |
| int i; | |
| /* Iterate through 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]; | |
| if (!objc_hash_is_key_in_hash (duplicate_classes, class)) | |
| objc_tree_insert_class (class); | |
| } | |
| /* Now iterate over "claimed" categories too (ie, categories that | |
| extend a class that has already been loaded by the runtime), and | |
| insert them in the classes tree hierarchy too. Otherwise, if you | |
| add a category, its +load method would not be called if the class | |
| is already loaded in the runtime. It the category is | |
| "unclaimed", ie, we haven't loaded the main class yet, postpone | |
| sending +load as we want to execute +load from the class before | |
| we execute the one from the category. */ | |
| for (i = 0; i < symtab->cat_def_cnt; ++i) | |
| { | |
| struct objc_category *category = symtab->defs[i + symtab->cls_def_cnt]; | |
| Class class = objc_getClass (category->class_name); | |
| /* If the class for the category exists then append its | |
| methods. */ | |
| if (class) | |
| objc_tree_insert_class (class); | |
| } | |
| } | |
| static void | |
| __objc_call_load_callback (struct objc_module *module) | |
| { | |
| if (_objc_load_callback) | |
| { | |
| /* The runtime mutex is locked at this point. */ | |
| struct objc_symtab *symtab = module->symtab; | |
| int i; | |
| /* Iterate through 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]; | |
| if (!objc_hash_is_key_in_hash (duplicate_classes, class)) | |
| { | |
| /* Call the _objc_load_callback for this class. */ | |
| DEBUG_PRINTF (" calling the load callback for class '%s'\n", class->name); | |
| _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++) | |
| { | |
| struct objc_category *category = symtab->defs[i + symtab->cls_def_cnt]; | |
| Class class = objc_getClass (category->class_name); | |
| DEBUG_PRINTF (" calling the load callback for category '%s (%s)'\n", | |
| category->class_name, category->category_name); | |
| _objc_load_callback (class, category); | |
| } | |
| } | |
| } | |
| /* Sanity check the version of gcc used to compile `module'. */ | |
| static void | |
| init_check_module_version (struct objc_module *module) | |
| { | |
| if ((module->version != OBJC_VERSION) || (module->size != sizeof (struct objc_module))) | |
| { | |
| _objc_abort ("Module %s version %d doesn't match runtime %d\n", | |
| module->name, (int)module->version, OBJC_VERSION); | |
| } | |
| } | |
| /* __objc_init_class must be called with __objc_runtime_mutex already | |
| locked. Return YES if the class could be setup; return NO if the | |
| class could not be setup because a class with the same name already | |
| exists. */ | |
| BOOL | |
| __objc_init_class (Class class) | |
| { | |
| /* Store the class in the class table and assign class numbers. */ | |
| if (__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); | |
| return YES; | |
| } | |
| else | |
| { | |
| /* The module contains a duplicate class. Remember it so that | |
| we will ignore it later. */ | |
| DEBUG_PRINTF (" duplicate class '%s' - will be ignored\n", class->name); | |
| objc_hash_add (&duplicate_classes, class, class); | |
| return NO; | |
| } | |
| } | |
| /* __objc_init_protocol must be called with __objc_runtime_mutex | |
| already locked, and the "Protocol" class already registered. */ | |
| static void | |
| __objc_init_protocol (struct objc_protocol *protocol) | |
| { | |
| static Class proto_class = 0; | |
| if (! proto_class) | |
| proto_class = objc_getClass ("Protocol"); | |
| if (((size_t)protocol->class_pointer) == PROTOCOL_VERSION) | |
| { | |
| /* Assign class pointer. */ | |
| protocol->class_pointer = proto_class; | |
| /* Register all the selectors in the protocol with the runtime. | |
| This both registers the selectors with the right types, and | |
| it also fixes up the 'struct objc_method' structures inside | |
| the protocol so that each method_name (a char * as compiled | |
| by the compiler) is replaced with the appropriate runtime | |
| SEL. */ | |
| if (protocol->class_methods) | |
| __objc_register_selectors_from_description_list (protocol->class_methods); | |
| if (protocol->instance_methods) | |
| __objc_register_selectors_from_description_list (protocol->instance_methods); | |
| /* Register the protocol in the hashtable or protocols by | |
| name. */ | |
| __objc_protocols_add_protocol (protocol->protocol_name, protocol); | |
| /* Init super protocols. */ | |
| __objc_init_protocols (protocol->protocol_list); | |
| } | |
| else if (protocol->class_pointer != proto_class) | |
| { | |
| _objc_abort ("Version %d doesn't match runtime protocol version %d\n", | |
| (int) ((char *) protocol->class_pointer | |
| - (char *) 0), | |
| PROTOCOL_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_getClass ("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]; | |
| __objc_init_protocol (aProto); | |
| } | |
| objc_mutex_unlock (__objc_runtime_mutex); | |
| } | |
| static void | |
| __objc_class_add_protocols (Class class, struct objc_protocol_list *protos) | |
| { | |
| if (! protos) | |
| return; | |
| protos->next = class->protocols; | |
| class->protocols = protos; | |
| } |