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