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