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