]>
Commit | Line | Data |
---|---|---|
88e17b57 | 1 | /* GNU Objective C Runtime initialization |
8d9254fc | 2 | Copyright (C) 1993-2020 Free Software Foundation, Inc. |
88e17b57 BE |
3 | Contributed by Kresten Krab Thorup |
4 | +load support contributed by Ovidiu Predescu <ovidiu@net-community.com> | |
5 | ||
38709cad | 6 | This file is part of GCC. |
88e17b57 | 7 | |
38709cad | 8 | GCC is free software; you can redistribute it and/or modify it under the |
88e17b57 | 9 | terms of the GNU General Public License as published by the Free Software |
748086b7 | 10 | Foundation; either version 3, or (at your option) any later version. |
88e17b57 | 11 | |
38709cad | 12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
88e17b57 BE |
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
14 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |
15 | details. | |
16 | ||
748086b7 JJ |
17 | Under Section 7 of GPL version 3, you are granted additional |
18 | permissions described in the GCC Runtime Library Exception, version | |
19 | 3.1, as published by the Free Software Foundation. | |
88e17b57 | 20 | |
748086b7 JJ |
21 | You should have received a copy of the GNU General Public License and |
22 | a copy of the GCC Runtime Library Exception along with this program; | |
23 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
24 | <http://www.gnu.org/licenses/>. */ | |
88e17b57 | 25 | |
e99776d8 NP |
26 | /* Uncommented the following line to enable debug logging. Use this |
27 | only while debugging the runtime. */ | |
28 | /* #define DEBUG 1 */ | |
29 | ||
6dead247 | 30 | #include "objc-private/common.h" |
7b869986 | 31 | #include "objc-private/error.h" |
fed2b101 | 32 | #include "objc/runtime.h" |
a19fac96 | 33 | #include "objc/thr.h" |
5be9cdc1 NP |
34 | #include "objc-private/hash.h" |
35 | #include "objc-private/objc-list.h" | |
fed2b101 | 36 | #include "objc-private/module-abi-8.h" |
41720477 | 37 | #include "objc-private/runtime.h" /* For __objc_resolve_class_links(). */ |
1af5b8f5 | 38 | #include "objc-private/selector.h" /* For __sel_register_typed_name(). */ |
fd312537 | 39 | #include "objc-private/objc-sync.h" /* For __objc_sync_init() */ |
f7185d47 NP |
40 | #include "objc-private/protocols.h" /* For __objc_protocols_init(), |
41 | __objc_protocols_add_protocol() | |
42 | __objc_protocols_register_selectors() */ | |
682e805a | 43 | #include "objc-private/accessors.h" /* For __objc_accessors_init() */ |
88e17b57 | 44 | |
575584a9 | 45 | /* The version number of this runtime. This must match the number |
40165636 | 46 | defined in gcc (objc-act.c). */ |
88e17b57 BE |
47 | #define OBJC_VERSION 8 |
48 | #define PROTOCOL_VERSION 2 | |
49 | ||
c07499dc | 50 | /* This list contains modules currently loaded into the runtime and |
1588200e NP |
51 | for which the +load method (and the load callback, if any) has not |
52 | been called yet. */ | |
40165636 | 53 | static struct objc_list *__objc_module_list = 0; /* !T:MUTEX */ |
88e17b57 | 54 | |
575584a9 NP |
55 | /* This list contains all proto_list's not yet assigned class |
56 | links. */ | |
40165636 | 57 | static struct objc_list *unclaimed_proto_list = 0; /* !T:MUTEX */ |
88e17b57 BE |
58 | |
59 | /* List of unresolved static instances. */ | |
60 | static struct objc_list *uninitialized_statics = 0; /* !T:MUTEX */ | |
61 | ||
0bfe3fa1 NP |
62 | /* List of duplicated classes found while loading modules. If we find |
63 | a class twice, we ignore it the second time. On some platforms, | |
64 | where the order in which modules are loaded is well defined, this | |
65 | allows you to replace a class in a shared library by linking in a | |
66 | new implementation which is loaded in in the right order, and which | |
67 | overrides the existing one. | |
68 | ||
69 | Protected by __objc_runtime_mutex. */ | |
70 | static cache_ptr duplicate_classes = NULL; | |
71 | ||
debfbfee NP |
72 | /* Global runtime "write" mutex. Having a single mutex prevents |
73 | deadlocks, but reduces concurrency. To improve concurrency, some | |
74 | groups of functions in the runtime have their own separate mutex | |
75 | (eg, __class_table_lock in class.c); to avoid deadlocks, these | |
76 | routines must make sure that they never acquire any other lock | |
77 | while holding their own local lock. Ie, they should lock, execute | |
78 | some C code that does not perform any calls to other runtime | |
79 | functions which may potentially lock different locks, then unlock. | |
80 | If they need to perform any calls to other runtime functions that | |
81 | may potentially lock other locks, then they should use the global | |
82 | __objc_runtime_mutex. */ | |
88e17b57 BE |
83 | objc_mutex_t __objc_runtime_mutex = 0; |
84 | ||
40165636 | 85 | /* Number of threads that are alive. */ |
88e17b57 BE |
86 | int __objc_runtime_threads_alive = 1; /* !T:MUTEX */ |
87 | ||
40165636 | 88 | /* Check compiler vs runtime version. */ |
fed2b101 | 89 | static void init_check_module_version (struct objc_module *); |
88e17b57 | 90 | |
40165636 RB |
91 | /* Assign isa links to protos. */ |
92 | static void __objc_init_protocols (struct objc_protocol_list *protos); | |
88e17b57 | 93 | |
f7185d47 NP |
94 | /* Assign isa link to a protocol, and register it. */ |
95 | static void __objc_init_protocol (struct objc_protocol *protocol); | |
96 | ||
40165636 RB |
97 | /* Add protocol to class. */ |
98 | static void __objc_class_add_protocols (Class, struct objc_protocol_list *); | |
88e17b57 | 99 | |
120d5f8e | 100 | /* Load callback hook. */ |
1588200e | 101 | void (*_objc_load_callback) (Class class, struct objc_category *category) = 0; /* !T:SAFE */ |
88e17b57 | 102 | |
0bfe3fa1 | 103 | /* Are all categories/classes resolved ? */ |
88e17b57 BE |
104 | BOOL __objc_dangling_categories = NO; /* !T:UNUSED */ |
105 | ||
575584a9 NP |
106 | /* Sends +load to all classes and categories in certain |
107 | situations. */ | |
88e17b57 BE |
108 | static void objc_send_load (void); |
109 | ||
110 | /* Inserts all the classes defined in module in a tree of classes that | |
fa539f51 | 111 | resembles the class hierarchy. This tree is traversed in preorder |
40165636 | 112 | and the classes in its nodes receive the +load message if these |
fa539f51 | 113 | methods were not executed before. The algorithm ensures that when |
40165636 RB |
114 | the +load method of a class is executed all the superclasses have |
115 | been already received the +load message. */ | |
fed2b101 | 116 | static void __objc_create_classes_tree (struct objc_module *module); |
88e17b57 | 117 | |
1588200e NP |
118 | /* Calls the _objc_load_callback for each class and category in the |
119 | module (if _objc_load_callback is not NULL). */ | |
120 | static void __objc_call_load_callback (struct objc_module *module); | |
88e17b57 BE |
121 | |
122 | /* A special version that works only before the classes are completely | |
40165636 | 123 | installed in the runtime. */ |
88e17b57 BE |
124 | static BOOL class_is_subclass_of_class (Class class, Class superclass); |
125 | ||
fa539f51 NP |
126 | /* This is a node in the class tree hierarchy used to send +load |
127 | messages. */ | |
0bfe3fa1 NP |
128 | typedef struct objc_class_tree |
129 | { | |
fa539f51 | 130 | /* The class corresponding to the node. */ |
88e17b57 | 131 | Class class; |
fa539f51 NP |
132 | |
133 | /* This is a linked list of all the direct subclasses of this class. | |
134 | 'head' points to a subclass node; 'tail' points to the next | |
135 | objc_list node (whose 'head' points to another subclass node, | |
136 | etc). */ | |
137 | struct objc_list *subclasses; | |
88e17b57 BE |
138 | } objc_class_tree; |
139 | ||
fa539f51 NP |
140 | /* This is a linked list of objc_class_tree trees. The head of these |
141 | trees are root classes (their super class is Nil). These different | |
40165636 | 142 | trees represent different class hierarchies. */ |
88e17b57 BE |
143 | static struct objc_list *__objc_class_tree_list = NULL; |
144 | ||
40165636 RB |
145 | /* Keeps the +load methods who have been already executed. This hash |
146 | should not be destroyed during the execution of the program. */ | |
88e17b57 BE |
147 | static cache_ptr __objc_load_methods = NULL; |
148 | ||
e083f3f9 RFM |
149 | /* This function is used when building the class tree used to send |
150 | ordinately the +load message to all classes needing it. The tree | |
151 | is really needed so that superclasses will get the message before | |
152 | subclasses. | |
153 | ||
fa539f51 | 154 | This tree may contain classes which are being loaded (or have just |
e083f3f9 RFM |
155 | being loaded), and whose super_class pointers have not yet been |
156 | resolved. This implies that their super_class pointers point to a | |
157 | string with the name of the superclass; when the first message is | |
158 | sent to the class (/an object of that class) the class links will | |
159 | be resolved, which will replace the super_class pointers with | |
160 | pointers to the actual superclasses. | |
161 | ||
162 | Unfortunately, the tree might also contain classes which had been | |
163 | loaded previously, and whose class links have already been | |
164 | resolved. | |
165 | ||
166 | This function returns the superclass of a class in both cases, and | |
167 | can be used to build the determine the class relationships while | |
575584a9 | 168 | building the tree. */ |
e083f3f9 RFM |
169 | static Class class_superclass_of_class (Class class) |
170 | { | |
171 | char *super_class_name; | |
172 | ||
173 | /* If the class links have been resolved, use the resolved | |
575584a9 | 174 | links. */ |
e083f3f9 RFM |
175 | if (CLS_ISRESOLV (class)) |
176 | return class->super_class; | |
177 | ||
178 | /* Else, 'class' has not yet been resolved. This means that its | |
575584a9 NP |
179 | super_class pointer is really the name of the super class (rather |
180 | than a pointer to the actual superclass). */ | |
e083f3f9 RFM |
181 | super_class_name = (char *)class->super_class; |
182 | ||
183 | /* Return Nil for a root class. */ | |
184 | if (super_class_name == NULL) | |
185 | return Nil; | |
186 | ||
187 | /* Lookup the superclass of non-root classes. */ | |
fed2b101 | 188 | return objc_getClass (super_class_name); |
e083f3f9 RFM |
189 | } |
190 | ||
191 | ||
40165636 | 192 | /* Creates a tree of classes whose topmost class is directly inherited |
fa539f51 NP |
193 | from `upper' and the bottom class in this tree is `bottom_class'. |
194 | If `upper' is Nil, creates a class hierarchy up to a root class. | |
195 | The classes in this tree are super classes of `bottom_class'. The | |
196 | `subclasses' member of each tree node point to the list of | |
197 | subclasses for the node. */ | |
88e17b57 BE |
198 | static objc_class_tree * |
199 | create_tree_of_subclasses_inherited_from (Class bottom_class, Class upper) | |
200 | { | |
fed2b101 | 201 | Class superclass; |
88e17b57 BE |
202 | objc_class_tree *tree, *prev; |
203 | ||
204 | DEBUG_PRINTF ("create_tree_of_subclasses_inherited_from:"); | |
e99776d8 | 205 | DEBUG_PRINTF (" bottom_class = %s, upper = %s\n", |
88e17b57 BE |
206 | (bottom_class ? bottom_class->name : NULL), |
207 | (upper ? upper->name : NULL)); | |
208 | ||
fa539f51 NP |
209 | superclass = class_superclass_of_class (bottom_class); |
210 | ||
211 | prev = objc_calloc (1, sizeof (objc_class_tree)); | |
88e17b57 BE |
212 | prev->class = bottom_class; |
213 | ||
fa539f51 NP |
214 | if (superclass == upper) |
215 | return prev; | |
216 | ||
88e17b57 BE |
217 | while (superclass != upper) |
218 | { | |
219 | tree = objc_calloc (1, sizeof (objc_class_tree)); | |
220 | tree->class = superclass; | |
221 | tree->subclasses = list_cons (prev, tree->subclasses); | |
e083f3f9 | 222 | superclass = class_superclass_of_class (superclass); |
88e17b57 BE |
223 | prev = tree; |
224 | } | |
225 | ||
226 | return tree; | |
227 | } | |
228 | ||
40165636 | 229 | /* Insert the `class' into the proper place in the `tree' class |
fa539f51 | 230 | hierarchy. This function returns a new tree if the class has been |
40165636 | 231 | successfully inserted into the tree or NULL if the class is not |
fa539f51 NP |
232 | part of the classes hierarchy described by `tree'. This function |
233 | is private to objc_tree_insert_class (), you should not call it | |
40165636 | 234 | directly. */ |
88e17b57 BE |
235 | static objc_class_tree * |
236 | __objc_tree_insert_class (objc_class_tree *tree, Class class) | |
237 | { | |
fa539f51 NP |
238 | DEBUG_PRINTF ("__objc_tree_insert_class: tree = %p (root: %s), class = %s\n", |
239 | tree, ((tree && tree->class) ? tree->class->name : "Nil"), class->name); | |
88e17b57 BE |
240 | |
241 | if (tree == NULL) | |
242 | return create_tree_of_subclasses_inherited_from (class, NULL); | |
243 | else if (class == tree->class) | |
244 | { | |
575584a9 | 245 | /* `class' has been already inserted. */ |
e99776d8 | 246 | DEBUG_PRINTF (" 1. class %s was previously inserted\n", class->name); |
88e17b57 BE |
247 | return tree; |
248 | } | |
e083f3f9 | 249 | else if (class_superclass_of_class (class) == tree->class) |
88e17b57 | 250 | { |
575584a9 NP |
251 | /* If class is a direct subclass of tree->class then add class |
252 | to the list of subclasses. First check to see if it wasn't | |
253 | already inserted. */ | |
88e17b57 BE |
254 | struct objc_list *list = tree->subclasses; |
255 | objc_class_tree *node; | |
256 | ||
257 | while (list) | |
258 | { | |
259 | /* Class has been already inserted; do nothing just return | |
40165636 RB |
260 | the tree. */ |
261 | if (((objc_class_tree *) list->head)->class == class) | |
88e17b57 | 262 | { |
e99776d8 | 263 | DEBUG_PRINTF (" 2. class %s was previously inserted\n", |
88e17b57 BE |
264 | class->name); |
265 | return tree; | |
266 | } | |
267 | list = list->tail; | |
268 | } | |
269 | ||
575584a9 NP |
270 | /* Create a new node class and insert it into the list of |
271 | subclasses. */ | |
88e17b57 BE |
272 | node = objc_calloc (1, sizeof (objc_class_tree)); |
273 | node->class = class; | |
274 | tree->subclasses = list_cons (node, tree->subclasses); | |
e99776d8 | 275 | DEBUG_PRINTF (" 3. class %s inserted\n", class->name); |
88e17b57 BE |
276 | return tree; |
277 | } | |
278 | else | |
279 | { | |
575584a9 NP |
280 | /* The class is not a direct subclass of tree->class. Search |
281 | for class's superclasses in the list of subclasses. */ | |
88e17b57 BE |
282 | struct objc_list *subclasses = tree->subclasses; |
283 | ||
40165636 RB |
284 | /* Precondition: the class must be a subclass of tree->class; |
285 | otherwise return NULL to indicate our caller that it must | |
286 | take the next tree. */ | |
287 | if (! class_is_subclass_of_class (class, tree->class)) | |
88e17b57 BE |
288 | return NULL; |
289 | ||
290 | for (; subclasses != NULL; subclasses = subclasses->tail) | |
291 | { | |
40165636 | 292 | Class aClass = ((objc_class_tree *) (subclasses->head))->class; |
88e17b57 BE |
293 | |
294 | if (class_is_subclass_of_class (class, aClass)) | |
295 | { | |
40165636 RB |
296 | /* If we found one of class's superclasses we insert the |
297 | class into its subtree and return the original tree | |
298 | since nothing has been changed. */ | |
88e17b57 BE |
299 | subclasses->head |
300 | = __objc_tree_insert_class (subclasses->head, class); | |
e99776d8 | 301 | DEBUG_PRINTF (" 4. class %s inserted\n", class->name); |
88e17b57 BE |
302 | return tree; |
303 | } | |
304 | } | |
305 | ||
40165636 RB |
306 | /* We haven't found a subclass of `class' in the `subclasses' |
307 | list. Create a new tree of classes whose topmost class is a | |
308 | direct subclass of tree->class. */ | |
88e17b57 BE |
309 | { |
310 | objc_class_tree *new_tree | |
40165636 | 311 | = create_tree_of_subclasses_inherited_from (class, tree->class); |
88e17b57 | 312 | tree->subclasses = list_cons (new_tree, tree->subclasses); |
e99776d8 | 313 | DEBUG_PRINTF (" 5. class %s inserted\n", class->name); |
88e17b57 BE |
314 | return tree; |
315 | } | |
316 | } | |
317 | } | |
318 | ||
40165636 | 319 | /* This function inserts `class' in the right tree hierarchy classes. */ |
88e17b57 BE |
320 | static void |
321 | objc_tree_insert_class (Class class) | |
322 | { | |
323 | struct objc_list *list_node; | |
324 | objc_class_tree *tree; | |
fa539f51 | 325 | |
88e17b57 BE |
326 | list_node = __objc_class_tree_list; |
327 | while (list_node) | |
328 | { | |
fa539f51 | 329 | /* Try to insert the class in this class hierarchy. */ |
88e17b57 BE |
330 | tree = __objc_tree_insert_class (list_node->head, class); |
331 | if (tree) | |
332 | { | |
333 | list_node->head = tree; | |
fa539f51 | 334 | return; |
88e17b57 BE |
335 | } |
336 | else | |
337 | list_node = list_node->tail; | |
338 | } | |
fa539f51 NP |
339 | |
340 | /* If the list was finished but the class hasn't been inserted, we | |
cad10e05 | 341 | don't have an existing class hierarchy that can accommodate it. |
fa539f51 NP |
342 | Create a new one. */ |
343 | __objc_class_tree_list = list_cons (NULL, __objc_class_tree_list); | |
344 | __objc_class_tree_list->head = __objc_tree_insert_class (NULL, class); | |
88e17b57 BE |
345 | } |
346 | ||
40165636 | 347 | /* Traverse tree in preorder. Used to send +load. */ |
88e17b57 BE |
348 | static void |
349 | objc_preorder_traverse (objc_class_tree *tree, | |
350 | int level, | |
40165636 | 351 | void (*function) (objc_class_tree *, int)) |
88e17b57 BE |
352 | { |
353 | struct objc_list *node; | |
354 | ||
355 | (*function) (tree, level); | |
356 | for (node = tree->subclasses; node; node = node->tail) | |
357 | objc_preorder_traverse (node->head, level + 1, function); | |
358 | } | |
359 | ||
40165636 | 360 | /* Traverse tree in postorder. Used to destroy a tree. */ |
88e17b57 BE |
361 | static void |
362 | objc_postorder_traverse (objc_class_tree *tree, | |
40165636 RB |
363 | int level, |
364 | void (*function) (objc_class_tree *, int)) | |
88e17b57 BE |
365 | { |
366 | struct objc_list *node; | |
367 | ||
368 | for (node = tree->subclasses; node; node = node->tail) | |
369 | objc_postorder_traverse (node->head, level + 1, function); | |
370 | (*function) (tree, level); | |
371 | } | |
372 | ||
40165636 | 373 | /* Used to print a tree class hierarchy. */ |
88e17b57 BE |
374 | #ifdef DEBUG |
375 | static void | |
376 | __objc_tree_print (objc_class_tree *tree, int level) | |
377 | { | |
378 | int i; | |
379 | ||
380 | for (i = 0; i < level; i++) | |
381 | printf (" "); | |
382 | printf ("%s\n", tree->class->name); | |
383 | } | |
384 | #endif | |
385 | ||
40165636 | 386 | /* Walks on a linked list of methods in the reverse order and executes |
c07499dc NP |
387 | all the methods corresponding to the `+load' selector. Walking in |
388 | the reverse order assures the +load of class is executed first and | |
389 | then +load of categories because of the way in which categories are | |
390 | added to the class methods. This function needs to be called with | |
391 | the objc_runtime_mutex locked. */ | |
88e17b57 | 392 | static void |
c07499dc | 393 | __objc_send_load_using_method_list (struct objc_method_list *method_list, Class class) |
88e17b57 | 394 | { |
c07499dc | 395 | static SEL load_selector = 0; |
88e17b57 BE |
396 | int i; |
397 | ||
c07499dc | 398 | if (!method_list) |
88e17b57 BE |
399 | return; |
400 | ||
c07499dc NP |
401 | /* This needs no lock protection because we are called with the |
402 | objc_runtime_mutex locked. */ | |
403 | if (!load_selector) | |
404 | load_selector = sel_registerName ("load"); | |
405 | ||
406 | /* method_list is a linked list of method lists; since we're | |
407 | executing in reverse order, we need to do the next list before we | |
408 | do this one. */ | |
409 | __objc_send_load_using_method_list (method_list->method_next, class); | |
88e17b57 | 410 | |
40165636 | 411 | /* Search the method list. */ |
88e17b57 BE |
412 | for (i = 0; i < method_list->method_count; i++) |
413 | { | |
fed2b101 | 414 | struct objc_method *mth = &method_list->method_list[i]; |
88e17b57 | 415 | |
c07499dc NP |
416 | /* We are searching for +load methods that we haven't executed |
417 | yet. */ | |
418 | if (mth->method_name && sel_eq (mth->method_name, load_selector) | |
270a1283 | 419 | && ! objc_hash_is_key_in_hash (__objc_load_methods, mth->method_imp)) |
88e17b57 | 420 | { |
c07499dc NP |
421 | /* Add this method into the +load hash table, so we won't |
422 | execute it again next time. */ | |
270a1283 DA |
423 | objc_hash_add (&__objc_load_methods, |
424 | mth->method_imp, | |
425 | mth->method_imp); | |
575584a9 | 426 | |
c07499dc | 427 | /* Call +load. */ |
e99776d8 | 428 | DEBUG_PRINTF (" begin of [%s +load]\n", class->name); |
e6be21fe | 429 | (*mth->method_imp) ((id)class, mth->method_name); |
e99776d8 | 430 | DEBUG_PRINTF (" end of [%s +load]\n", class->name); |
e6be21fe | 431 | |
88e17b57 BE |
432 | break; |
433 | } | |
434 | } | |
435 | } | |
436 | ||
c07499dc NP |
437 | /* This function needs to be called with the objc_runtime_mutex |
438 | locked. */ | |
88e17b57 | 439 | static void |
8f8c44cb KG |
440 | __objc_send_load (objc_class_tree *tree, |
441 | int level __attribute__ ((__unused__))) | |
88e17b57 | 442 | { |
88e17b57 | 443 | Class class = tree->class; |
fed2b101 | 444 | struct objc_method_list *method_list = class->class_pointer->methods; |
88e17b57 | 445 | |
e99776d8 | 446 | DEBUG_PRINTF ("+load: need to send load to class '%s'\n", class->name); |
c07499dc | 447 | __objc_send_load_using_method_list (method_list, class); |
88e17b57 BE |
448 | } |
449 | ||
450 | static void | |
8f8c44cb KG |
451 | __objc_destroy_class_tree_node (objc_class_tree *tree, |
452 | int level __attribute__ ((__unused__))) | |
88e17b57 BE |
453 | { |
454 | objc_free (tree); | |
455 | } | |
456 | ||
40165636 RB |
457 | /* This is used to check if the relationship between two classes |
458 | before the runtime completely installs the classes. */ | |
88e17b57 BE |
459 | static BOOL |
460 | class_is_subclass_of_class (Class class, Class superclass) | |
461 | { | |
462 | for (; class != Nil;) | |
463 | { | |
464 | if (class == superclass) | |
465 | return YES; | |
e083f3f9 | 466 | class = class_superclass_of_class (class); |
88e17b57 BE |
467 | } |
468 | ||
469 | return NO; | |
470 | } | |
471 | ||
40165636 RB |
472 | /* This list contains all the classes in the runtime system for whom |
473 | their superclasses are not yet known to the runtime. */ | |
474 | static struct objc_list *unresolved_classes = 0; | |
88e17b57 | 475 | |
1501d094 | 476 | /* Extern function used to reference the Object class. */ |
6000b42b JDA |
477 | extern void __objc_force_linking (void); |
478 | ||
479 | void | |
88e17b57 BE |
480 | __objc_force_linking (void) |
481 | { | |
482 | extern void __objc_linking (void); | |
483 | __objc_linking (); | |
88e17b57 BE |
484 | } |
485 | ||
40165636 RB |
486 | /* Run through the statics list, removing modules as soon as all its |
487 | statics have been initialized. */ | |
88e17b57 BE |
488 | static void |
489 | objc_init_statics (void) | |
490 | { | |
491 | struct objc_list **cell = &uninitialized_statics; | |
492 | struct objc_static_instances **statics_in_module; | |
493 | ||
40165636 | 494 | objc_mutex_lock (__objc_runtime_mutex); |
88e17b57 BE |
495 | |
496 | while (*cell) | |
497 | { | |
498 | int module_initialized = 1; | |
499 | ||
500 | for (statics_in_module = (*cell)->head; | |
501 | *statics_in_module; statics_in_module++) | |
502 | { | |
503 | struct objc_static_instances *statics = *statics_in_module; | |
fed2b101 | 504 | Class class = objc_getClass (statics->class_name); |
88e17b57 | 505 | |
40165636 | 506 | if (! class) |
88e17b57 | 507 | { |
5254c66b NP |
508 | /* It is unfortunate that this will cause all the |
509 | statics initialization to be done again (eg, if we | |
510 | already initialized constant strings, and are now | |
511 | initializing protocols, setting module_initialized to | |
512 | 0 would cause constant strings to be initialized | |
513 | again). It would be good to be able to track if we | |
514 | have already initialized some of them. */ | |
515 | module_initialized = 0; | |
516 | } | |
517 | else | |
518 | { | |
519 | /* Note that if this is a list of Protocol objects, some | |
520 | of them may have been initialized already (because | |
521 | they were attached to classes or categories, and the | |
522 | class/category loading code automatically fixes them | |
523 | up), and some of them may not. We really need to go | |
f7185d47 NP |
524 | through the whole list to be sure! Protocols are |
525 | also special because we want to register them and | |
526 | register all their selectors. */ | |
88e17b57 BE |
527 | id *inst; |
528 | ||
f7185d47 NP |
529 | if (strcmp (statics->class_name, "Protocol") == 0) |
530 | { | |
531 | /* Protocols are special, because not only we want | |
532 | to fix up their class pointers, but we also want | |
533 | to register them and their selectors with the | |
534 | runtime. */ | |
535 | for (inst = &statics->instances[0]; *inst; inst++) | |
536 | __objc_init_protocol ((struct objc_protocol *)*inst); | |
537 | } | |
538 | else | |
539 | { | |
575584a9 NP |
540 | /* Other static instances (typically constant |
541 | strings) are easier as we just fix up their class | |
542 | pointers. */ | |
f7185d47 NP |
543 | for (inst = &statics->instances[0]; *inst; inst++) |
544 | (*inst)->class_pointer = class; | |
545 | } | |
88e17b57 BE |
546 | } |
547 | } | |
548 | if (module_initialized) | |
549 | { | |
550 | /* Remove this module from the uninitialized list. */ | |
551 | struct objc_list *this = *cell; | |
552 | *cell = this->tail; | |
40165636 | 553 | objc_free (this); |
88e17b57 BE |
554 | } |
555 | else | |
556 | cell = &(*cell)->tail; | |
557 | } | |
558 | ||
40165636 | 559 | objc_mutex_unlock (__objc_runtime_mutex); |
575584a9 | 560 | } |
88e17b57 BE |
561 | |
562 | /* This function is called by constructor functions generated for each | |
40165636 RB |
563 | module compiled. (_GLOBAL_$I$...) The purpose of this function is |
564 | to gather the module pointers so that they may be processed by the | |
565 | initialization routines as soon as possible. */ | |
88e17b57 | 566 | void |
fed2b101 | 567 | __objc_exec_class (struct objc_module *module) |
88e17b57 | 568 | { |
fed2b101 NP |
569 | /* Have we processed any constructors previously? This flag is used |
570 | to indicate that some global data structures need to be | |
571 | built. */ | |
88e17b57 BE |
572 | static BOOL previous_constructors = 0; |
573 | ||
40165636 | 574 | static struct objc_list *unclaimed_categories = 0; |
88e17b57 | 575 | |
fed2b101 NP |
576 | /* The symbol table (defined in objc-private/module-abi-8.h) |
577 | generated by gcc. */ | |
578 | struct objc_symtab *symtab = module->symtab; | |
88e17b57 | 579 | |
fed2b101 | 580 | /* The statics in this module. */ |
88e17b57 BE |
581 | struct objc_static_instances **statics |
582 | = symtab->defs[symtab->cls_def_cnt + symtab->cat_def_cnt]; | |
583 | ||
fed2b101 | 584 | /* Entry used to traverse hash lists. */ |
40165636 | 585 | struct objc_list **cell; |
88e17b57 | 586 | |
fed2b101 | 587 | /* The table of selector references for this module. */ |
600cbba2 | 588 | struct objc_selector *selectors = symtab->refs; |
88e17b57 | 589 | |
88e17b57 BE |
590 | int i; |
591 | ||
e99776d8 | 592 | DEBUG_PRINTF ("\n__objc_exec_class (%p) - start processing module...\n", module); |
88e17b57 | 593 | |
575584a9 | 594 | /* Check gcc version. */ |
40165636 | 595 | init_check_module_version (module); |
88e17b57 | 596 | |
575584a9 NP |
597 | /* On the first call of this routine, initialize some data |
598 | structures. */ | |
40165636 | 599 | if (! previous_constructors) |
88e17b57 | 600 | { |
575584a9 | 601 | /* Initialize thread-safe system. */ |
40165636 | 602 | __objc_init_thread_system (); |
88e17b57 | 603 | __objc_runtime_threads_alive = 1; |
40165636 | 604 | __objc_runtime_mutex = objc_mutex_allocate (); |
88e17b57 | 605 | |
40165636 RB |
606 | __objc_init_selector_tables (); |
607 | __objc_init_class_tables (); | |
608 | __objc_init_dispatch_tables (); | |
0bfe3fa1 NP |
609 | duplicate_classes = objc_hash_new (8, |
610 | (hash_func_type)objc_hash_ptr, | |
611 | objc_compare_ptrs); | |
270a1283 DA |
612 | __objc_load_methods = objc_hash_new (128, |
613 | (hash_func_type)objc_hash_ptr, | |
614 | objc_compare_ptrs); | |
debfbfee | 615 | __objc_protocols_init (); |
682e805a | 616 | __objc_accessors_init (); |
fd312537 | 617 | __objc_sync_init (); |
88e17b57 BE |
618 | previous_constructors = 1; |
619 | } | |
620 | ||
c07499dc NP |
621 | /* Save the module pointer so that later we remember to call +load |
622 | on all classes and categories on it. */ | |
40165636 RB |
623 | objc_mutex_lock (__objc_runtime_mutex); |
624 | __objc_module_list = list_cons (module, __objc_module_list); | |
88e17b57 | 625 | |
600cbba2 | 626 | /* Replace referenced selectors from names to SELs. */ |
88e17b57 | 627 | if (selectors) |
e99776d8 NP |
628 | { |
629 | DEBUG_PRINTF (" registering selectors\n"); | |
630 | __objc_register_selectors_from_module (selectors); | |
631 | } | |
88e17b57 | 632 | |
575584a9 NP |
633 | /* Parse the classes in the load module and gather selector |
634 | information. */ | |
88e17b57 BE |
635 | for (i = 0; i < symtab->cls_def_cnt; ++i) |
636 | { | |
637 | Class class = (Class) symtab->defs[i]; | |
40165636 | 638 | const char *superclass = (char *) class->super_class; |
88e17b57 BE |
639 | |
640 | /* Make sure we have what we think. */ | |
40165636 RB |
641 | assert (CLS_ISCLASS (class)); |
642 | assert (CLS_ISMETA (class->class_pointer)); | |
e99776d8 | 643 | DEBUG_PRINTF (" installing class '%s'\n", class->name); |
88e17b57 | 644 | |
b4a50e43 NP |
645 | /* Workaround for a bug in clang: Clang may set flags other than |
646 | _CLS_CLASS and _CLS_META even when compiling for the | |
647 | traditional ABI (version 8), confusing our runtime. Try to | |
648 | wipe these flags out. */ | |
649 | if (CLS_ISCLASS (class)) | |
650 | __CLS_INFO (class) = _CLS_CLASS; | |
651 | else | |
652 | __CLS_INFO (class) = _CLS_META; | |
653 | ||
575584a9 NP |
654 | /* Initialize the subclass list to be NULL. In some cases it |
655 | isn't and this crashes the program. */ | |
88e17b57 BE |
656 | class->subclass_list = NULL; |
657 | ||
0bfe3fa1 NP |
658 | if (__objc_init_class (class)) |
659 | { | |
660 | /* Check to see if the superclass is known in this point. If | |
661 | it's not add the class to the unresolved_classes list. */ | |
662 | if (superclass && ! objc_getClass (superclass)) | |
663 | unresolved_classes = list_cons (class, unresolved_classes); | |
664 | } | |
665 | } | |
88e17b57 BE |
666 | |
667 | /* Process category information from the module. */ | |
668 | for (i = 0; i < symtab->cat_def_cnt; ++i) | |
669 | { | |
fed2b101 NP |
670 | struct objc_category *category = symtab->defs[i + symtab->cls_def_cnt]; |
671 | Class class = objc_getClass (category->class_name); | |
88e17b57 | 672 | |
575584a9 NP |
673 | /* If the class for the category exists then append its |
674 | methods. */ | |
88e17b57 BE |
675 | if (class) |
676 | { | |
e99776d8 | 677 | DEBUG_PRINTF (" installing category '%s (%s)'\n", category->class_name, category->category_name); |
88e17b57 BE |
678 | /* Do instance methods. */ |
679 | if (category->instance_methods) | |
680 | class_add_method_list (class, category->instance_methods); | |
681 | ||
682 | /* Do class methods. */ | |
683 | if (category->class_methods) | |
684 | class_add_method_list ((Class) class->class_pointer, | |
685 | category->class_methods); | |
686 | ||
687 | if (category->protocols) | |
688 | { | |
689 | __objc_init_protocols (category->protocols); | |
690 | __objc_class_add_protocols (class, category->protocols); | |
691 | } | |
692 | ||
693 | /* Register the instance methods as class methods, this is | |
40165636 RB |
694 | only done for root classes. */ |
695 | __objc_register_instance_methods_to_class (class); | |
88e17b57 BE |
696 | } |
697 | else | |
698 | { | |
e99776d8 | 699 | DEBUG_PRINTF (" delaying installation of category '%s (%s)'\n", category->class_name, category->category_name); |
575584a9 NP |
700 | /* The object to which the category methods belong can't be |
701 | found. Save the information. */ | |
40165636 | 702 | unclaimed_categories = list_cons (category, unclaimed_categories); |
88e17b57 BE |
703 | } |
704 | } | |
705 | ||
706 | if (statics) | |
707 | uninitialized_statics = list_cons (statics, uninitialized_statics); | |
708 | if (uninitialized_statics) | |
709 | objc_init_statics (); | |
710 | ||
575584a9 NP |
711 | /* Scan the unclaimed category hash. Attempt to attach any |
712 | unclaimed categories to objects. */ | |
e5e0f6f5 | 713 | for (cell = &unclaimed_categories; *cell; ) |
88e17b57 | 714 | { |
fed2b101 NP |
715 | struct objc_category *category = (*cell)->head; |
716 | Class class = objc_getClass (category->class_name); | |
88e17b57 BE |
717 | |
718 | if (class) | |
719 | { | |
e99776d8 | 720 | DEBUG_PRINTF (" installing (delayed) category '%s (%s)'\n", category->class_name, category->category_name); |
88e17b57 BE |
721 | list_remove_head (cell); |
722 | ||
723 | if (category->instance_methods) | |
724 | class_add_method_list (class, category->instance_methods); | |
725 | ||
726 | if (category->class_methods) | |
727 | class_add_method_list ((Class) class->class_pointer, | |
728 | category->class_methods); | |
729 | ||
730 | if (category->protocols) | |
731 | { | |
732 | __objc_init_protocols (category->protocols); | |
733 | __objc_class_add_protocols (class, category->protocols); | |
734 | } | |
735 | ||
736 | /* Register the instance methods as class methods, this is | |
40165636 RB |
737 | only done for root classes. */ |
738 | __objc_register_instance_methods_to_class (class); | |
88e17b57 | 739 | } |
e5e0f6f5 NP |
740 | else |
741 | cell = &(*cell)->tail; | |
88e17b57 BE |
742 | } |
743 | ||
fed2b101 | 744 | if (unclaimed_proto_list && objc_getClass ("Protocol")) |
88e17b57 | 745 | { |
40165636 RB |
746 | list_mapcar (unclaimed_proto_list, |
747 | (void (*) (void *))__objc_init_protocols); | |
88e17b57 BE |
748 | list_free (unclaimed_proto_list); |
749 | unclaimed_proto_list = 0; | |
750 | } | |
751 | ||
752 | objc_send_load (); | |
753 | ||
41720477 NP |
754 | /* Check if there are no unresolved classes (ie, classes whose |
755 | superclass has not been loaded yet) and that the 'Object' class, | |
756 | used as the class of classes, exist. If so, it is worth | |
757 | "resolving the class links" at this point, which will setup all | |
758 | the class/superclass pointers. */ | |
759 | if (!unresolved_classes && objc_getClass ("Object")) | |
e99776d8 NP |
760 | { |
761 | DEBUG_PRINTF (" resolving class links\n"); | |
762 | __objc_resolve_class_links (); | |
763 | } | |
120d5f8e | 764 | |
41720477 | 765 | objc_mutex_unlock (__objc_runtime_mutex); |
e99776d8 NP |
766 | |
767 | DEBUG_PRINTF ("__objc_exec_class (%p) - finished processing module...\n\n", module); | |
88e17b57 BE |
768 | } |
769 | ||
c07499dc NP |
770 | /* This function needs to be called with the objc_runtime_mutex |
771 | locked. */ | |
40165636 RB |
772 | static void |
773 | objc_send_load (void) | |
88e17b57 | 774 | { |
c07499dc | 775 | if (!__objc_module_list) |
88e17b57 BE |
776 | return; |
777 | ||
778 | /* Try to find out if all the classes loaded so far also have their | |
c07499dc | 779 | superclasses known to the runtime. We suppose that the objects |
40165636 RB |
780 | that are allocated in the +load method are in general of a class |
781 | declared in the same module. */ | |
88e17b57 BE |
782 | if (unresolved_classes) |
783 | { | |
784 | Class class = unresolved_classes->head; | |
785 | ||
fed2b101 | 786 | while (objc_getClass ((char *) class->super_class)) |
88e17b57 BE |
787 | { |
788 | list_remove_head (&unresolved_classes); | |
789 | if (unresolved_classes) | |
790 | class = unresolved_classes->head; | |
791 | else | |
792 | break; | |
793 | } | |
794 | ||
40165636 RB |
795 | /* If we still have classes for whom we don't have yet their |
796 | super classes known to the runtime we don't send the +load | |
1588200e | 797 | messages (and call the load callback) yet. */ |
88e17b57 BE |
798 | if (unresolved_classes) |
799 | return; | |
800 | } | |
801 | ||
1501d094 NP |
802 | /* Special check. If 'Object', which is used by meta-classes, has |
803 | not been loaded yet, delay sending of +load. */ | |
fed2b101 | 804 | if (! objc_getClass ("Object")) |
88e17b57 BE |
805 | return; |
806 | ||
40165636 | 807 | /* Iterate over all modules in the __objc_module_list and call on |
1588200e | 808 | them the __objc_create_classes_tree function. This function |
40165636 RB |
809 | creates a tree of classes that resembles the class hierarchy. */ |
810 | list_mapcar (__objc_module_list, | |
811 | (void (*) (void *)) __objc_create_classes_tree); | |
88e17b57 BE |
812 | |
813 | while (__objc_class_tree_list) | |
814 | { | |
815 | #ifdef DEBUG | |
816 | objc_preorder_traverse (__objc_class_tree_list->head, | |
817 | 0, __objc_tree_print); | |
818 | #endif | |
819 | objc_preorder_traverse (__objc_class_tree_list->head, | |
820 | 0, __objc_send_load); | |
821 | objc_postorder_traverse (__objc_class_tree_list->head, | |
822 | 0, __objc_destroy_class_tree_node); | |
823 | list_remove_head (&__objc_class_tree_list); | |
824 | } | |
825 | ||
1588200e NP |
826 | /* For each module, call the _objc_load_callback if any is |
827 | defined. */ | |
828 | list_mapcar (__objc_module_list, (void (*) (void *)) __objc_call_load_callback); | |
829 | ||
830 | /* Empty the list of modules. */ | |
88e17b57 BE |
831 | list_free (__objc_module_list); |
832 | __objc_module_list = NULL; | |
833 | } | |
834 | ||
835 | static void | |
fed2b101 | 836 | __objc_create_classes_tree (struct objc_module *module) |
88e17b57 | 837 | { |
575584a9 | 838 | /* The runtime mutex is locked at this point */ |
fed2b101 | 839 | struct objc_symtab *symtab = module->symtab; |
88e17b57 BE |
840 | int i; |
841 | ||
cad10e05 | 842 | /* Iterate through classes defined in this module and insert them in |
40165636 | 843 | the classes tree hierarchy. */ |
88e17b57 BE |
844 | for (i = 0; i < symtab->cls_def_cnt; i++) |
845 | { | |
846 | Class class = (Class) symtab->defs[i]; | |
847 | ||
0bfe3fa1 NP |
848 | if (!objc_hash_is_key_in_hash (duplicate_classes, class)) |
849 | objc_tree_insert_class (class); | |
88e17b57 | 850 | } |
c07499dc NP |
851 | |
852 | /* Now iterate over "claimed" categories too (ie, categories that | |
853 | extend a class that has already been loaded by the runtime), and | |
854 | insert them in the classes tree hiearchy too. Otherwise, if you | |
855 | add a category, its +load method would not be called if the class | |
856 | is already loaded in the runtime. It the category is | |
857 | "unclaimed", ie, we haven't loaded the main class yet, postpone | |
858 | sending +load as we want to execute +load from the class before | |
859 | we execute the one from the category. */ | |
860 | for (i = 0; i < symtab->cat_def_cnt; ++i) | |
861 | { | |
862 | struct objc_category *category = symtab->defs[i + symtab->cls_def_cnt]; | |
863 | Class class = objc_getClass (category->class_name); | |
864 | ||
865 | /* If the class for the category exists then append its | |
866 | methods. */ | |
867 | if (class) | |
868 | objc_tree_insert_class (class); | |
869 | } | |
88e17b57 BE |
870 | } |
871 | ||
872 | static void | |
1588200e | 873 | __objc_call_load_callback (struct objc_module *module) |
88e17b57 | 874 | { |
1588200e | 875 | if (_objc_load_callback) |
88e17b57 | 876 | { |
1588200e NP |
877 | /* The runtime mutex is locked at this point. */ |
878 | struct objc_symtab *symtab = module->symtab; | |
879 | int i; | |
880 | ||
cad10e05 | 881 | /* Iterate through classes defined in this module and call the callback |
1588200e NP |
882 | for each one. */ |
883 | for (i = 0; i < symtab->cls_def_cnt; i++) | |
884 | { | |
885 | Class class = (Class) symtab->defs[i]; | |
0bfe3fa1 NP |
886 | |
887 | if (!objc_hash_is_key_in_hash (duplicate_classes, class)) | |
888 | { | |
889 | /* Call the _objc_load_callback for this class. */ | |
e99776d8 | 890 | DEBUG_PRINTF (" calling the load callback for class '%s'\n", class->name); |
0bfe3fa1 NP |
891 | _objc_load_callback (class, 0); |
892 | } | |
1588200e NP |
893 | } |
894 | ||
895 | /* Call the _objc_load_callback for categories. Don't register | |
896 | the instance methods as class methods for categories to root | |
897 | classes since they were already added in the class. */ | |
898 | for (i = 0; i < symtab->cat_def_cnt; i++) | |
899 | { | |
900 | struct objc_category *category = symtab->defs[i + symtab->cls_def_cnt]; | |
901 | Class class = objc_getClass (category->class_name); | |
902 | ||
e99776d8 NP |
903 | DEBUG_PRINTF (" calling the load callback for category '%s (%s)'\n", |
904 | category->class_name, category->category_name); | |
1588200e NP |
905 | _objc_load_callback (class, category); |
906 | } | |
88e17b57 BE |
907 | } |
908 | } | |
909 | ||
40165636 | 910 | /* Sanity check the version of gcc used to compile `module'. */ |
40165636 | 911 | static void |
fed2b101 | 912 | init_check_module_version (struct objc_module *module) |
88e17b57 | 913 | { |
fed2b101 | 914 | if ((module->version != OBJC_VERSION) || (module->size != sizeof (struct objc_module))) |
88e17b57 | 915 | { |
7b869986 NP |
916 | _objc_abort ("Module %s version %d doesn't match runtime %d\n", |
917 | module->name, (int)module->version, OBJC_VERSION); | |
88e17b57 BE |
918 | } |
919 | } | |
920 | ||
0bfe3fa1 NP |
921 | /* __objc_init_class must be called with __objc_runtime_mutex already |
922 | locked. Return YES if the class could be setup; return NO if the | |
923 | class could not be setup because a class with the same name already | |
924 | exists. */ | |
925 | BOOL | |
6c5c7efd NP |
926 | __objc_init_class (Class class) |
927 | { | |
928 | /* Store the class in the class table and assign class numbers. */ | |
1575c9de NP |
929 | if (__objc_add_class_to_hash (class)) |
930 | { | |
931 | /* Register all of the selectors in the class and meta class. */ | |
932 | __objc_register_selectors_from_class (class); | |
933 | __objc_register_selectors_from_class ((Class) class->class_pointer); | |
934 | ||
935 | /* Install the fake dispatch tables. */ | |
936 | __objc_install_premature_dtable (class); | |
937 | __objc_install_premature_dtable (class->class_pointer); | |
938 | ||
939 | /* Register the instance methods as class methods, this is only | |
940 | done for root classes. */ | |
941 | __objc_register_instance_methods_to_class (class); | |
942 | ||
943 | if (class->protocols) | |
944 | __objc_init_protocols (class->protocols); | |
0bfe3fa1 NP |
945 | |
946 | return YES; | |
1575c9de NP |
947 | } |
948 | else | |
0bfe3fa1 NP |
949 | { |
950 | /* The module contains a duplicate class. Remember it so that | |
951 | we will ignore it later. */ | |
e99776d8 | 952 | DEBUG_PRINTF (" duplicate class '%s' - will be ignored\n", class->name); |
0bfe3fa1 NP |
953 | objc_hash_add (&duplicate_classes, class, class); |
954 | return NO; | |
955 | } | |
6c5c7efd NP |
956 | } |
957 | ||
f7185d47 NP |
958 | /* __objc_init_protocol must be called with __objc_runtime_mutex |
959 | already locked, and the "Protocol" class already registered. */ | |
960 | static void | |
961 | __objc_init_protocol (struct objc_protocol *protocol) | |
962 | { | |
963 | static Class proto_class = 0; | |
964 | ||
965 | if (! proto_class) | |
fed2b101 | 966 | proto_class = objc_getClass ("Protocol"); |
f7185d47 NP |
967 | |
968 | if (((size_t)protocol->class_pointer) == PROTOCOL_VERSION) | |
969 | { | |
575584a9 | 970 | /* Assign class pointer. */ |
f7185d47 NP |
971 | protocol->class_pointer = proto_class; |
972 | ||
973 | /* Register all the selectors in the protocol with the runtime. | |
974 | This both registers the selectors with the right types, and | |
975 | it also fixes up the 'struct objc_method' structures inside | |
976 | the protocol so that each method_name (a char * as compiled | |
977 | by the compiler) is replaced with the appropriate runtime | |
978 | SEL. */ | |
979 | if (protocol->class_methods) | |
980 | __objc_register_selectors_from_description_list (protocol->class_methods); | |
981 | ||
982 | if (protocol->instance_methods) | |
983 | __objc_register_selectors_from_description_list (protocol->instance_methods); | |
984 | ||
985 | /* Register the protocol in the hashtable or protocols by | |
986 | name. */ | |
987 | __objc_protocols_add_protocol (protocol->protocol_name, protocol); | |
988 | ||
575584a9 | 989 | /* Init super protocols. */ |
f7185d47 NP |
990 | __objc_init_protocols (protocol->protocol_list); |
991 | } | |
992 | else if (protocol->class_pointer != proto_class) | |
993 | { | |
994 | _objc_abort ("Version %d doesn't match runtime protocol version %d\n", | |
995 | (int) ((char *) protocol->class_pointer | |
996 | - (char *) 0), | |
997 | PROTOCOL_VERSION); | |
998 | } | |
999 | } | |
1000 | ||
88e17b57 | 1001 | static void |
40165636 | 1002 | __objc_init_protocols (struct objc_protocol_list *protos) |
88e17b57 | 1003 | { |
8f8c44cb | 1004 | size_t i; |
88e17b57 BE |
1005 | static Class proto_class = 0; |
1006 | ||
1007 | if (! protos) | |
1008 | return; | |
1009 | ||
40165636 | 1010 | objc_mutex_lock (__objc_runtime_mutex); |
88e17b57 | 1011 | |
40165636 | 1012 | if (! proto_class) |
fed2b101 | 1013 | proto_class = objc_getClass ("Protocol"); |
88e17b57 | 1014 | |
40165636 | 1015 | if (! proto_class) |
88e17b57 BE |
1016 | { |
1017 | unclaimed_proto_list = list_cons (protos, unclaimed_proto_list); | |
40165636 | 1018 | objc_mutex_unlock (__objc_runtime_mutex); |
88e17b57 BE |
1019 | return; |
1020 | } | |
1021 | ||
1022 | #if 0 | |
575584a9 | 1023 | assert (protos->next == 0); /* Only single ones allowed. */ |
88e17b57 BE |
1024 | #endif |
1025 | ||
40165636 | 1026 | for (i = 0; i < protos->count; i++) |
88e17b57 | 1027 | { |
40165636 | 1028 | struct objc_protocol *aProto = protos->list[i]; |
f7185d47 | 1029 | __objc_init_protocol (aProto); |
88e17b57 BE |
1030 | } |
1031 | ||
40165636 | 1032 | objc_mutex_unlock (__objc_runtime_mutex); |
88e17b57 BE |
1033 | } |
1034 | ||
40165636 RB |
1035 | static void |
1036 | __objc_class_add_protocols (Class class, struct objc_protocol_list *protos) | |
88e17b57 | 1037 | { |
88e17b57 BE |
1038 | if (! protos) |
1039 | return; | |
1040 | ||
88e17b57 BE |
1041 | protos->next = class->protocols; |
1042 | class->protocols = protos; | |
1043 | } |