]>
Commit | Line | Data |
---|---|---|
88e17b57 | 1 | /* GNU Objective C Runtime class related functions |
83ffe9cd | 2 | Copyright (C) 1993-2023 Free Software Foundation, Inc. |
88e17b57 BE |
3 | Contributed by Kresten Krab Thorup and Dennis Glatting. |
4 | ||
2726bdba NP |
5 | Lock-free class table code designed and written from scratch by |
6 | Nicola Pero, 2001. | |
7 | ||
6c82ad25 | 8 | This file is part of GCC. |
88e17b57 | 9 | |
6c82ad25 | 10 | GCC is free software; you can redistribute it and/or modify it under the |
88e17b57 | 11 | terms of the GNU General Public License as published by the Free Software |
748086b7 | 12 | Foundation; either version 3, or (at your option) any later version. |
88e17b57 | 13 | |
6c82ad25 | 14 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
88e17b57 BE |
15 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
16 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | |
17 | details. | |
18 | ||
748086b7 JJ |
19 | Under Section 7 of GPL version 3, you are granted additional |
20 | permissions described in the GCC Runtime Library Exception, version | |
21 | 3.1, as published by the Free Software Foundation. | |
88e17b57 | 22 | |
748086b7 JJ |
23 | You should have received a copy of the GNU General Public License and |
24 | a copy of the GCC Runtime Library Exception along with this program; | |
25 | see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
26 | <http://www.gnu.org/licenses/>. */ | |
88e17b57 | 27 | |
575584a9 | 28 | /* The code in this file critically affects class method invocation |
2726bdba | 29 | speed. This long preamble comment explains why, and the issues |
575584a9 | 30 | involved. |
2726bdba NP |
31 | |
32 | One of the traditional weaknesses of the GNU Objective-C runtime is | |
33 | that class method invocations are slow. The reason is that when you | |
34 | write | |
35 | ||
36 | array = [NSArray new]; | |
37 | ||
38 | this gets basically compiled into the equivalent of | |
39 | ||
40 | array = [(objc_get_class ("NSArray")) new]; | |
41 | ||
42 | objc_get_class returns the class pointer corresponding to the string | |
43 | `NSArray'; and because of the lookup, the operation is more | |
575584a9 | 44 | complicated and slow than a simple instance method invocation. |
2726bdba NP |
45 | |
46 | Most high performance Objective-C code (using the GNU Objc runtime) | |
47 | I had the opportunity to read (or write) work around this problem by | |
48 | caching the class pointer: | |
49 | ||
50 | Class arrayClass = [NSArray class]; | |
51 | ||
52 | ... later on ... | |
53 | ||
54 | array = [arrayClass new]; | |
55 | array = [arrayClass new]; | |
56 | array = [arrayClass new]; | |
57 | ||
58 | In this case, you always perform a class lookup (the first one), but | |
59 | then all the [arrayClass new] methods run exactly as fast as an | |
60 | instance method invocation. It helps if you have many class method | |
575584a9 | 61 | invocations to the same class. |
2726bdba NP |
62 | |
63 | The long-term solution to this problem would be to modify the | |
64 | compiler to output tables of class pointers corresponding to all the | |
65 | class method invocations, and to add code to the runtime to update | |
66 | these tables - that should in the end allow class method invocations | |
67 | to perform precisely as fast as instance method invocations, because | |
68 | no class lookup would be involved. I think the Apple Objective-C | |
69 | runtime uses this technique. Doing this involves synchronized | |
575584a9 | 70 | modifications in the runtime and in the compiler. |
2726bdba NP |
71 | |
72 | As a first medicine to the problem, I [NP] have redesigned and | |
73 | rewritten the way the runtime is performing class lookup. This | |
74 | doesn't give as much speed as the other (definitive) approach, but | |
75 | at least a class method invocation now takes approximately 4.5 times | |
76 | an instance method invocation on my machine (it would take approx 12 | |
575584a9 | 77 | times before the rewriting), which is a lot better. |
2726bdba NP |
78 | |
79 | One of the main reason the new class lookup is so faster is because | |
80 | I implemented it in a way that can safely run multithreaded without | |
81 | using locks - a so-called `lock-free' data structure. The atomic | |
82 | operation is pointer assignment. The reason why in this problem | |
83 | lock-free data structures work so well is that you never remove | |
84 | classes from the table - and the difficult thing with lock-free data | |
85 | structures is freeing data when is removed from the structures. */ | |
86 | ||
6dead247 | 87 | #include "objc-private/common.h" |
7b869986 | 88 | #include "objc-private/error.h" |
be05b0f5 | 89 | #include "objc/runtime.h" |
348a3445 | 90 | #include "objc/thr.h" |
be05b0f5 NP |
91 | #include "objc-private/module-abi-8.h" /* For CLS_ISCLASS and similar. */ |
92 | #include "objc-private/runtime.h" /* the kitchen sink */ | |
51194e8e | 93 | #include "objc-private/sarray.h" /* For sarray_put_at_safe. */ |
80e4b9e5 | 94 | #include "objc-private/selector.h" /* For sarray_put_at_safe. */ |
be05b0f5 | 95 | #include <string.h> /* For memset */ |
2726bdba NP |
96 | |
97 | /* We use a table which maps a class name to the corresponding class | |
575584a9 NP |
98 | pointer. The first part of this file defines this table, and |
99 | functions to do basic operations on the table. The second part of | |
100 | the file implements some higher level Objective-C functionality for | |
101 | classes by using the functions provided in the first part to manage | |
102 | the table. */ | |
2726bdba NP |
103 | |
104 | /** | |
105 | ** Class Table Internals | |
106 | **/ | |
107 | ||
108 | /* A node holding a class */ | |
109 | typedef struct class_node | |
110 | { | |
111 | struct class_node *next; /* Pointer to next entry on the list. | |
112 | NULL indicates end of list. */ | |
113 | ||
114 | const char *name; /* The class name string */ | |
115 | int length; /* The class name string length */ | |
116 | Class pointer; /* The Class pointer */ | |
117 | ||
118 | } *class_node_ptr; | |
119 | ||
120 | /* A table containing classes is a class_node_ptr (pointing to the | |
121 | first entry in the table - if it is NULL, then the table is | |
122 | empty). */ | |
123 | ||
124 | /* We have 1024 tables. Each table contains all class names which | |
125 | have the same hash (which is a number between 0 and 1023). To look | |
126 | up a class_name, we compute its hash, and get the corresponding | |
127 | table. Once we have the table, we simply compare strings directly | |
128 | till we find the one which we want (using the length first). The | |
129 | number of tables is quite big on purpose (a normal big application | |
130 | has less than 1000 classes), so that you shouldn't normally get any | |
131 | collisions, and get away with a single comparison (which we can't | |
132 | avoid since we need to know that you have got the right thing). */ | |
133 | #define CLASS_TABLE_SIZE 1024 | |
134 | #define CLASS_TABLE_MASK 1023 | |
135 | ||
136 | static class_node_ptr class_table_array[CLASS_TABLE_SIZE]; | |
137 | ||
138 | /* The table writing mutex - we lock on writing to avoid conflicts | |
139 | between different writers, but we read without locks. That is | |
140 | possible because we assume pointer assignment to be an atomic | |
debfbfee NP |
141 | operation. TODO: This is only true under certain circumstances, |
142 | which should be clarified. */ | |
2726bdba NP |
143 | static objc_mutex_t __class_table_lock = NULL; |
144 | ||
145 | /* CLASS_TABLE_HASH is how we compute the hash of a class name. It is | |
575584a9 | 146 | a macro - *not* a function - arguments *are* modified directly. |
2726bdba NP |
147 | |
148 | INDEX should be a variable holding an int; | |
149 | HASH should be a variable holding an int; | |
150 | CLASS_NAME should be a variable holding a (char *) to the class_name. | |
151 | ||
152 | After the macro is executed, INDEX contains the length of the | |
153 | string, and HASH the computed hash of the string; CLASS_NAME is | |
154 | untouched. */ | |
155 | ||
7f339ecb TV |
156 | #define CLASS_TABLE_HASH(INDEX, HASH, CLASS_NAME) \ |
157 | do { \ | |
158 | HASH = 0; \ | |
159 | for (INDEX = 0; CLASS_NAME[INDEX] != '\0'; INDEX++) \ | |
160 | { \ | |
161 | HASH = (HASH << 4) ^ (HASH >> 28) ^ CLASS_NAME[INDEX]; \ | |
162 | } \ | |
163 | \ | |
164 | HASH = (HASH ^ (HASH >> 10) ^ (HASH >> 20)) & CLASS_TABLE_MASK; \ | |
165 | } while (0) | |
2726bdba NP |
166 | |
167 | /* Setup the table. */ | |
168 | static void | |
8f8c44cb | 169 | class_table_setup (void) |
2726bdba NP |
170 | { |
171 | /* Start - nothing in the table. */ | |
40165636 | 172 | memset (class_table_array, 0, sizeof (class_node_ptr) * CLASS_TABLE_SIZE); |
2726bdba NP |
173 | |
174 | /* The table writing mutex. */ | |
175 | __class_table_lock = objc_mutex_allocate (); | |
176 | } | |
177 | ||
178 | ||
575584a9 NP |
179 | /* Insert a class in the table (used when a new class is |
180 | registered). */ | |
2726bdba NP |
181 | static void |
182 | class_table_insert (const char *class_name, Class class_pointer) | |
183 | { | |
184 | int hash, length; | |
185 | class_node_ptr new_node; | |
186 | ||
187 | /* Find out the class name's hash and length. */ | |
188 | CLASS_TABLE_HASH (length, hash, class_name); | |
189 | ||
190 | /* Prepare the new node holding the class. */ | |
191 | new_node = objc_malloc (sizeof (struct class_node)); | |
192 | new_node->name = class_name; | |
193 | new_node->length = length; | |
194 | new_node->pointer = class_pointer; | |
195 | ||
196 | /* Lock the table for modifications. */ | |
197 | objc_mutex_lock (__class_table_lock); | |
198 | ||
199 | /* Insert the new node in the table at the beginning of the table at | |
200 | class_table_array[hash]. */ | |
201 | new_node->next = class_table_array[hash]; | |
202 | class_table_array[hash] = new_node; | |
203 | ||
204 | objc_mutex_unlock (__class_table_lock); | |
205 | } | |
206 | ||
2726bdba NP |
207 | /* Get a class from the table. This does not need mutex protection. |
208 | Currently, this function is called each time you call a static | |
209 | method, this is why it must be very fast. */ | |
210 | static inline Class | |
211 | class_table_get_safe (const char *class_name) | |
212 | { | |
213 | class_node_ptr node; | |
214 | int length, hash; | |
215 | ||
216 | /* Compute length and hash. */ | |
217 | CLASS_TABLE_HASH (length, hash, class_name); | |
218 | ||
219 | node = class_table_array[hash]; | |
220 | ||
221 | if (node != NULL) | |
222 | { | |
223 | do | |
224 | { | |
225 | if (node->length == length) | |
226 | { | |
227 | /* Compare the class names. */ | |
228 | int i; | |
229 | ||
230 | for (i = 0; i < length; i++) | |
231 | { | |
232 | if ((node->name)[i] != class_name[i]) | |
575584a9 | 233 | break; |
2726bdba NP |
234 | } |
235 | ||
236 | if (i == length) | |
237 | { | |
238 | /* They are equal! */ | |
239 | return node->pointer; | |
240 | } | |
241 | } | |
242 | } | |
243 | while ((node = node->next) != NULL); | |
244 | } | |
245 | ||
246 | return Nil; | |
247 | } | |
248 | ||
249 | /* Enumerate over the class table. */ | |
250 | struct class_table_enumerator | |
251 | { | |
252 | int hash; | |
253 | class_node_ptr node; | |
254 | }; | |
255 | ||
256 | ||
257 | static Class | |
258 | class_table_next (struct class_table_enumerator **e) | |
259 | { | |
260 | struct class_table_enumerator *enumerator = *e; | |
261 | class_node_ptr next; | |
262 | ||
263 | if (enumerator == NULL) | |
264 | { | |
265 | *e = objc_malloc (sizeof (struct class_table_enumerator)); | |
266 | enumerator = *e; | |
267 | enumerator->hash = 0; | |
268 | enumerator->node = NULL; | |
269 | ||
270 | next = class_table_array[enumerator->hash]; | |
271 | } | |
272 | else | |
575584a9 | 273 | next = enumerator->node->next; |
2726bdba NP |
274 | |
275 | if (next != NULL) | |
276 | { | |
277 | enumerator->node = next; | |
278 | return enumerator->node->pointer; | |
279 | } | |
280 | else | |
281 | { | |
282 | enumerator->hash++; | |
283 | ||
284 | while (enumerator->hash < CLASS_TABLE_SIZE) | |
285 | { | |
286 | next = class_table_array[enumerator->hash]; | |
287 | if (next != NULL) | |
288 | { | |
289 | enumerator->node = next; | |
290 | return enumerator->node->pointer; | |
291 | } | |
292 | enumerator->hash++; | |
293 | } | |
294 | ||
295 | /* Ok - table finished - done. */ | |
296 | objc_free (enumerator); | |
297 | return Nil; | |
298 | } | |
299 | } | |
300 | ||
301 | #if 0 /* DEBUGGING FUNCTIONS */ | |
302 | /* Debugging function - print the class table. */ | |
303 | void | |
40165636 | 304 | class_table_print (void) |
2726bdba NP |
305 | { |
306 | int i; | |
307 | ||
308 | for (i = 0; i < CLASS_TABLE_SIZE; i++) | |
309 | { | |
310 | class_node_ptr node; | |
311 | ||
312 | printf ("%d:\n", i); | |
313 | node = class_table_array[i]; | |
314 | ||
315 | while (node != NULL) | |
316 | { | |
317 | printf ("\t%s\n", node->name); | |
318 | node = node->next; | |
319 | } | |
320 | } | |
321 | } | |
322 | ||
323 | /* Debugging function - print an histogram of number of classes in | |
324 | function of hash key values. Useful to evaluate the hash function | |
325 | in real cases. */ | |
326 | void | |
40165636 | 327 | class_table_print_histogram (void) |
2726bdba NP |
328 | { |
329 | int i, j; | |
330 | int counter = 0; | |
331 | ||
332 | for (i = 0; i < CLASS_TABLE_SIZE; i++) | |
333 | { | |
334 | class_node_ptr node; | |
335 | ||
336 | node = class_table_array[i]; | |
337 | ||
338 | while (node != NULL) | |
339 | { | |
340 | counter++; | |
341 | node = node->next; | |
342 | } | |
343 | if (((i + 1) % 50) == 0) | |
344 | { | |
345 | printf ("%4d:", i + 1); | |
346 | for (j = 0; j < counter; j++) | |
575584a9 NP |
347 | printf ("X"); |
348 | ||
2726bdba NP |
349 | printf ("\n"); |
350 | counter = 0; | |
351 | } | |
352 | } | |
353 | printf ("%4d:", i + 1); | |
354 | for (j = 0; j < counter; j++) | |
575584a9 NP |
355 | printf ("X"); |
356 | ||
2726bdba NP |
357 | printf ("\n"); |
358 | } | |
359 | #endif /* DEBUGGING FUNCTIONS */ | |
360 | ||
361 | /** | |
362 | ** Objective-C runtime functions | |
363 | **/ | |
364 | ||
365 | /* From now on, the only access to the class table data structure | |
366 | should be via the class_table_* functions. */ | |
367 | ||
368 | /* This is a hook which is called by objc_get_class and | |
575584a9 | 369 | objc_lookup_class if the runtime is not able to find the class. |
90a2689f NP |
370 | This may e.g. try to load in the class using dynamic loading. |
371 | ||
372 | This hook was a public, global variable in the Traditional GNU | |
373 | Objective-C Runtime API (objc/objc-api.h). The modern GNU | |
374 | Objective-C Runtime API (objc/runtime.h) provides the | |
375 | objc_setGetUnknownClassHandler() function instead. | |
376 | */ | |
40165636 | 377 | Class (*_objc_lookup_class) (const char *name) = 0; /* !T:SAFE */ |
88e17b57 | 378 | |
90a2689f NP |
379 | /* The handler currently in use. PS: if both |
380 | __obj_get_unknown_class_handler and _objc_lookup_class are defined, | |
381 | __objc_get_unknown_class_handler is called first. */ | |
382 | static objc_get_unknown_class_handler | |
383 | __objc_get_unknown_class_handler = NULL; | |
384 | ||
385 | objc_get_unknown_class_handler | |
386 | objc_setGetUnknownClassHandler (objc_get_unknown_class_handler | |
387 | new_handler) | |
388 | { | |
389 | objc_get_unknown_class_handler old_handler | |
390 | = __objc_get_unknown_class_handler; | |
391 | __objc_get_unknown_class_handler = new_handler; | |
392 | return old_handler; | |
393 | } | |
394 | ||
88e17b57 | 395 | |
2726bdba | 396 | /* True when class links has been resolved. */ |
88e17b57 BE |
397 | BOOL __objc_class_links_resolved = NO; /* !T:UNUSED */ |
398 | ||
399 | ||
40165636 RB |
400 | void |
401 | __objc_init_class_tables (void) | |
88e17b57 | 402 | { |
2726bdba NP |
403 | /* Allocate the class hash table. */ |
404 | ||
40165636 | 405 | if (__class_table_lock) |
88e17b57 | 406 | return; |
2726bdba | 407 | |
40165636 | 408 | objc_mutex_lock (__objc_runtime_mutex); |
2726bdba NP |
409 | |
410 | class_table_setup (); | |
88e17b57 | 411 | |
40165636 | 412 | objc_mutex_unlock (__objc_runtime_mutex); |
88e17b57 BE |
413 | } |
414 | ||
2726bdba | 415 | /* This function adds a class to the class hash table, and assigns the |
1575c9de NP |
416 | class a number, unless it's already known. Return 'YES' if the |
417 | class was added. Return 'NO' if the class was already known. */ | |
418 | BOOL | |
40165636 | 419 | __objc_add_class_to_hash (Class class) |
88e17b57 | 420 | { |
1575c9de | 421 | Class existing_class; |
88e17b57 | 422 | |
40165636 | 423 | objc_mutex_lock (__objc_runtime_mutex); |
88e17b57 | 424 | |
2726bdba | 425 | /* Make sure the table is there. */ |
40165636 | 426 | assert (__class_table_lock); |
88e17b57 | 427 | |
2726bdba | 428 | /* Make sure it's not a meta class. */ |
40165636 | 429 | assert (CLS_ISCLASS (class)); |
88e17b57 BE |
430 | |
431 | /* Check to see if the class is already in the hash table. */ | |
1575c9de NP |
432 | existing_class = class_table_get_safe (class->name); |
433 | ||
434 | if (existing_class) | |
435 | { | |
436 | objc_mutex_unlock (__objc_runtime_mutex); | |
437 | return NO; | |
438 | } | |
439 | else | |
88e17b57 | 440 | { |
1575c9de NP |
441 | /* The class isn't in the hash table. Add the class and assign |
442 | a class number. */ | |
88e17b57 | 443 | static unsigned int class_number = 1; |
1575c9de | 444 | |
40165636 RB |
445 | CLS_SETNUMBER (class, class_number); |
446 | CLS_SETNUMBER (class->class_pointer, class_number); | |
88e17b57 BE |
447 | |
448 | ++class_number; | |
2726bdba | 449 | class_table_insert (class->name, class); |
88e17b57 | 450 | |
1575c9de NP |
451 | objc_mutex_unlock (__objc_runtime_mutex); |
452 | return YES; | |
453 | } | |
88e17b57 BE |
454 | } |
455 | ||
40165636 | 456 | Class |
90a2689f | 457 | objc_getClass (const char *name) |
88e17b57 BE |
458 | { |
459 | Class class; | |
460 | ||
90a2689f NP |
461 | if (name == NULL) |
462 | return Nil; | |
88e17b57 | 463 | |
90a2689f NP |
464 | class = class_table_get_safe (name); |
465 | ||
88e17b57 BE |
466 | if (class) |
467 | return class; | |
1cde73d7 | 468 | |
90a2689f NP |
469 | if (__objc_get_unknown_class_handler) |
470 | return (*__objc_get_unknown_class_handler) (name); | |
88e17b57 BE |
471 | |
472 | if (_objc_lookup_class) | |
40165636 | 473 | return (*_objc_lookup_class) (name); |
90a2689f NP |
474 | |
475 | return Nil; | |
476 | } | |
477 | ||
478 | Class | |
6e45b376 | 479 | objc_lookUpClass (const char *name) |
90a2689f NP |
480 | { |
481 | if (name == NULL) | |
482 | return Nil; | |
483 | else | |
484 | return class_table_get_safe (name); | |
485 | } | |
486 | ||
487 | Class | |
488 | objc_getMetaClass (const char *name) | |
489 | { | |
490 | Class class = objc_getClass (name); | |
491 | ||
492 | if (class) | |
493 | return class->class_pointer; | |
88e17b57 | 494 | else |
90a2689f | 495 | return Nil; |
88e17b57 BE |
496 | } |
497 | ||
90a2689f NP |
498 | Class |
499 | objc_getRequiredClass (const char *name) | |
500 | { | |
501 | Class class = objc_getClass (name); | |
502 | ||
503 | if (class) | |
504 | return class; | |
505 | else | |
506 | _objc_abort ("objc_getRequiredClass ('%s') failed: class not found\n", name); | |
507 | } | |
508 | ||
509 | int | |
510 | objc_getClassList (Class *returnValue, int maxNumberOfClassesToReturn) | |
511 | { | |
512 | /* Iterate over all entries in the table. */ | |
513 | int hash, count = 0; | |
514 | ||
90a2689f NP |
515 | for (hash = 0; hash < CLASS_TABLE_SIZE; hash++) |
516 | { | |
517 | class_node_ptr node = class_table_array[hash]; | |
518 | ||
519 | while (node != NULL) | |
520 | { | |
521 | if (returnValue) | |
522 | { | |
523 | if (count < maxNumberOfClassesToReturn) | |
524 | returnValue[count] = node->pointer; | |
525 | else | |
575584a9 | 526 | return count; |
90a2689f NP |
527 | } |
528 | count++; | |
529 | node = node->next; | |
530 | } | |
531 | } | |
532 | ||
90a2689f NP |
533 | return count; |
534 | } | |
535 | ||
6c5c7efd NP |
536 | Class |
537 | objc_allocateClassPair (Class super_class, const char *class_name, size_t extraBytes) | |
538 | { | |
539 | Class new_class; | |
540 | Class new_meta_class; | |
541 | ||
542 | if (class_name == NULL) | |
543 | return Nil; | |
544 | ||
545 | if (objc_getClass (class_name)) | |
546 | return Nil; | |
547 | ||
548 | if (super_class) | |
549 | { | |
550 | /* If you want to build a hierarchy of classes, you need to | |
551 | build and register them one at a time. The risk is that you | |
552 | are able to cause confusion by registering a subclass before | |
553 | the superclass or similar. */ | |
554 | if (CLS_IS_IN_CONSTRUCTION (super_class)) | |
555 | return Nil; | |
556 | } | |
557 | ||
558 | /* Technically, we should create the metaclass first, then use | |
559 | class_createInstance() to create the class. That complication | |
560 | would be relevant if we had class variables, but we don't, so we | |
561 | just ignore it and create everything directly and assume all | |
562 | classes have the same size. */ | |
563 | new_class = objc_calloc (1, sizeof (struct objc_class) + extraBytes); | |
564 | new_meta_class = objc_calloc (1, sizeof (struct objc_class) + extraBytes); | |
565 | ||
566 | /* We create an unresolved class, similar to one generated by the | |
567 | compiler. It will be resolved later when we register it. | |
568 | ||
569 | Note how the metaclass details are not that important; when the | |
570 | class is resolved, the ones that matter will be fixed up. */ | |
571 | new_class->class_pointer = new_meta_class; | |
572 | new_meta_class->class_pointer = 0; | |
573 | ||
574 | if (super_class) | |
575 | { | |
576 | /* Force the name of the superclass in place of the link to the | |
577 | actual superclass, which will be put there when the class is | |
578 | resolved. */ | |
579 | const char *super_class_name = class_getName (super_class); | |
580 | new_class->super_class = (void *)super_class_name; | |
581 | new_meta_class->super_class = (void *)super_class_name; | |
582 | } | |
583 | else | |
584 | { | |
585 | new_class->super_class = (void *)0; | |
586 | new_meta_class->super_class = (void *)0; | |
587 | } | |
588 | ||
589 | new_class->name = objc_malloc (strlen (class_name) + 1); | |
590 | strcpy ((char*)new_class->name, class_name); | |
591 | new_meta_class->name = new_class->name; | |
592 | ||
593 | new_class->version = 0; | |
594 | new_meta_class->version = 0; | |
595 | ||
596 | new_class->info = _CLS_CLASS | _CLS_IN_CONSTRUCTION; | |
597 | new_meta_class->info = _CLS_META | _CLS_IN_CONSTRUCTION; | |
598 | ||
599 | if (super_class) | |
600 | new_class->instance_size = super_class->instance_size; | |
601 | else | |
602 | new_class->instance_size = 0; | |
603 | new_meta_class->instance_size = sizeof (struct objc_class); | |
604 | ||
605 | return new_class; | |
606 | } | |
607 | ||
608 | void | |
609 | objc_registerClassPair (Class class_) | |
610 | { | |
611 | if (class_ == Nil) | |
612 | return; | |
613 | ||
614 | if ((! CLS_ISCLASS (class_)) || (! CLS_IS_IN_CONSTRUCTION (class_))) | |
615 | return; | |
616 | ||
617 | if ((! CLS_ISMETA (class_->class_pointer)) || (! CLS_IS_IN_CONSTRUCTION (class_->class_pointer))) | |
618 | return; | |
619 | ||
620 | objc_mutex_lock (__objc_runtime_mutex); | |
621 | ||
622 | if (objc_getClass (class_->name)) | |
623 | { | |
624 | objc_mutex_unlock (__objc_runtime_mutex); | |
625 | return; | |
626 | } | |
627 | ||
628 | CLS_SET_NOT_IN_CONSTRUCTION (class_); | |
629 | CLS_SET_NOT_IN_CONSTRUCTION (class_->class_pointer); | |
630 | ||
631 | __objc_init_class (class_); | |
632 | ||
633 | /* Resolve class links immediately. No point in waiting. */ | |
634 | __objc_resolve_class_links (); | |
635 | ||
636 | objc_mutex_unlock (__objc_runtime_mutex); | |
637 | } | |
638 | ||
639 | void | |
640 | objc_disposeClassPair (Class class_) | |
641 | { | |
642 | if (class_ == Nil) | |
643 | return; | |
644 | ||
645 | if ((! CLS_ISCLASS (class_)) || (! CLS_IS_IN_CONSTRUCTION (class_))) | |
646 | return; | |
647 | ||
648 | if ((! CLS_ISMETA (class_->class_pointer)) || (! CLS_IS_IN_CONSTRUCTION (class_->class_pointer))) | |
649 | return; | |
650 | ||
651 | /* Undo any class_addIvar(). */ | |
652 | if (class_->ivars) | |
653 | { | |
654 | int i; | |
655 | for (i = 0; i < class_->ivars->ivar_count; i++) | |
656 | { | |
657 | struct objc_ivar *ivar = &(class_->ivars->ivar_list[i]); | |
658 | ||
659 | objc_free ((char *)ivar->ivar_name); | |
660 | objc_free ((char *)ivar->ivar_type); | |
661 | } | |
662 | ||
663 | objc_free (class_->ivars); | |
664 | } | |
665 | ||
666 | /* Undo any class_addMethod(). */ | |
667 | if (class_->methods) | |
668 | { | |
669 | struct objc_method_list *list = class_->methods; | |
670 | while (list) | |
671 | { | |
672 | int i; | |
673 | struct objc_method_list *next = list->method_next; | |
674 | ||
675 | for (i = 0; i < list->method_count; i++) | |
676 | { | |
677 | struct objc_method *method = &(list->method_list[i]); | |
678 | ||
679 | objc_free ((char *)method->method_name); | |
680 | objc_free ((char *)method->method_types); | |
681 | } | |
682 | ||
683 | objc_free (list); | |
684 | list = next; | |
685 | } | |
686 | } | |
687 | ||
688 | /* Undo any class_addProtocol(). */ | |
689 | if (class_->protocols) | |
690 | { | |
691 | struct objc_protocol_list *list = class_->protocols; | |
692 | while (list) | |
693 | { | |
694 | struct objc_protocol_list *next = list->next; | |
695 | ||
696 | objc_free (list); | |
697 | list = next; | |
698 | } | |
699 | } | |
700 | ||
701 | /* Undo any class_addMethod() on the meta-class. */ | |
702 | if (class_->class_pointer->methods) | |
703 | { | |
704 | struct objc_method_list *list = class_->class_pointer->methods; | |
705 | while (list) | |
706 | { | |
707 | int i; | |
708 | struct objc_method_list *next = list->method_next; | |
709 | ||
710 | for (i = 0; i < list->method_count; i++) | |
711 | { | |
712 | struct objc_method *method = &(list->method_list[i]); | |
713 | ||
714 | objc_free ((char *)method->method_name); | |
715 | objc_free ((char *)method->method_types); | |
716 | } | |
717 | ||
718 | objc_free (list); | |
719 | list = next; | |
720 | } | |
721 | } | |
722 | ||
723 | /* Undo objc_allocateClassPair(). */ | |
724 | objc_free ((char *)(class_->name)); | |
725 | objc_free (class_->class_pointer); | |
726 | objc_free (class_); | |
727 | } | |
728 | ||
90a2689f NP |
729 | /* Traditional GNU Objective-C Runtime API. Important: this method is |
730 | called automatically by the compiler while messaging (if using the | |
731 | traditional ABI), so it is worth keeping it fast; don't make it | |
732 | just a wrapper around objc_getClass(). */ | |
be05b0f5 | 733 | /* Note that this is roughly equivalent to objc_getRequiredClass(). */ |
88e17b57 BE |
734 | /* Get the class object for the class named NAME. If NAME does not |
735 | identify a known class, the hook _objc_lookup_class is called. If | |
2726bdba | 736 | this fails, an error message is issued and the system aborts. */ |
88e17b57 BE |
737 | Class |
738 | objc_get_class (const char *name) | |
739 | { | |
740 | Class class; | |
741 | ||
2726bdba | 742 | class = class_table_get_safe (name); |
88e17b57 BE |
743 | |
744 | if (class) | |
745 | return class; | |
746 | ||
90a2689f NP |
747 | if (__objc_get_unknown_class_handler) |
748 | class = (*__objc_get_unknown_class_handler) (name); | |
749 | ||
750 | if ((!class) && _objc_lookup_class) | |
40165636 | 751 | class = (*_objc_lookup_class) (name); |
88e17b57 | 752 | |
40165636 | 753 | if (class) |
88e17b57 BE |
754 | return class; |
755 | ||
7b869986 NP |
756 | _objc_abort ("objc runtime: cannot find class %s\n", name); |
757 | ||
88e17b57 BE |
758 | return 0; |
759 | } | |
760 | ||
69c32980 | 761 | /* This is used by the compiler too. */ |
80e4b9e5 | 762 | Class |
40165636 | 763 | objc_get_meta_class (const char *name) |
88e17b57 | 764 | { |
40165636 | 765 | return objc_get_class (name)->class_pointer; |
88e17b57 BE |
766 | } |
767 | ||
b4a50e43 | 768 | /* This is not used by GCC, but the clang compiler seems to use it |
cad10e05 | 769 | when targeting the GNU runtime. That's wrong, but we have it to |
b4a50e43 NP |
770 | be compatible. */ |
771 | Class | |
772 | objc_lookup_class (const char *name) | |
773 | { | |
774 | return objc_getClass (name); | |
775 | } | |
776 | ||
51194e8e NP |
777 | /* This is used when the implementation of a method changes. It goes |
778 | through all classes, looking for the ones that have these methods | |
779 | (either method_a or method_b; method_b can be NULL), and reloads | |
780 | the implementation for these. You should call this with the | |
781 | runtime mutex already locked. */ | |
782 | void | |
783 | __objc_update_classes_with_methods (struct objc_method *method_a, struct objc_method *method_b) | |
784 | { | |
785 | int hash; | |
786 | ||
787 | /* Iterate over all classes. */ | |
788 | for (hash = 0; hash < CLASS_TABLE_SIZE; hash++) | |
789 | { | |
790 | class_node_ptr node = class_table_array[hash]; | |
791 | ||
792 | while (node != NULL) | |
793 | { | |
0e0677a2 NP |
794 | /* We execute this loop twice: the first time, we iterate |
795 | over all methods in the class (instance methods), while | |
796 | the second time we iterate over all methods in the meta | |
797 | class (class methods). */ | |
798 | Class class = Nil; | |
799 | BOOL done = NO; | |
800 | ||
801 | while (done == NO) | |
51194e8e | 802 | { |
0e0677a2 | 803 | struct objc_method_list * method_list; |
51194e8e | 804 | |
0e0677a2 NP |
805 | if (class == Nil) |
806 | { | |
807 | /* The first time, we work on the class. */ | |
808 | class = node->pointer; | |
809 | } | |
810 | else | |
51194e8e | 811 | { |
0e0677a2 NP |
812 | /* The second time, we work on the meta class. */ |
813 | class = class->class_pointer; | |
814 | done = YES; | |
815 | } | |
51194e8e | 816 | |
0e0677a2 | 817 | method_list = class->methods; |
51194e8e | 818 | |
0e0677a2 NP |
819 | while (method_list) |
820 | { | |
821 | int i; | |
822 | ||
823 | for (i = 0; i < method_list->method_count; ++i) | |
51194e8e | 824 | { |
0e0677a2 NP |
825 | struct objc_method *method = &method_list->method_list[i]; |
826 | ||
827 | /* If the method is one of the ones we are | |
828 | looking for, update the implementation. */ | |
829 | if (method == method_a) | |
575584a9 | 830 | sarray_at_put_safe (class->dtable, |
0e0677a2 NP |
831 | (sidx) method_a->method_name->sel_id, |
832 | method_a->method_imp); | |
833 | ||
834 | if (method == method_b) | |
835 | { | |
836 | if (method_b != NULL) | |
837 | sarray_at_put_safe (class->dtable, | |
838 | (sidx) method_b->method_name->sel_id, | |
839 | method_b->method_imp); | |
840 | } | |
51194e8e | 841 | } |
0e0677a2 NP |
842 | |
843 | method_list = method_list->method_next; | |
51194e8e | 844 | } |
51194e8e NP |
845 | } |
846 | node = node->next; | |
847 | } | |
848 | } | |
849 | } | |
850 | ||
2726bdba NP |
851 | /* Resolve super/subclass links for all classes. The only thing we |
852 | can be sure of is that the class_pointer for class objects point to | |
853 | the right meta class objects. */ | |
40165636 RB |
854 | void |
855 | __objc_resolve_class_links (void) | |
88e17b57 | 856 | { |
2726bdba | 857 | struct class_table_enumerator *es = NULL; |
88e17b57 | 858 | Class object_class = objc_get_class ("Object"); |
2726bdba | 859 | Class class1; |
88e17b57 | 860 | |
40165636 | 861 | assert (object_class); |
88e17b57 | 862 | |
40165636 | 863 | objc_mutex_lock (__objc_runtime_mutex); |
88e17b57 | 864 | |
2726bdba NP |
865 | /* Assign subclass links. */ |
866 | while ((class1 = class_table_next (&es))) | |
88e17b57 | 867 | { |
88e17b57 | 868 | /* Make sure we have what we think we have. */ |
40165636 RB |
869 | assert (CLS_ISCLASS (class1)); |
870 | assert (CLS_ISMETA (class1->class_pointer)); | |
88e17b57 | 871 | |
2726bdba NP |
872 | /* The class_pointer of all meta classes point to Object's meta |
873 | class. */ | |
88e17b57 BE |
874 | class1->class_pointer->class_pointer = object_class->class_pointer; |
875 | ||
40165636 | 876 | if (! CLS_ISRESOLV (class1)) |
88e17b57 | 877 | { |
40165636 RB |
878 | CLS_SETRESOLV (class1); |
879 | CLS_SETRESOLV (class1->class_pointer); | |
88e17b57 | 880 | |
40165636 | 881 | if (class1->super_class) |
88e17b57 BE |
882 | { |
883 | Class a_super_class | |
884 | = objc_get_class ((char *) class1->super_class); | |
885 | ||
886 | assert (a_super_class); | |
887 | ||
888 | DEBUG_PRINTF ("making class connections for: %s\n", | |
889 | class1->name); | |
890 | ||
2726bdba | 891 | /* Assign subclass links for superclass. */ |
88e17b57 BE |
892 | class1->sibling_class = a_super_class->subclass_list; |
893 | a_super_class->subclass_list = class1; | |
894 | ||
2726bdba | 895 | /* Assign subclass links for meta class of superclass. */ |
88e17b57 BE |
896 | if (a_super_class->class_pointer) |
897 | { | |
898 | class1->class_pointer->sibling_class | |
899 | = a_super_class->class_pointer->subclass_list; | |
900 | a_super_class->class_pointer->subclass_list | |
901 | = class1->class_pointer; | |
902 | } | |
903 | } | |
2726bdba NP |
904 | else /* A root class, make its meta object be a subclass of |
905 | Object. */ | |
88e17b57 BE |
906 | { |
907 | class1->class_pointer->sibling_class | |
908 | = object_class->subclass_list; | |
909 | object_class->subclass_list = class1->class_pointer; | |
910 | } | |
911 | } | |
912 | } | |
913 | ||
2726bdba NP |
914 | /* Assign superclass links. */ |
915 | es = NULL; | |
916 | while ((class1 = class_table_next (&es))) | |
88e17b57 | 917 | { |
88e17b57 BE |
918 | Class sub_class; |
919 | for (sub_class = class1->subclass_list; sub_class; | |
920 | sub_class = sub_class->sibling_class) | |
921 | { | |
922 | sub_class->super_class = class1; | |
40165636 | 923 | if (CLS_ISCLASS (sub_class)) |
88e17b57 BE |
924 | sub_class->class_pointer->super_class = class1->class_pointer; |
925 | } | |
926 | } | |
927 | ||
40165636 | 928 | objc_mutex_unlock (__objc_runtime_mutex); |
88e17b57 BE |
929 | } |
930 | ||
debfbfee NP |
931 | const char * |
932 | class_getName (Class class_) | |
933 | { | |
934 | if (class_ == Nil) | |
935 | return "nil"; | |
88e17b57 | 936 | |
debfbfee NP |
937 | return class_->name; |
938 | } | |
88e17b57 | 939 | |
be05b0f5 NP |
940 | BOOL |
941 | class_isMetaClass (Class class_) | |
942 | { | |
943 | /* CLS_ISMETA includes the check for Nil class_. */ | |
944 | return CLS_ISMETA (class_); | |
945 | } | |
946 | ||
1cde73d7 NP |
947 | /* Even inside libobjc it may be worth using class_getSuperclass |
948 | instead of accessing class_->super_class directly because it | |
949 | resolves the class links if needed. If you access | |
950 | class_->super_class directly, make sure to deal with the situation | |
951 | where the class is not resolved yet! */ | |
be05b0f5 NP |
952 | Class |
953 | class_getSuperclass (Class class_) | |
954 | { | |
955 | if (class_ == Nil) | |
956 | return Nil; | |
957 | ||
3f542037 NP |
958 | /* Classes that are in construction are not resolved, and still have |
959 | the class name (instead of a class pointer) in the | |
e2852612 | 960 | class_->super_class field. In that case we need to lookup the |
67914693 | 961 | superclass name to return the superclass. We cannot resolve the |
3f542037 | 962 | class until it is registered. */ |
6c5c7efd | 963 | if (CLS_IS_IN_CONSTRUCTION (class_)) |
0e0677a2 NP |
964 | { |
965 | if (CLS_ISMETA (class_)) | |
966 | return object_getClass ((id)objc_lookUpClass ((const char *)(class_->super_class))); | |
967 | else | |
968 | return objc_lookUpClass ((const char *)(class_->super_class)); | |
969 | } | |
6c5c7efd | 970 | |
1cde73d7 NP |
971 | /* If the class is not resolved yet, super_class would point to a |
972 | string (the name of the super class) as opposed to the actual | |
973 | super class. In that case, we need to resolve the class links | |
974 | before we can return super_class. */ | |
975 | if (! CLS_ISRESOLV (class_)) | |
976 | __objc_resolve_class_links (); | |
977 | ||
be05b0f5 NP |
978 | return class_->super_class; |
979 | } | |
980 | ||
981 | int | |
982 | class_getVersion (Class class_) | |
983 | { | |
984 | if (class_ == Nil) | |
985 | return 0; | |
986 | ||
987 | return (int)(class_->version); | |
988 | } | |
989 | ||
990 | void | |
991 | class_setVersion (Class class_, int version) | |
992 | { | |
993 | if (class_ == Nil) | |
994 | return; | |
995 | ||
996 | class_->version = version; | |
997 | } | |
998 | ||
999 | size_t | |
1000 | class_getInstanceSize (Class class_) | |
1001 | { | |
1002 | if (class_ == Nil) | |
1003 | return 0; | |
1004 | ||
1005 | return class_->instance_size; | |
1006 | } | |
1007 |