]> git.ipfire.org Git - thirdparty/gcc.git/blame - libobjc/class.c
* config/avr/avr.h (PREFERRED_RELOAD_CLASS): Remove.
[thirdparty/gcc.git] / libobjc / class.c
CommitLineData
8a7d0ecc 1/* GNU Objective C Runtime class related functions
6bc9506f 2 Copyright (C) 1993, 1995, 1996, 1997, 2001, 2002, 2009
61776355 3 Free Software Foundation, Inc.
8a7d0ecc 4 Contributed by Kresten Krab Thorup and Dennis Glatting.
5
12e22ea5 6 Lock-free class table code designed and written from scratch by
7 Nicola Pero, 2001.
8
893d9197 9This file is part of GCC.
8a7d0ecc 10
893d9197 11GCC is free software; you can redistribute it and/or modify it under the
8a7d0ecc 12terms of the GNU General Public License as published by the Free Software
6bc9506f 13Foundation; either version 3, or (at your option) any later version.
8a7d0ecc 14
893d9197 15GCC is distributed in the hope that it will be useful, but WITHOUT ANY
8a7d0ecc 16WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18details.
19
6bc9506f 20Under Section 7 of GPL version 3, you are granted additional
21permissions described in the GCC Runtime Library Exception, version
223.1, as published by the Free Software Foundation.
8a7d0ecc 23
6bc9506f 24You should have received a copy of the GNU General Public License and
25a copy of the GCC Runtime Library Exception along with this program;
26see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
27<http://www.gnu.org/licenses/>. */
8a7d0ecc 28
12e22ea5 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
e58aa1bc 90#include "objc-private/common.h"
c3a945cd 91#include "objc-private/error.h"
f75aa158 92#include "objc/runtime.h"
2386cda7 93#include "objc/thr.h"
f75aa158 94#include "objc-private/module-abi-8.h" /* For CLS_ISCLASS and similar. */
95#include "objc-private/runtime.h" /* the kitchen sink */
cd9fd8f4 96#include "objc-private/sarray.h" /* For sarray_put_at_safe. */
f75aa158 97#include <string.h> /* For memset */
12e22ea5 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 */
111typedef 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
138static 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
e983fc72 143 operation. TODO: This is only true under certain circumstances,
144 which should be clarified. */
12e22ea5 145static 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. */
168static void
adff42e6 169class_table_setup (void)
12e22ea5 170{
171 /* Start - nothing in the table. */
61776355 172 memset (class_table_array, 0, sizeof (class_node_ptr) * CLASS_TABLE_SIZE);
12e22ea5 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). */
180static void
181class_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:). */
207static void
208class_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 }
8a7d0ecc 239
12e22ea5 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. */
247static inline Class
248class_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. */
289struct class_table_enumerator
290{
291 int hash;
292 class_node_ptr node;
293};
294
295
296static Class
297class_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. */
344void
61776355 345class_table_print (void)
12e22ea5 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. */
367void
61776355 368class_table_print_histogram (void)
12e22ea5 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.
86bde516 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*/
61776355 420Class (*_objc_lookup_class) (const char *name) = 0; /* !T:SAFE */
8a7d0ecc 421
86bde516 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. */
425static objc_get_unknown_class_handler
426__objc_get_unknown_class_handler = NULL;
427
428objc_get_unknown_class_handler
429objc_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
8a7d0ecc 438
12e22ea5 439/* True when class links has been resolved. */
8a7d0ecc 440BOOL __objc_class_links_resolved = NO; /* !T:UNUSED */
441
442
61776355 443void
444__objc_init_class_tables (void)
8a7d0ecc 445{
12e22ea5 446 /* Allocate the class hash table. */
447
61776355 448 if (__class_table_lock)
8a7d0ecc 449 return;
12e22ea5 450
61776355 451 objc_mutex_lock (__objc_runtime_mutex);
12e22ea5 452
453 class_table_setup ();
8a7d0ecc 454
61776355 455 objc_mutex_unlock (__objc_runtime_mutex);
8a7d0ecc 456}
457
12e22ea5 458/* This function adds a class to the class hash table, and assigns the
459 class a number, unless it's already known. */
8a7d0ecc 460void
61776355 461__objc_add_class_to_hash (Class class)
8a7d0ecc 462{
463 Class h_class;
464
61776355 465 objc_mutex_lock (__objc_runtime_mutex);
8a7d0ecc 466
12e22ea5 467 /* Make sure the table is there. */
61776355 468 assert (__class_table_lock);
8a7d0ecc 469
12e22ea5 470 /* Make sure it's not a meta class. */
61776355 471 assert (CLS_ISCLASS (class));
8a7d0ecc 472
473 /* Check to see if the class is already in the hash table. */
12e22ea5 474 h_class = class_table_get_safe (class->name);
61776355 475 if (! h_class)
8a7d0ecc 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
61776355 481 CLS_SETNUMBER (class, class_number);
482 CLS_SETNUMBER (class->class_pointer, class_number);
8a7d0ecc 483
484 ++class_number;
12e22ea5 485 class_table_insert (class->name, class);
8a7d0ecc 486 }
487
61776355 488 objc_mutex_unlock (__objc_runtime_mutex);
8a7d0ecc 489}
490
61776355 491Class
86bde516 492objc_getClass (const char *name)
8a7d0ecc 493{
494 Class class;
495
86bde516 496 if (name == NULL)
497 return Nil;
8a7d0ecc 498
86bde516 499 class = class_table_get_safe (name);
500
8a7d0ecc 501 if (class)
502 return class;
86bde516 503
504 if (__objc_get_unknown_class_handler)
505 return (*__objc_get_unknown_class_handler) (name);
8a7d0ecc 506
507 if (_objc_lookup_class)
61776355 508 return (*_objc_lookup_class) (name);
86bde516 509
510 return Nil;
511}
512
513Class
514objc_lookupClass (const char *name)
515{
516 if (name == NULL)
517 return Nil;
518 else
519 return class_table_get_safe (name);
520}
521
522Class
523objc_getMetaClass (const char *name)
524{
525 Class class = objc_getClass (name);
526
527 if (class)
528 return class->class_pointer;
8a7d0ecc 529 else
86bde516 530 return Nil;
8a7d0ecc 531}
532
86bde516 533Class
534objc_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
544int
545objc_getClassList (Class *returnValue, int maxNumberOfClassesToReturn)
546{
547 /* Iterate over all entries in the table. */
548 int hash, count = 0;
549
86bde516 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 {
86bde516 562 return count;
563 }
564 }
565 count++;
566 node = node->next;
567 }
568 }
569
86bde516 570 return count;
571}
572
573/* Traditional GNU Objective-C Runtime API. */
574/* Get the class object for the class named NAME. If NAME does not
575 identify a known class, the hook _objc_lookup_class is called. If
576 this fails, nil is returned. */
577Class
578objc_lookup_class (const char *name)
579{
580 return objc_getClass (name);
581}
582
583/* Traditional GNU Objective-C Runtime API. Important: this method is
584 called automatically by the compiler while messaging (if using the
585 traditional ABI), so it is worth keeping it fast; don't make it
586 just a wrapper around objc_getClass(). */
f75aa158 587/* Note that this is roughly equivalent to objc_getRequiredClass(). */
8a7d0ecc 588/* Get the class object for the class named NAME. If NAME does not
589 identify a known class, the hook _objc_lookup_class is called. If
12e22ea5 590 this fails, an error message is issued and the system aborts. */
8a7d0ecc 591Class
592objc_get_class (const char *name)
593{
594 Class class;
595
12e22ea5 596 class = class_table_get_safe (name);
8a7d0ecc 597
598 if (class)
599 return class;
600
86bde516 601 if (__objc_get_unknown_class_handler)
602 class = (*__objc_get_unknown_class_handler) (name);
603
604 if ((!class) && _objc_lookup_class)
61776355 605 class = (*_objc_lookup_class) (name);
8a7d0ecc 606
61776355 607 if (class)
8a7d0ecc 608 return class;
609
c3a945cd 610 _objc_abort ("objc runtime: cannot find class %s\n", name);
611
8a7d0ecc 612 return 0;
613}
614
615MetaClass
61776355 616objc_get_meta_class (const char *name)
8a7d0ecc 617{
61776355 618 return objc_get_class (name)->class_pointer;
8a7d0ecc 619}
620
621/* This function provides a way to enumerate all the classes in the
622 executable. Pass *ENUM_STATE == NULL to start the enumeration. The
623 function will return 0 when there are no more classes.
624 For example:
625 id class;
626 void *es = NULL;
61776355 627 while ((class = objc_next_class (&es)))
8a7d0ecc 628 ... do something with class;
629*/
630Class
61776355 631objc_next_class (void **enum_state)
8a7d0ecc 632{
12e22ea5 633 Class class;
8a7d0ecc 634
61776355 635 objc_mutex_lock (__objc_runtime_mutex);
12e22ea5 636
637 /* Make sure the table is there. */
61776355 638 assert (__class_table_lock);
8a7d0ecc 639
61776355 640 class = class_table_next ((struct class_table_enumerator **) enum_state);
8a7d0ecc 641
61776355 642 objc_mutex_unlock (__objc_runtime_mutex);
12e22ea5 643
644 return class;
8a7d0ecc 645}
646
cd9fd8f4 647/* This is used when the implementation of a method changes. It goes
648 through all classes, looking for the ones that have these methods
649 (either method_a or method_b; method_b can be NULL), and reloads
650 the implementation for these. You should call this with the
651 runtime mutex already locked. */
652void
653__objc_update_classes_with_methods (struct objc_method *method_a, struct objc_method *method_b)
654{
655 int hash;
656
657 /* Iterate over all classes. */
658 for (hash = 0; hash < CLASS_TABLE_SIZE; hash++)
659 {
660 class_node_ptr node = class_table_array[hash];
661
662 while (node != NULL)
663 {
664 /* Iterate over all methods in the class. */
665 Class class = node->pointer;
666 struct objc_method_list * method_list = class->methods;
667
668 while (method_list)
669 {
670 int i;
671
672 for (i = 0; i < method_list->method_count; ++i)
673 {
674 struct objc_method *method = &method_list->method_list[i];
675
676 /* If the method is one of the ones we are looking
677 for, update the implementation. */
678 if (method == method_a)
679 {
680 sarray_at_put_safe (class->dtable,
681 (sidx) method_a->method_name->sel_id,
682 method_a->method_imp);
683 }
684
685 if (method == method_b)
686 {
687 if (method_b != NULL)
688 {
689 sarray_at_put_safe (class->dtable,
690 (sidx) method_b->method_name->sel_id,
691 method_b->method_imp);
692 }
693 }
694 }
695
696 method_list = method_list->method_next;
697 }
698 node = node->next;
699 }
700 }
701}
702
12e22ea5 703/* Resolve super/subclass links for all classes. The only thing we
704 can be sure of is that the class_pointer for class objects point to
705 the right meta class objects. */
61776355 706void
707__objc_resolve_class_links (void)
8a7d0ecc 708{
12e22ea5 709 struct class_table_enumerator *es = NULL;
8a7d0ecc 710 Class object_class = objc_get_class ("Object");
12e22ea5 711 Class class1;
8a7d0ecc 712
61776355 713 assert (object_class);
8a7d0ecc 714
61776355 715 objc_mutex_lock (__objc_runtime_mutex);
8a7d0ecc 716
12e22ea5 717 /* Assign subclass links. */
718 while ((class1 = class_table_next (&es)))
8a7d0ecc 719 {
8a7d0ecc 720 /* Make sure we have what we think we have. */
61776355 721 assert (CLS_ISCLASS (class1));
722 assert (CLS_ISMETA (class1->class_pointer));
8a7d0ecc 723
12e22ea5 724 /* The class_pointer of all meta classes point to Object's meta
725 class. */
8a7d0ecc 726 class1->class_pointer->class_pointer = object_class->class_pointer;
727
61776355 728 if (! CLS_ISRESOLV (class1))
8a7d0ecc 729 {
61776355 730 CLS_SETRESOLV (class1);
731 CLS_SETRESOLV (class1->class_pointer);
8a7d0ecc 732
61776355 733 if (class1->super_class)
8a7d0ecc 734 {
735 Class a_super_class
736 = objc_get_class ((char *) class1->super_class);
737
738 assert (a_super_class);
739
740 DEBUG_PRINTF ("making class connections for: %s\n",
741 class1->name);
742
12e22ea5 743 /* Assign subclass links for superclass. */
8a7d0ecc 744 class1->sibling_class = a_super_class->subclass_list;
745 a_super_class->subclass_list = class1;
746
12e22ea5 747 /* Assign subclass links for meta class of superclass. */
8a7d0ecc 748 if (a_super_class->class_pointer)
749 {
750 class1->class_pointer->sibling_class
751 = a_super_class->class_pointer->subclass_list;
752 a_super_class->class_pointer->subclass_list
753 = class1->class_pointer;
754 }
755 }
12e22ea5 756 else /* A root class, make its meta object be a subclass of
757 Object. */
8a7d0ecc 758 {
759 class1->class_pointer->sibling_class
760 = object_class->subclass_list;
761 object_class->subclass_list = class1->class_pointer;
762 }
763 }
764 }
765
12e22ea5 766 /* Assign superclass links. */
767 es = NULL;
768 while ((class1 = class_table_next (&es)))
8a7d0ecc 769 {
8a7d0ecc 770 Class sub_class;
771 for (sub_class = class1->subclass_list; sub_class;
772 sub_class = sub_class->sibling_class)
773 {
774 sub_class->super_class = class1;
61776355 775 if (CLS_ISCLASS (sub_class))
8a7d0ecc 776 sub_class->class_pointer->super_class = class1->class_pointer;
777 }
778 }
779
61776355 780 objc_mutex_unlock (__objc_runtime_mutex);
8a7d0ecc 781}
782
e983fc72 783const char *
784class_getName (Class class_)
785{
786 if (class_ == Nil)
787 return "nil";
8a7d0ecc 788
e983fc72 789 return class_->name;
790}
8a7d0ecc 791
f75aa158 792BOOL
793class_isMetaClass (Class class_)
794{
795 /* CLS_ISMETA includes the check for Nil class_. */
796 return CLS_ISMETA (class_);
797}
798
799Class
800class_getSuperclass (Class class_)
801{
802 if (class_ == Nil)
803 return Nil;
804
805 return class_->super_class;
806}
807
808int
809class_getVersion (Class class_)
810{
811 if (class_ == Nil)
812 return 0;
813
814 return (int)(class_->version);
815}
816
817void
818class_setVersion (Class class_, int version)
819{
820 if (class_ == Nil)
821 return;
822
823 class_->version = version;
824}
825
826size_t
827class_getInstanceSize (Class class_)
828{
829 if (class_ == Nil)
830 return 0;
831
832 return class_->instance_size;
833}
834
8a7d0ecc 835#define CLASSOF(c) ((c)->class_pointer)
836
837Class
838class_pose_as (Class impostor, Class super_class)
839{
61776355 840 if (! CLS_ISRESOLV (impostor))
8a7d0ecc 841 __objc_resolve_class_links ();
842
12e22ea5 843 /* Preconditions */
8a7d0ecc 844 assert (impostor);
845 assert (super_class);
846 assert (impostor->super_class == super_class);
847 assert (CLS_ISCLASS (impostor));
848 assert (CLS_ISCLASS (super_class));
849 assert (impostor->instance_size == super_class->instance_size);
850
851 {
852 Class *subclass = &(super_class->subclass_list);
853
12e22ea5 854 /* Move subclasses of super_class to impostor. */
8a7d0ecc 855 while (*subclass)
856 {
12e22ea5 857 Class nextSub = (*subclass)->sibling_class;
858
859 if (*subclass != impostor)
860 {
861 Class sub = *subclass;
862
863 /* Classes */
864 sub->sibling_class = impostor->subclass_list;
865 sub->super_class = impostor;
866 impostor->subclass_list = sub;
867
868 /* It will happen that SUB is not a class object if it is
869 the top of the meta class hierarchy chain (root
870 meta-class objects inherit their class object). If
871 that is the case... don't mess with the meta-meta
872 class. */
873 if (CLS_ISCLASS (sub))
874 {
875 /* Meta classes */
876 CLASSOF (sub)->sibling_class =
877 CLASSOF (impostor)->subclass_list;
878 CLASSOF (sub)->super_class = CLASSOF (impostor);
879 CLASSOF (impostor)->subclass_list = CLASSOF (sub);
880 }
881 }
882
883 *subclass = nextSub;
8a7d0ecc 884 }
885
12e22ea5 886 /* Set subclasses of superclass to be impostor only. */
8a7d0ecc 887 super_class->subclass_list = impostor;
888 CLASSOF (super_class)->subclass_list = CLASSOF (impostor);
889
12e22ea5 890 /* Set impostor to have no sibling classes. */
8a7d0ecc 891 impostor->sibling_class = 0;
892 CLASSOF (impostor)->sibling_class = 0;
893 }
894
12e22ea5 895 /* Check relationship of impostor and super_class is kept. */
8a7d0ecc 896 assert (impostor->super_class == super_class);
897 assert (CLASSOF (impostor)->super_class == CLASSOF (super_class));
898
12e22ea5 899 /* This is how to update the lookup table. Regardless of what the
900 keys of the hashtable is, change all values that are superclass
901 into impostor. */
8a7d0ecc 902
61776355 903 objc_mutex_lock (__objc_runtime_mutex);
8a7d0ecc 904
12e22ea5 905 class_table_replace (super_class, impostor);
8a7d0ecc 906
61776355 907 objc_mutex_unlock (__objc_runtime_mutex);
8a7d0ecc 908
12e22ea5 909 /* Next, we update the dispatch tables... */
8a7d0ecc 910 __objc_update_dispatch_table_for_class (CLASSOF (impostor));
911 __objc_update_dispatch_table_for_class (impostor);
912
913 return impostor;
914}