diff --git a/gcc/objc/init.c b/gcc/objc/init.c index b95f38b9fe1..fe64bf43940 100644 --- a/gcc/objc/init.c +++ b/gcc/objc/init.c @@ -27,7 +27,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* The version number of this runtime. This must match the number defined in gcc (objc-act.c) */ -#define OBJC_VERSION 7 +#define OBJC_VERSION 8 #define PROTOCOL_VERSION 2 /* This list contains all modules currently loaded into the runtime */ @@ -67,6 +67,25 @@ extern SEL __sel_register_typed_name (const char *name, const char *types, struct objc_selector *orig, BOOL is_const); +/* Send +load to all classes and categories from a module that implement + this method */ +static void __objc_send_load(Module_t module); + +/* This list contains all the classes in the runtime system for whom their + superclasses are not yet know to the runtime. */ +static struct objc_list* unresolved_classes = 0; + +/* Static function used to references the Object and NXConstantString classes. */ +static void +__objc_force_linking (void) +{ + extern void __objc_linking (void); + __objc_linking (); + + /* Call the function to avoid compiler warning */ + __objc_force_linking (); +} + /* Run through the statics list, removing modules as soon as all its statics have been initialized. */ static void @@ -143,6 +162,10 @@ __objc_exec_class (Module_t module) /* 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; @@ -196,6 +219,7 @@ __objc_exec_class (Module_t module) 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)); @@ -216,8 +240,10 @@ __objc_exec_class (Module_t module) if (class->protocols) __objc_init_protocols (class->protocols); - if (_objc_load_callback) - _objc_load_callback(class, 0); + /* 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. */ @@ -260,8 +286,8 @@ __objc_exec_class (Module_t module) } } - if (module->statics) - uninitialized_statics = list_cons (module->statics, uninitialized_statics); + if (statics) + uninitialized_statics = list_cons (statics, uninitialized_statics); if (uninitialized_statics) objc_init_statics (); @@ -306,9 +332,118 @@ __objc_exec_class (Module_t module) unclaimed_proto_list = 0; } + objc_send_load (); + objc_mutex_unlock(__objc_runtime_mutex); } +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 which 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 sending messages to constant strings in +load + methods. If the class is not yet known, even if all the classes are known, + delay sending of +load. */ + if (!objc_lookup_class ("NXConstantString")) + return; + + /* Iterate over all modules in the __objc_module_list and call on them the + __objc_send_load function that sends the +load message. */ + list_mapcar (__objc_module_list, (void(*)(void*))__objc_send_load); + list_free (__objc_module_list); + __objc_module_list = NULL; +} + +static void +__objc_send_message_in_list (MethodList_t method_list, id object, SEL op) +{ + while (method_list) + { + int i; + + /* 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)) + { + /* The method was found. */ + (*mth->method_imp) (object, mth->method_name); + break; + } + } + method_list = method_list->method_next; + } +} + +static void +__objc_send_load(Module_t module) +{ + /* The runtime mutex is locked in this point */ + + Symtab_t symtab = module->symtab; + static SEL load_sel = 0; + int i; + + if (!load_sel) + load_sel = sel_register_name ("load"); + + /* Iterate thru classes defined in this module and send them the +load + message if they implement it. At this point all methods defined in + categories were added to the corresponding class, so all the +load + methods of categories are in their corresponding classes. */ + for (i = 0; i < symtab->cls_def_cnt; i++) + { + Class class = (Class) symtab->defs[i]; + MethodList_t method_list = class->class_pointer->methods; + + __objc_send_message_in_list (method_list, (id)class, load_sel); + + /* 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) {