]>
Commit | Line | Data |
---|---|---|
88e17b57 | 1 | /* GNU Objective C Runtime initialization |
748086b7 JJ |
2 | Copyright (C) 1993, 1995, 1996, 1997, 2002, 2009 |
3 | Free Software Foundation, Inc. | |
88e17b57 BE |
4 | Contributed by Kresten Krab Thorup |
5 | +load support contributed by Ovidiu Predescu <ovidiu@net-community.com> | |
6 | ||
38709cad | 7 | This file is part of GCC. |
88e17b57 | 8 | |
38709cad | 9 | GCC is free software; you can redistribute it and/or modify it under the |
88e17b57 | 10 | terms of the GNU General Public License as published by the Free Software |
748086b7 | 11 | Foundation; either version 3, or (at your option) any later version. |
88e17b57 | 12 | |
38709cad | 13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
88e17b57 BE |
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
15 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |
16 | details. | |
17 | ||
748086b7 JJ |
18 | Under Section 7 of GPL version 3, you are granted additional |
19 | permissions described in the GCC Runtime Library Exception, version | |
20 | 3.1, as published by the Free Software Foundation. | |
88e17b57 | 21 | |
748086b7 JJ |
22 | You should have received a copy of the GNU General Public License and |
23 | a copy of the GCC Runtime Library Exception along with this program; | |
24 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
25 | <http://www.gnu.org/licenses/>. */ | |
88e17b57 | 26 | |
348a3445 | 27 | #include "objc/runtime.h" |
88e17b57 BE |
28 | |
29 | /* The version number of this runtime. This must match the number | |
40165636 | 30 | defined in gcc (objc-act.c). */ |
88e17b57 BE |
31 | #define OBJC_VERSION 8 |
32 | #define PROTOCOL_VERSION 2 | |
33 | ||
40165636 RB |
34 | /* This list contains all modules currently loaded into the runtime. */ |
35 | static struct objc_list *__objc_module_list = 0; /* !T:MUTEX */ | |
88e17b57 | 36 | |
40165636 RB |
37 | /* This list contains all proto_list's not yet assigned class links. */ |
38 | static struct objc_list *unclaimed_proto_list = 0; /* !T:MUTEX */ | |
88e17b57 BE |
39 | |
40 | /* List of unresolved static instances. */ | |
41 | static struct objc_list *uninitialized_statics = 0; /* !T:MUTEX */ | |
42 | ||
40165636 | 43 | /* Global runtime "write" mutex. */ |
88e17b57 BE |
44 | objc_mutex_t __objc_runtime_mutex = 0; |
45 | ||
40165636 | 46 | /* Number of threads that are alive. */ |
88e17b57 BE |
47 | int __objc_runtime_threads_alive = 1; /* !T:MUTEX */ |
48 | ||
40165636 | 49 | /* Check compiler vs runtime version. */ |
88e17b57 BE |
50 | static void init_check_module_version (Module_t); |
51 | ||
40165636 RB |
52 | /* Assign isa links to protos. */ |
53 | static void __objc_init_protocols (struct objc_protocol_list *protos); | |
88e17b57 | 54 | |
40165636 RB |
55 | /* Add protocol to class. */ |
56 | static void __objc_class_add_protocols (Class, struct objc_protocol_list *); | |
88e17b57 | 57 | |
40165636 RB |
58 | /* This is a hook which is called by __objc_exec_class every time a |
59 | class or a category is loaded into the runtime. This may e.g. help | |
60 | a dynamic loader determine the classes that have been loaded when | |
61 | an object file is dynamically linked in. */ | |
62 | void (*_objc_load_callback) (Class class, Category *category); /* !T:SAFE */ | |
88e17b57 | 63 | |
40165636 | 64 | /* Is all categories/classes resolved? */ |
88e17b57 BE |
65 | BOOL __objc_dangling_categories = NO; /* !T:UNUSED */ |
66 | ||
67 | extern SEL | |
68 | __sel_register_typed_name (const char *name, const char *types, | |
69 | struct objc_selector *orig, BOOL is_const); | |
70 | ||
40165636 | 71 | /* Sends +load to all classes and categories in certain situations. */ |
88e17b57 BE |
72 | static void objc_send_load (void); |
73 | ||
74 | /* Inserts all the classes defined in module in a tree of classes that | |
40165636 RB |
75 | resembles the class hierarchy. This tree is traversed in preorder |
76 | and the classes in its nodes receive the +load message if these | |
77 | methods were not executed before. The algorithm ensures that when | |
78 | the +load method of a class is executed all the superclasses have | |
79 | been already received the +load message. */ | |
88e17b57 BE |
80 | static void __objc_create_classes_tree (Module_t module); |
81 | ||
82 | static void __objc_call_callback (Module_t module); | |
83 | ||
84 | /* A special version that works only before the classes are completely | |
40165636 | 85 | installed in the runtime. */ |
88e17b57 BE |
86 | static BOOL class_is_subclass_of_class (Class class, Class superclass); |
87 | ||
88 | typedef struct objc_class_tree { | |
89 | Class class; | |
90 | struct objc_list *subclasses; /* `head' is pointer to an objc_class_tree */ | |
91 | } objc_class_tree; | |
92 | ||
40165636 RB |
93 | /* This is a linked list of objc_class_tree trees. The head of these |
94 | trees are root classes (their super class is Nil). These different | |
95 | trees represent different class hierarchies. */ | |
88e17b57 BE |
96 | static struct objc_list *__objc_class_tree_list = NULL; |
97 | ||
40165636 RB |
98 | /* Keeps the +load methods who have been already executed. This hash |
99 | should not be destroyed during the execution of the program. */ | |
88e17b57 BE |
100 | static cache_ptr __objc_load_methods = NULL; |
101 | ||
e083f3f9 RFM |
102 | /* This function is used when building the class tree used to send |
103 | ordinately the +load message to all classes needing it. The tree | |
104 | is really needed so that superclasses will get the message before | |
105 | subclasses. | |
106 | ||
107 | This tree will contain classes which are being loaded (or have just | |
108 | being loaded), and whose super_class pointers have not yet been | |
109 | resolved. This implies that their super_class pointers point to a | |
110 | string with the name of the superclass; when the first message is | |
111 | sent to the class (/an object of that class) the class links will | |
112 | be resolved, which will replace the super_class pointers with | |
113 | pointers to the actual superclasses. | |
114 | ||
115 | Unfortunately, the tree might also contain classes which had been | |
116 | loaded previously, and whose class links have already been | |
117 | resolved. | |
118 | ||
119 | This function returns the superclass of a class in both cases, and | |
120 | can be used to build the determine the class relationships while | |
121 | building the tree. | |
122 | */ | |
123 | static Class class_superclass_of_class (Class class) | |
124 | { | |
125 | char *super_class_name; | |
126 | ||
127 | /* If the class links have been resolved, use the resolved | |
128 | * links. */ | |
129 | if (CLS_ISRESOLV (class)) | |
130 | return class->super_class; | |
131 | ||
132 | /* Else, 'class' has not yet been resolved. This means that its | |
133 | * super_class pointer is really the name of the super class (rather | |
134 | * than a pointer to the actual superclass). */ | |
135 | super_class_name = (char *)class->super_class; | |
136 | ||
137 | /* Return Nil for a root class. */ | |
138 | if (super_class_name == NULL) | |
139 | return Nil; | |
140 | ||
141 | /* Lookup the superclass of non-root classes. */ | |
142 | return objc_lookup_class (super_class_name); | |
143 | } | |
144 | ||
145 | ||
40165636 RB |
146 | /* Creates a tree of classes whose topmost class is directly inherited |
147 | from `upper' and the bottom class in this tree is | |
148 | `bottom_class'. The classes in this tree are super classes of | |
149 | `bottom_class'. `subclasses' member of each tree node point to the | |
150 | next subclass tree node. */ | |
151 | ||
88e17b57 BE |
152 | static objc_class_tree * |
153 | create_tree_of_subclasses_inherited_from (Class bottom_class, Class upper) | |
154 | { | |
155 | Class superclass = bottom_class->super_class ? | |
40165636 | 156 | objc_lookup_class ((char *) bottom_class->super_class) |
88e17b57 BE |
157 | : Nil; |
158 | ||
159 | objc_class_tree *tree, *prev; | |
160 | ||
161 | DEBUG_PRINTF ("create_tree_of_subclasses_inherited_from:"); | |
162 | DEBUG_PRINTF ("bottom_class = %s, upper = %s\n", | |
163 | (bottom_class ? bottom_class->name : NULL), | |
164 | (upper ? upper->name : NULL)); | |
165 | ||
166 | tree = prev = objc_calloc (1, sizeof (objc_class_tree)); | |
167 | prev->class = bottom_class; | |
168 | ||
169 | while (superclass != upper) | |
170 | { | |
171 | tree = objc_calloc (1, sizeof (objc_class_tree)); | |
172 | tree->class = superclass; | |
173 | tree->subclasses = list_cons (prev, tree->subclasses); | |
e083f3f9 | 174 | superclass = class_superclass_of_class (superclass); |
88e17b57 BE |
175 | prev = tree; |
176 | } | |
177 | ||
178 | return tree; | |
179 | } | |
180 | ||
40165636 RB |
181 | /* Insert the `class' into the proper place in the `tree' class |
182 | hierarchy. This function returns a new tree if the class has been | |
183 | successfully inserted into the tree or NULL if the class is not | |
184 | part of the classes hierarchy described by `tree'. This function is | |
185 | private to objc_tree_insert_class (), you should not call it | |
186 | directly. */ | |
187 | ||
88e17b57 BE |
188 | static objc_class_tree * |
189 | __objc_tree_insert_class (objc_class_tree *tree, Class class) | |
190 | { | |
191 | DEBUG_PRINTF ("__objc_tree_insert_class: tree = %x, class = %s\n", | |
192 | tree, class->name); | |
193 | ||
194 | if (tree == NULL) | |
195 | return create_tree_of_subclasses_inherited_from (class, NULL); | |
196 | else if (class == tree->class) | |
197 | { | |
198 | /* `class' has been already inserted */ | |
199 | DEBUG_PRINTF ("1. class %s was previously inserted\n", class->name); | |
200 | return tree; | |
201 | } | |
e083f3f9 | 202 | else if (class_superclass_of_class (class) == tree->class) |
88e17b57 BE |
203 | { |
204 | /* If class is a direct subclass of tree->class then add class to the | |
205 | list of subclasses. First check to see if it wasn't already | |
40165636 | 206 | inserted. */ |
88e17b57 BE |
207 | struct objc_list *list = tree->subclasses; |
208 | objc_class_tree *node; | |
209 | ||
210 | while (list) | |
211 | { | |
212 | /* Class has been already inserted; do nothing just return | |
40165636 RB |
213 | the tree. */ |
214 | if (((objc_class_tree *) list->head)->class == class) | |
88e17b57 BE |
215 | { |
216 | DEBUG_PRINTF ("2. class %s was previously inserted\n", | |
217 | class->name); | |
218 | return tree; | |
219 | } | |
220 | list = list->tail; | |
221 | } | |
222 | ||
223 | /* Create a new node class and insert it into the list of subclasses */ | |
224 | node = objc_calloc (1, sizeof (objc_class_tree)); | |
225 | node->class = class; | |
226 | tree->subclasses = list_cons (node, tree->subclasses); | |
227 | DEBUG_PRINTF ("3. class %s inserted\n", class->name); | |
228 | return tree; | |
229 | } | |
230 | else | |
231 | { | |
40165636 RB |
232 | /* The class is not a direct subclass of tree->class. Search for |
233 | class's superclasses in the list of subclasses. */ | |
88e17b57 BE |
234 | struct objc_list *subclasses = tree->subclasses; |
235 | ||
40165636 RB |
236 | /* Precondition: the class must be a subclass of tree->class; |
237 | otherwise return NULL to indicate our caller that it must | |
238 | take the next tree. */ | |
239 | if (! class_is_subclass_of_class (class, tree->class)) | |
88e17b57 BE |
240 | return NULL; |
241 | ||
242 | for (; subclasses != NULL; subclasses = subclasses->tail) | |
243 | { | |
40165636 | 244 | Class aClass = ((objc_class_tree *) (subclasses->head))->class; |
88e17b57 BE |
245 | |
246 | if (class_is_subclass_of_class (class, aClass)) | |
247 | { | |
40165636 RB |
248 | /* If we found one of class's superclasses we insert the |
249 | class into its subtree and return the original tree | |
250 | since nothing has been changed. */ | |
88e17b57 BE |
251 | subclasses->head |
252 | = __objc_tree_insert_class (subclasses->head, class); | |
253 | DEBUG_PRINTF ("4. class %s inserted\n", class->name); | |
254 | return tree; | |
255 | } | |
256 | } | |
257 | ||
40165636 RB |
258 | /* We haven't found a subclass of `class' in the `subclasses' |
259 | list. Create a new tree of classes whose topmost class is a | |
260 | direct subclass of tree->class. */ | |
88e17b57 BE |
261 | { |
262 | objc_class_tree *new_tree | |
40165636 | 263 | = create_tree_of_subclasses_inherited_from (class, tree->class); |
88e17b57 BE |
264 | tree->subclasses = list_cons (new_tree, tree->subclasses); |
265 | DEBUG_PRINTF ("5. class %s inserted\n", class->name); | |
266 | return tree; | |
267 | } | |
268 | } | |
269 | } | |
270 | ||
40165636 RB |
271 | /* This function inserts `class' in the right tree hierarchy classes. */ |
272 | ||
88e17b57 BE |
273 | static void |
274 | objc_tree_insert_class (Class class) | |
275 | { | |
276 | struct objc_list *list_node; | |
277 | objc_class_tree *tree; | |
278 | ||
279 | list_node = __objc_class_tree_list; | |
280 | while (list_node) | |
281 | { | |
282 | tree = __objc_tree_insert_class (list_node->head, class); | |
283 | if (tree) | |
284 | { | |
285 | list_node->head = tree; | |
286 | break; | |
287 | } | |
288 | else | |
289 | list_node = list_node->tail; | |
290 | } | |
291 | ||
40165636 RB |
292 | /* If the list was finished but the class hasn't been inserted, |
293 | insert it here. */ | |
294 | if (! list_node) | |
88e17b57 BE |
295 | { |
296 | __objc_class_tree_list = list_cons (NULL, __objc_class_tree_list); | |
297 | __objc_class_tree_list->head = __objc_tree_insert_class (NULL, class); | |
298 | } | |
299 | } | |
300 | ||
40165636 RB |
301 | /* Traverse tree in preorder. Used to send +load. */ |
302 | ||
88e17b57 BE |
303 | static void |
304 | objc_preorder_traverse (objc_class_tree *tree, | |
305 | int level, | |
40165636 | 306 | void (*function) (objc_class_tree *, int)) |
88e17b57 BE |
307 | { |
308 | struct objc_list *node; | |
309 | ||
310 | (*function) (tree, level); | |
311 | for (node = tree->subclasses; node; node = node->tail) | |
312 | objc_preorder_traverse (node->head, level + 1, function); | |
313 | } | |
314 | ||
40165636 RB |
315 | /* Traverse tree in postorder. Used to destroy a tree. */ |
316 | ||
88e17b57 BE |
317 | static void |
318 | objc_postorder_traverse (objc_class_tree *tree, | |
40165636 RB |
319 | int level, |
320 | void (*function) (objc_class_tree *, int)) | |
88e17b57 BE |
321 | { |
322 | struct objc_list *node; | |
323 | ||
324 | for (node = tree->subclasses; node; node = node->tail) | |
325 | objc_postorder_traverse (node->head, level + 1, function); | |
326 | (*function) (tree, level); | |
327 | } | |
328 | ||
40165636 RB |
329 | /* Used to print a tree class hierarchy. */ |
330 | ||
88e17b57 BE |
331 | #ifdef DEBUG |
332 | static void | |
333 | __objc_tree_print (objc_class_tree *tree, int level) | |
334 | { | |
335 | int i; | |
336 | ||
337 | for (i = 0; i < level; i++) | |
338 | printf (" "); | |
339 | printf ("%s\n", tree->class->name); | |
340 | } | |
341 | #endif | |
342 | ||
40165636 RB |
343 | /* Walks on a linked list of methods in the reverse order and executes |
344 | all the methods corresponding to `op' selector. Walking in the | |
345 | reverse order assures the +load of class is executed first and then | |
346 | +load of categories because of the way in which categories are | |
347 | added to the class methods. */ | |
348 | ||
88e17b57 BE |
349 | static void |
350 | __objc_send_message_in_list (MethodList_t method_list, Class class, SEL op) | |
351 | { | |
352 | int i; | |
353 | ||
40165636 | 354 | if (! method_list) |
88e17b57 BE |
355 | return; |
356 | ||
357 | /* First execute the `op' message in the following method lists */ | |
358 | __objc_send_message_in_list (method_list->method_next, class, op); | |
359 | ||
40165636 | 360 | /* Search the method list. */ |
88e17b57 BE |
361 | for (i = 0; i < method_list->method_count; i++) |
362 | { | |
363 | Method_t mth = &method_list->method_list[i]; | |
364 | ||
365 | if (mth->method_name && sel_eq (mth->method_name, op) | |
270a1283 | 366 | && ! objc_hash_is_key_in_hash (__objc_load_methods, mth->method_imp)) |
88e17b57 | 367 | { |
88e17b57 | 368 | /* Add this method into the +load hash table */ |
270a1283 DA |
369 | objc_hash_add (&__objc_load_methods, |
370 | mth->method_imp, | |
371 | mth->method_imp); | |
88e17b57 BE |
372 | |
373 | DEBUG_PRINTF ("sending +load in class: %s\n", class->name); | |
374 | ||
40165636 | 375 | /* The method was found and wasn't previously executed. */ |
e6be21fe RFM |
376 | (*mth->method_imp) ((id)class, mth->method_name); |
377 | ||
88e17b57 BE |
378 | break; |
379 | } | |
380 | } | |
381 | } | |
382 | ||
383 | static void | |
8f8c44cb KG |
384 | __objc_send_load (objc_class_tree *tree, |
385 | int level __attribute__ ((__unused__))) | |
88e17b57 BE |
386 | { |
387 | static SEL load_sel = 0; | |
388 | Class class = tree->class; | |
389 | MethodList_t method_list = class->class_pointer->methods; | |
390 | ||
40165636 | 391 | if (! load_sel) |
88e17b57 BE |
392 | load_sel = sel_register_name ("load"); |
393 | ||
394 | __objc_send_message_in_list (method_list, class, load_sel); | |
395 | } | |
396 | ||
397 | static void | |
8f8c44cb KG |
398 | __objc_destroy_class_tree_node (objc_class_tree *tree, |
399 | int level __attribute__ ((__unused__))) | |
88e17b57 BE |
400 | { |
401 | objc_free (tree); | |
402 | } | |
403 | ||
40165636 RB |
404 | /* This is used to check if the relationship between two classes |
405 | before the runtime completely installs the classes. */ | |
406 | ||
88e17b57 BE |
407 | static BOOL |
408 | class_is_subclass_of_class (Class class, Class superclass) | |
409 | { | |
410 | for (; class != Nil;) | |
411 | { | |
412 | if (class == superclass) | |
413 | return YES; | |
e083f3f9 | 414 | class = class_superclass_of_class (class); |
88e17b57 BE |
415 | } |
416 | ||
417 | return NO; | |
418 | } | |
419 | ||
40165636 RB |
420 | /* This list contains all the classes in the runtime system for whom |
421 | their superclasses are not yet known to the runtime. */ | |
422 | static struct objc_list *unresolved_classes = 0; | |
88e17b57 | 423 | |
40165636 RB |
424 | /* Extern function used to reference the Object and NXConstantString |
425 | classes. */ | |
6000b42b JDA |
426 | |
427 | extern void __objc_force_linking (void); | |
428 | ||
429 | void | |
88e17b57 BE |
430 | __objc_force_linking (void) |
431 | { | |
432 | extern void __objc_linking (void); | |
433 | __objc_linking (); | |
88e17b57 BE |
434 | } |
435 | ||
40165636 RB |
436 | /* Run through the statics list, removing modules as soon as all its |
437 | statics have been initialized. */ | |
438 | ||
88e17b57 BE |
439 | static void |
440 | objc_init_statics (void) | |
441 | { | |
442 | struct objc_list **cell = &uninitialized_statics; | |
443 | struct objc_static_instances **statics_in_module; | |
444 | ||
40165636 | 445 | objc_mutex_lock (__objc_runtime_mutex); |
88e17b57 BE |
446 | |
447 | while (*cell) | |
448 | { | |
449 | int module_initialized = 1; | |
450 | ||
451 | for (statics_in_module = (*cell)->head; | |
452 | *statics_in_module; statics_in_module++) | |
453 | { | |
454 | struct objc_static_instances *statics = *statics_in_module; | |
455 | Class class = objc_lookup_class (statics->class_name); | |
456 | ||
40165636 | 457 | if (! class) |
88e17b57 BE |
458 | module_initialized = 0; |
459 | /* Actually, the static's class_pointer will be NULL when we | |
460 | haven't been here before. However, the comparison is to be | |
461 | reminded of taking into account class posing and to think about | |
462 | possible semantics... */ | |
463 | else if (class != statics->instances[0]->class_pointer) | |
464 | { | |
465 | id *inst; | |
466 | ||
467 | for (inst = &statics->instances[0]; *inst; inst++) | |
468 | { | |
469 | (*inst)->class_pointer = class; | |
470 | ||
471 | /* ??? Make sure the object will not be freed. With | |
472 | refcounting, invoke `-retain'. Without refcounting, do | |
473 | nothing and hope that `-free' will never be invoked. */ | |
474 | ||
475 | /* ??? Send the object an `-initStatic' or something to | |
476 | that effect now or later on? What are the semantics of | |
477 | statically allocated instances, besides the trivial | |
478 | NXConstantString, anyway? */ | |
479 | } | |
480 | } | |
481 | } | |
482 | if (module_initialized) | |
483 | { | |
484 | /* Remove this module from the uninitialized list. */ | |
485 | struct objc_list *this = *cell; | |
486 | *cell = this->tail; | |
40165636 | 487 | objc_free (this); |
88e17b57 BE |
488 | } |
489 | else | |
490 | cell = &(*cell)->tail; | |
491 | } | |
492 | ||
40165636 | 493 | objc_mutex_unlock (__objc_runtime_mutex); |
88e17b57 BE |
494 | } /* objc_init_statics */ |
495 | ||
496 | /* This function is called by constructor functions generated for each | |
40165636 RB |
497 | module compiled. (_GLOBAL_$I$...) The purpose of this function is |
498 | to gather the module pointers so that they may be processed by the | |
499 | initialization routines as soon as possible. */ | |
88e17b57 BE |
500 | |
501 | void | |
502 | __objc_exec_class (Module_t module) | |
503 | { | |
504 | /* Have we processed any constructors previously? This flag is used to | |
505 | indicate that some global data structures need to be built. */ | |
506 | static BOOL previous_constructors = 0; | |
507 | ||
40165636 | 508 | static struct objc_list *unclaimed_categories = 0; |
88e17b57 BE |
509 | |
510 | /* The symbol table (defined in objc-api.h) generated by gcc */ | |
511 | Symtab_t symtab = module->symtab; | |
512 | ||
513 | /* The statics in this module */ | |
514 | struct objc_static_instances **statics | |
515 | = symtab->defs[symtab->cls_def_cnt + symtab->cat_def_cnt]; | |
516 | ||
517 | /* Entry used to traverse hash lists */ | |
40165636 | 518 | struct objc_list **cell; |
88e17b57 BE |
519 | |
520 | /* The table of selector references for this module */ | |
521 | SEL selectors = symtab->refs; | |
522 | ||
523 | /* dummy counter */ | |
524 | int i; | |
525 | ||
526 | DEBUG_PRINTF ("received module: %s\n", module->name); | |
527 | ||
528 | /* check gcc version */ | |
40165636 | 529 | init_check_module_version (module); |
88e17b57 BE |
530 | |
531 | /* On the first call of this routine, initialize some data structures. */ | |
40165636 | 532 | if (! previous_constructors) |
88e17b57 BE |
533 | { |
534 | /* Initialize thread-safe system */ | |
40165636 | 535 | __objc_init_thread_system (); |
88e17b57 | 536 | __objc_runtime_threads_alive = 1; |
40165636 | 537 | __objc_runtime_mutex = objc_mutex_allocate (); |
88e17b57 | 538 | |
40165636 RB |
539 | __objc_init_selector_tables (); |
540 | __objc_init_class_tables (); | |
541 | __objc_init_dispatch_tables (); | |
88e17b57 | 542 | __objc_class_tree_list = list_cons (NULL, __objc_class_tree_list); |
270a1283 DA |
543 | __objc_load_methods = objc_hash_new (128, |
544 | (hash_func_type)objc_hash_ptr, | |
545 | objc_compare_ptrs); | |
88e17b57 BE |
546 | previous_constructors = 1; |
547 | } | |
548 | ||
549 | /* Save the module pointer for later processing. (not currently used) */ | |
40165636 RB |
550 | objc_mutex_lock (__objc_runtime_mutex); |
551 | __objc_module_list = list_cons (module, __objc_module_list); | |
88e17b57 BE |
552 | |
553 | /* Replace referenced selectors from names to SEL's. */ | |
554 | if (selectors) | |
555 | { | |
556 | for (i = 0; selectors[i].sel_id; ++i) | |
557 | { | |
558 | const char *name, *type; | |
40165636 RB |
559 | name = (char *) selectors[i].sel_id; |
560 | type = (char *) selectors[i].sel_types; | |
88e17b57 BE |
561 | /* Constructors are constant static data so we can safely store |
562 | pointers to them in the runtime structures. is_const == YES */ | |
563 | __sel_register_typed_name (name, type, | |
40165636 | 564 | (struct objc_selector *) &(selectors[i]), |
88e17b57 BE |
565 | YES); |
566 | } | |
567 | } | |
568 | ||
569 | /* Parse the classes in the load module and gather selector information. */ | |
570 | DEBUG_PRINTF ("gathering selectors from module: %s\n", module->name); | |
571 | for (i = 0; i < symtab->cls_def_cnt; ++i) | |
572 | { | |
573 | Class class = (Class) symtab->defs[i]; | |
40165636 | 574 | const char *superclass = (char *) class->super_class; |
88e17b57 BE |
575 | |
576 | /* Make sure we have what we think. */ | |
40165636 RB |
577 | assert (CLS_ISCLASS (class)); |
578 | assert (CLS_ISMETA (class->class_pointer)); | |
88e17b57 BE |
579 | DEBUG_PRINTF ("phase 1, processing class: %s\n", class->name); |
580 | ||
581 | /* Initialize the subclass list to be NULL. | |
40165636 | 582 | In some cases it isn't and this crashes the program. */ |
88e17b57 BE |
583 | class->subclass_list = NULL; |
584 | ||
585 | /* Store the class in the class table and assign class numbers. */ | |
586 | __objc_add_class_to_hash (class); | |
587 | ||
588 | /* Register all of the selectors in the class and meta class. */ | |
589 | __objc_register_selectors_from_class (class); | |
590 | __objc_register_selectors_from_class ((Class) class->class_pointer); | |
591 | ||
592 | /* Install the fake dispatch tables */ | |
40165636 RB |
593 | __objc_install_premature_dtable (class); |
594 | __objc_install_premature_dtable (class->class_pointer); | |
88e17b57 BE |
595 | |
596 | /* Register the instance methods as class methods, this is | |
40165636 RB |
597 | only done for root classes. */ |
598 | __objc_register_instance_methods_to_class (class); | |
88e17b57 BE |
599 | |
600 | if (class->protocols) | |
601 | __objc_init_protocols (class->protocols); | |
602 | ||
603 | /* Check to see if the superclass is known in this point. If it's not | |
40165636 RB |
604 | add the class to the unresolved_classes list. */ |
605 | if (superclass && ! objc_lookup_class (superclass)) | |
88e17b57 BE |
606 | unresolved_classes = list_cons (class, unresolved_classes); |
607 | } | |
608 | ||
609 | /* Process category information from the module. */ | |
610 | for (i = 0; i < symtab->cat_def_cnt; ++i) | |
611 | { | |
612 | Category_t category = symtab->defs[i + symtab->cls_def_cnt]; | |
613 | Class class = objc_lookup_class (category->class_name); | |
614 | ||
615 | /* If the class for the category exists then append its methods. */ | |
616 | if (class) | |
617 | { | |
618 | ||
619 | DEBUG_PRINTF ("processing categories from (module,object): %s, %s\n", | |
620 | module->name, | |
621 | class->name); | |
622 | ||
623 | /* Do instance methods. */ | |
624 | if (category->instance_methods) | |
625 | class_add_method_list (class, category->instance_methods); | |
626 | ||
627 | /* Do class methods. */ | |
628 | if (category->class_methods) | |
629 | class_add_method_list ((Class) class->class_pointer, | |
630 | category->class_methods); | |
631 | ||
632 | if (category->protocols) | |
633 | { | |
634 | __objc_init_protocols (category->protocols); | |
635 | __objc_class_add_protocols (class, category->protocols); | |
636 | } | |
637 | ||
638 | /* Register the instance methods as class methods, this is | |
40165636 RB |
639 | only done for root classes. */ |
640 | __objc_register_instance_methods_to_class (class); | |
88e17b57 BE |
641 | } |
642 | else | |
643 | { | |
644 | /* The object to which the category methods belong can't be found. | |
645 | Save the information. */ | |
40165636 | 646 | unclaimed_categories = list_cons (category, unclaimed_categories); |
88e17b57 BE |
647 | } |
648 | } | |
649 | ||
650 | if (statics) | |
651 | uninitialized_statics = list_cons (statics, uninitialized_statics); | |
652 | if (uninitialized_statics) | |
653 | objc_init_statics (); | |
654 | ||
655 | /* Scan the unclaimed category hash. Attempt to attach any unclaimed | |
656 | categories to objects. */ | |
e5e0f6f5 | 657 | for (cell = &unclaimed_categories; *cell; ) |
88e17b57 BE |
658 | { |
659 | Category_t category = (*cell)->head; | |
660 | Class class = objc_lookup_class (category->class_name); | |
661 | ||
662 | if (class) | |
663 | { | |
664 | DEBUG_PRINTF ("attaching stored categories to object: %s\n", | |
665 | class->name); | |
666 | ||
667 | list_remove_head (cell); | |
668 | ||
669 | if (category->instance_methods) | |
670 | class_add_method_list (class, category->instance_methods); | |
671 | ||
672 | if (category->class_methods) | |
673 | class_add_method_list ((Class) class->class_pointer, | |
674 | category->class_methods); | |
675 | ||
676 | if (category->protocols) | |
677 | { | |
678 | __objc_init_protocols (category->protocols); | |
679 | __objc_class_add_protocols (class, category->protocols); | |
680 | } | |
681 | ||
682 | /* Register the instance methods as class methods, this is | |
40165636 RB |
683 | only done for root classes. */ |
684 | __objc_register_instance_methods_to_class (class); | |
88e17b57 | 685 | } |
e5e0f6f5 NP |
686 | else |
687 | cell = &(*cell)->tail; | |
88e17b57 BE |
688 | } |
689 | ||
690 | if (unclaimed_proto_list && objc_lookup_class ("Protocol")) | |
691 | { | |
40165636 RB |
692 | list_mapcar (unclaimed_proto_list, |
693 | (void (*) (void *))__objc_init_protocols); | |
88e17b57 BE |
694 | list_free (unclaimed_proto_list); |
695 | unclaimed_proto_list = 0; | |
696 | } | |
697 | ||
698 | objc_send_load (); | |
699 | ||
40165636 | 700 | objc_mutex_unlock (__objc_runtime_mutex); |
88e17b57 BE |
701 | } |
702 | ||
40165636 RB |
703 | static void |
704 | objc_send_load (void) | |
88e17b57 | 705 | { |
40165636 | 706 | if (! __objc_module_list) |
88e17b57 BE |
707 | return; |
708 | ||
709 | /* Try to find out if all the classes loaded so far also have their | |
40165636 RB |
710 | superclasses known to the runtime. We suppose that the objects |
711 | that are allocated in the +load method are in general of a class | |
712 | declared in the same module. */ | |
88e17b57 BE |
713 | if (unresolved_classes) |
714 | { | |
715 | Class class = unresolved_classes->head; | |
716 | ||
40165636 | 717 | while (objc_lookup_class ((char *) class->super_class)) |
88e17b57 BE |
718 | { |
719 | list_remove_head (&unresolved_classes); | |
720 | if (unresolved_classes) | |
721 | class = unresolved_classes->head; | |
722 | else | |
723 | break; | |
724 | } | |
725 | ||
40165636 RB |
726 | /* If we still have classes for whom we don't have yet their |
727 | super classes known to the runtime we don't send the +load | |
728 | messages. */ | |
88e17b57 BE |
729 | if (unresolved_classes) |
730 | return; | |
731 | } | |
732 | ||
40165636 RB |
733 | /* Special check to allow creating and sending messages to constant |
734 | strings in +load methods. If these classes are not yet known, | |
735 | even if all the other classes are known, delay sending of +load. */ | |
736 | if (! objc_lookup_class ("NXConstantString") || | |
737 | ! objc_lookup_class ("Object")) | |
88e17b57 BE |
738 | return; |
739 | ||
40165636 RB |
740 | /* Iterate over all modules in the __objc_module_list and call on |
741 | them the __objc_create_classes_tree function. This function | |
742 | creates a tree of classes that resembles the class hierarchy. */ | |
743 | list_mapcar (__objc_module_list, | |
744 | (void (*) (void *)) __objc_create_classes_tree); | |
88e17b57 BE |
745 | |
746 | while (__objc_class_tree_list) | |
747 | { | |
748 | #ifdef DEBUG | |
749 | objc_preorder_traverse (__objc_class_tree_list->head, | |
750 | 0, __objc_tree_print); | |
751 | #endif | |
752 | objc_preorder_traverse (__objc_class_tree_list->head, | |
753 | 0, __objc_send_load); | |
754 | objc_postorder_traverse (__objc_class_tree_list->head, | |
755 | 0, __objc_destroy_class_tree_node); | |
756 | list_remove_head (&__objc_class_tree_list); | |
757 | } | |
758 | ||
40165636 | 759 | list_mapcar (__objc_module_list, (void (*) (void *)) __objc_call_callback); |
88e17b57 BE |
760 | list_free (__objc_module_list); |
761 | __objc_module_list = NULL; | |
762 | } | |
763 | ||
764 | static void | |
765 | __objc_create_classes_tree (Module_t module) | |
766 | { | |
767 | /* The runtime mutex is locked in this point */ | |
768 | ||
769 | Symtab_t symtab = module->symtab; | |
770 | int i; | |
771 | ||
40165636 RB |
772 | /* Iterate thru classes defined in this module and insert them in |
773 | the classes tree hierarchy. */ | |
88e17b57 BE |
774 | for (i = 0; i < symtab->cls_def_cnt; i++) |
775 | { | |
776 | Class class = (Class) symtab->defs[i]; | |
777 | ||
778 | objc_tree_insert_class (class); | |
779 | } | |
780 | } | |
781 | ||
782 | static void | |
783 | __objc_call_callback (Module_t module) | |
784 | { | |
40165636 | 785 | /* The runtime mutex is locked in this point. */ |
88e17b57 BE |
786 | |
787 | Symtab_t symtab = module->symtab; | |
788 | int i; | |
789 | ||
40165636 RB |
790 | /* Iterate thru classes defined in this module and call the callback |
791 | for each one. */ | |
88e17b57 BE |
792 | for (i = 0; i < symtab->cls_def_cnt; i++) |
793 | { | |
794 | Class class = (Class) symtab->defs[i]; | |
795 | ||
40165636 | 796 | /* Call the _objc_load_callback for this class. */ |
88e17b57 | 797 | if (_objc_load_callback) |
40165636 | 798 | _objc_load_callback (class, 0); |
88e17b57 BE |
799 | } |
800 | ||
40165636 RB |
801 | /* Call the _objc_load_callback for categories. Don't register the |
802 | instance methods as class methods for categories to root classes | |
803 | since they were already added in the class. */ | |
88e17b57 BE |
804 | for (i = 0; i < symtab->cat_def_cnt; i++) |
805 | { | |
806 | Category_t category = symtab->defs[i + symtab->cls_def_cnt]; | |
807 | Class class = objc_lookup_class (category->class_name); | |
808 | ||
809 | if (_objc_load_callback) | |
40165636 | 810 | _objc_load_callback (class, category); |
88e17b57 BE |
811 | } |
812 | } | |
813 | ||
40165636 RB |
814 | /* Sanity check the version of gcc used to compile `module'. */ |
815 | ||
816 | static void | |
817 | init_check_module_version (Module_t module) | |
88e17b57 BE |
818 | { |
819 | if ((module->version != OBJC_VERSION) || (module->size != sizeof (Module))) | |
820 | { | |
821 | int code; | |
822 | ||
40165636 | 823 | if (module->version > OBJC_VERSION) |
88e17b57 BE |
824 | code = OBJC_ERR_OBJC_VERSION; |
825 | else if (module->version < OBJC_VERSION) | |
826 | code = OBJC_ERR_GCC_VERSION; | |
827 | else | |
828 | code = OBJC_ERR_MODULE_SIZE; | |
829 | ||
40165636 RB |
830 | objc_error (nil, code, "Module %s version %d doesn't match runtime %d\n", |
831 | module->name, (int)module->version, OBJC_VERSION); | |
88e17b57 BE |
832 | } |
833 | } | |
834 | ||
835 | static void | |
40165636 | 836 | __objc_init_protocols (struct objc_protocol_list *protos) |
88e17b57 | 837 | { |
8f8c44cb | 838 | size_t i; |
88e17b57 BE |
839 | static Class proto_class = 0; |
840 | ||
841 | if (! protos) | |
842 | return; | |
843 | ||
40165636 | 844 | objc_mutex_lock (__objc_runtime_mutex); |
88e17b57 | 845 | |
40165636 RB |
846 | if (! proto_class) |
847 | proto_class = objc_lookup_class ("Protocol"); | |
88e17b57 | 848 | |
40165636 | 849 | if (! proto_class) |
88e17b57 BE |
850 | { |
851 | unclaimed_proto_list = list_cons (protos, unclaimed_proto_list); | |
40165636 | 852 | objc_mutex_unlock (__objc_runtime_mutex); |
88e17b57 BE |
853 | return; |
854 | } | |
855 | ||
856 | #if 0 | |
857 | assert (protos->next == 0); /* only single ones allowed */ | |
858 | #endif | |
859 | ||
40165636 | 860 | for (i = 0; i < protos->count; i++) |
88e17b57 | 861 | { |
40165636 | 862 | struct objc_protocol *aProto = protos->list[i]; |
88e17b57 BE |
863 | if (((size_t)aProto->class_pointer) == PROTOCOL_VERSION) |
864 | { | |
865 | /* assign class pointer */ | |
866 | aProto->class_pointer = proto_class; | |
867 | ||
868 | /* init super protocols */ | |
869 | __objc_init_protocols (aProto->protocol_list); | |
870 | } | |
871 | else if (protos->list[i]->class_pointer != proto_class) | |
872 | { | |
40165636 | 873 | objc_error (nil, OBJC_ERR_PROTOCOL_VERSION, |
88e17b57 | 874 | "Version %d doesn't match runtime protocol version %d\n", |
40165636 RB |
875 | (int) ((char *) protos->list[i]->class_pointer |
876 | - (char *) 0), | |
88e17b57 BE |
877 | PROTOCOL_VERSION); |
878 | } | |
879 | } | |
880 | ||
40165636 | 881 | objc_mutex_unlock (__objc_runtime_mutex); |
88e17b57 BE |
882 | } |
883 | ||
40165636 RB |
884 | static void |
885 | __objc_class_add_protocols (Class class, struct objc_protocol_list *protos) | |
88e17b57 | 886 | { |
40165636 | 887 | /* Well... */ |
88e17b57 BE |
888 | if (! protos) |
889 | return; | |
890 | ||
40165636 | 891 | /* Add it... */ |
88e17b57 BE |
892 | protos->next = class->protocols; |
893 | class->protocols = protos; | |
894 | } |