2 * Copyright (c) 2005-2007 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 /***********************************************************************
26 * Support for new-ABI classes and images.
27 **********************************************************************/
31 #include "objc-private.h"
32 #include "objc-runtime-new.h"
33 #include "objc-loadmethod.h"
37 #include <mach-o/dyld.h>
38 #include <mach-o/ldsyms.h>
40 #define newcls(cls) ((struct class_t *)cls)
41 #define newcat(cat) ((struct category_t *)cat)
42 #define newmethod(meth) ((struct method_t *)meth)
43 #define newivar(ivar) ((struct ivar_t *)ivar)
44 #define newcategory(cat) ((struct category_t *)cat)
45 #define newprotocol(p) ((struct protocol_t *)p)
47 static const char *getName(struct class_t *cls);
48 static uint32_t instanceSize(struct class_t *cls);
49 static BOOL isMetaClass(struct class_t *cls);
50 static struct class_t *getSuperclass(struct class_t *cls);
51 static void unload_class(class_t *cls);
52 static class_t *setSuperclass(class_t *cls, class_t *newSuper);
53 static class_t *realizeClass(class_t *cls);
55 static OBJC_DECLARE_LOCK (runtimeLock);
56 // fixme use more fine-grained locks
61 category_t *list[0]; // variable-size
64 typedef struct chained_method_list {
65 struct chained_method_list *next;
67 method_t list[0]; // variable-size
68 } chained_method_list;
70 static size_t chained_mlist_size(const chained_method_list *mlist)
72 return sizeof(chained_method_list) + mlist->count * sizeof(method_t);
75 // fixme don't chain property lists
76 typedef struct chained_property_list {
77 struct chained_property_list *next;
79 struct objc_property list[0]; // variable-size
80 } chained_property_list;
83 static size_t chained_property_list_size(const chained_property_list *plist)
85 return sizeof(chained_property_list) +
86 plist->count * sizeof(struct objc_property);
89 static size_t protocol_list_size(const protocol_list_t *plist)
91 return sizeof(protocol_list_t) + plist->count * sizeof(protocol_t *);
95 static size_t ivar_list_size(const ivar_list_t *ilist)
97 return sizeof(ivar_list_t) + (ilist->count-1) * ilist->entsize;
100 static method_t *method_list_nth(const method_list_t *mlist, uint32_t i)
102 return (method_t *)(i*mlist->entsize + (char *)&mlist->first);
105 static ivar_t *ivar_list_nth(const ivar_list_t *ilist, uint32_t i)
107 return (ivar_t *)(i*ilist->entsize + (char *)&ilist->first);
111 static void try_free(const void *p)
113 if (p && malloc_size(p)) free((void *)p);
117 /***********************************************************************
119 * Reallocates rw->ro if necessary to make it writeable.
120 * Locking: runtimeLock must be held by the caller.
121 **********************************************************************/
122 static class_ro_t *make_ro_writeable(class_rw_t *rw)
124 OBJC_CHECK_LOCKED(&runtimeLock);
126 if (rw->flags & RW_COPIED_RO) {
127 // already writeable, do nothing
129 class_ro_t *ro = _memdup_internal(rw->ro, sizeof(*rw->ro));
131 rw->flags |= RW_COPIED_RO;
133 return (class_ro_t *)rw->ro;
137 /***********************************************************************
138 * unattachedCategories
139 * Returns the class => categories map of unattached categories.
140 * Locking: runtimeLock must be held by the caller.
141 **********************************************************************/
142 static NXMapTable *unattachedCategories(void)
144 OBJC_CHECK_LOCKED(&runtimeLock);
146 static NXMapTable *category_map = NULL;
148 if (category_map) return category_map;
150 // fixme initial map size
151 category_map = NXCreateMapTableFromZone(NXPtrValueMapPrototype, 16,
152 _objc_internal_zone());
158 /***********************************************************************
159 * addUnattachedCategoryForClass
160 * Records an unattached category.
161 * Locking: runtimeLock must be held by the caller.
162 **********************************************************************/
163 static void addUnattachedCategoryForClass(category_t *cat, class_t *cls)
165 OBJC_CHECK_LOCKED(&runtimeLock);
167 // DO NOT use cat->cls!
168 // cls may be cat->cls->isa, or cat->cls may have been remapped.
169 NXMapTable *cats = unattachedCategories();
172 list = NXMapGet(cats, cls);
174 list = _calloc_internal(sizeof(*list) + sizeof(category_t *), 1);
176 list = _realloc_internal(list, sizeof(*list) + sizeof(category_t *) * (list->count + 1));
178 list->list[list->count++] = cat;
179 NXMapInsert(cats, cls, list);
183 /***********************************************************************
184 * removeUnattachedCategoryForClass
185 * Removes an unattached category.
186 * Locking: runtimeLock must be held by the caller.
187 **********************************************************************/
188 static void removeUnattachedCategoryForClass(category_t *cat, class_t *cls)
190 OBJC_CHECK_LOCKED(&runtimeLock);
192 // DO NOT use cat->cls!
193 // cls may be cat->cls->isa, or cat->cls may have been remapped.
194 NXMapTable *cats = unattachedCategories();
197 list = NXMapGet(cats, cls);
201 for (i = 0; i < list->count; i++) {
202 if (list->list[i] == cat) {
203 // shift entries to preserve list order
204 memmove(&list->list[i], &list->list[i+1],
205 (list->count-i-1) * sizeof(category_t *));
213 /***********************************************************************
214 * unattachedCategoriesForClass
215 * Returns the list of unattached categories for a class, and
216 * deletes them from the list.
217 * The result must be freed by the caller.
218 * Locking: runtimeLock must be held by the caller.
219 **********************************************************************/
220 static category_list *unattachedCategoriesForClass(class_t *cls)
222 OBJC_CHECK_LOCKED(&runtimeLock);
223 return NXMapRemove(unattachedCategories(), cls);
227 /***********************************************************************
229 * Returns YES if class cls has been realized.
230 * Locking: To prevent concurrent realization, hold runtimeLock.
231 **********************************************************************/
232 static BOOL isRealized(class_t *cls)
234 return (cls->data->flags & RW_REALIZED) ? YES : NO;
238 /***********************************************************************
240 * Returns YES if class cls has ever been methodized.
241 * Note that its method lists may still be out of date.
242 * Locking: To prevent concurrent methodization, hold runtimeLock.
243 **********************************************************************/
244 static BOOL isMethodized(class_t *cls)
246 if (!isRealized(cls)) return NO;
247 return (cls->data->flags & RW_METHODIZED) ? YES : NO;
250 static chained_method_list *
251 buildMethodList(const method_list_t *mlist, category_list *cats, BOOL isMeta)
253 // Do NOT use cat->cls! It may have been remapped.
254 chained_method_list *newlist;
258 // Count methods in all lists.
259 if (mlist) count = mlist->count;
261 for (c = 0; c < cats->count; c++) {
262 if (isMeta && cats->list[c]->classMethods) {
263 count += cats->list[c]->classMethods->count;
265 else if (!isMeta && cats->list[c]->instanceMethods) {
266 count += cats->list[c]->instanceMethods->count;
271 // Allocate new list.
272 newlist = _malloc_internal(sizeof(*newlist) + count * sizeof(method_t));
274 newlist->next = NULL;
276 // Copy methods; newest categories first, then ordinary methods
280 method_list_t *cmlist;
282 cmlist = cats->list[c]->classMethods;
284 cmlist = cats->list[c]->instanceMethods;
287 for (m = 0; m < cmlist->count; m++) {
288 newlist->list[newlist->count++] =
289 *method_list_nth(cmlist, m);
295 for (m = 0; m < mlist->count; m++) {
296 newlist->list[newlist->count++] = *method_list_nth(mlist, m);
300 assert(newlist->count == count);
301 for (m = 0; m < newlist->count; m++) {
302 newlist->list[m].name =
303 sel_registerName((const char *)newlist->list[m].name);
304 if (newlist->list[m].name == (SEL)kRTAddress_ignoredSelector) {
305 newlist->list[m].imp = (IMP)&_objc_ignored_method;
313 static chained_property_list *
314 buildPropertyList(const struct objc_property_list *plist, category_list *cats, BOOL isMeta)
316 // Do NOT use cat->cls! It may have been remapped.
317 chained_property_list *newlist;
321 // Count properties in all lists.
322 if (plist) count = plist->count;
324 for (c = 0; c < cats->count; c++) {
326 if (isMeta && cats->list[c]->classProperties) {
327 count += cats->list[c]->classProperties->count;
330 if (!isMeta && cats->list[c]->instanceProperties) {
331 count += cats->list[c]->instanceProperties->count;
336 if (count == 0) return NULL;
338 // Allocate new list.
339 newlist = _malloc_internal(sizeof(*newlist) + count * sizeof(struct objc_property));
341 newlist->next = NULL;
343 // Copy properties; newest categories first, then ordinary properties
347 struct objc_property_list *cplist;
350 cplist = cats->list[c]->classProperties;
353 cplist = cats->list[c]->instanceProperties;
356 for (p = 0; p < cplist->count; p++) {
357 newlist->list[newlist->count++] =
358 *property_list_nth(cplist, p);
364 for (p = 0; p < plist->count; p++) {
365 newlist->list[newlist->count++] = *property_list_nth(plist, p);
369 assert(newlist->count == count);
375 static protocol_list_t **
376 buildProtocolList(category_list *cats, struct protocol_list_t *base,
377 struct protocol_list_t **protos)
379 // Do NOT use cat->cls! It may have been remapped.
380 struct protocol_list_t **p, **newp;
381 struct protocol_list_t **newprotos;
385 // count protocol list in base
388 // count protocol lists in cats
389 if (cats) for (i = 0; i < cats->count; i++) {
390 category_t *cat = cats->list[i];
391 if (cat->protocols) count++;
394 // no base or category protocols? return existing protocols unchanged
395 if (count == 0) return protos;
397 // count protocol lists in protos
398 for (p = protos; p && *p; p++) {
402 if (count == 0) return NULL;
404 newprotos = (struct protocol_list_t **)
405 _malloc_internal((count+1) * sizeof(struct protocol_list_t *));
412 for (p = protos; p && *p; p++) {
416 if (cats) for (i = 0; i < cats->count; i++) {
417 category_t *cat = cats->list[i];
418 if (cat->protocols) {
419 *newp++ = cat->protocols;
429 /***********************************************************************
431 * Fixes up cls's method list, protocol list, and property list.
432 * Attaches any outstanding categories.
433 * Locking: runtimeLock must be held by the caller
434 **********************************************************************/
435 static void methodizeClass(struct class_t *cls)
437 OBJC_CHECK_LOCKED(&runtimeLock);
442 assert(isRealized(cls));
444 if (!(cls->data->flags & RW_METHODIZED)) {
445 // Methodizing for the first time
446 if (PrintConnecting) {
447 _objc_inform("CLASS: methodizing class '%s' %s",
449 isMetaClass(cls) ? "(meta)" : "");
452 // Build method and protocol and property lists.
453 // Include methods and protocols and properties from categories, if any
454 // Do NOT use cat->cls! It may have been remapped.
455 cats = unattachedCategoriesForClass(cls);
456 if (cats || cls->data->ro->baseMethods) {
458 buildMethodList(cls->data->ro->baseMethods, cats,
462 if (cats || cls->data->ro->baseProperties) {
463 cls->data->properties =
464 buildPropertyList(cls->data->ro->baseProperties, cats,
468 if (cats || cls->data->ro->baseProtocols) {
469 cls->data->protocols =
470 buildProtocolList(cats, cls->data->ro->baseProtocols, NULL);
473 if (PrintConnecting) {
475 if (cats) for (i = 0; i < cats->count; i++) {
476 _objc_inform("CLASS: attached category %c%s(%s)",
477 isMetaClass(cls) ? '+' : '-',
478 getName(cls), cats->list[i]->name);
482 if (cats) _free_internal(cats);
484 cls->data->flags |= RW_METHODIZED;
487 // Re-methodizing: check for more categories
488 if ((cats = unattachedCategoriesForClass(cls))) {
489 chained_method_list *newlist;
490 chained_property_list *newproperties;
491 struct protocol_list_t **newprotos;
493 if (PrintConnecting) {
494 _objc_inform("CLASS: attaching categories to class '%s' %s",
496 isMetaClass(cls) ? "(meta)" : "");
499 newlist = buildMethodList(NULL, cats, isMetaClass(cls));
500 newlist->next = cls->data->methods;
501 cls->data->methods = newlist;
503 newproperties = buildPropertyList(NULL, cats, isMetaClass(cls));
505 newproperties->next = cls->data->properties;
506 cls->data->properties = newproperties;
509 newprotos = buildProtocolList(cats, NULL, cls->data->protocols);
510 if (cls->data->protocols && cls->data->protocols != newprotos) {
511 _free_internal(cls->data->protocols);
513 cls->data->protocols = newprotos;
515 _free_internal(cats);
521 /***********************************************************************
523 * Atomically sets and clears some bits in cls's info field.
524 * set and clear must not overlap.
525 **********************************************************************/
526 static OBJC_DECLARE_LOCK(infoLock);
527 // fixme use atomic ops instead of lock
528 static void changeInfo(class_t *cls, unsigned int set, unsigned int clear)
530 assert(isRealized(cls));
531 OBJC_LOCK(&infoLock);
532 cls->data->flags = (cls->data->flags | set) & ~clear;
533 OBJC_UNLOCK(&infoLock);
537 /***********************************************************************
539 * Returns the classname => class map for realized non-meta classes.
540 * Locking: runtimeLock must be held by the caller
541 **********************************************************************/
542 static NXMapTable *realizedClasses(void)
544 static NXMapTable *class_map = NULL;
546 OBJC_CHECK_LOCKED(&runtimeLock);
548 if (class_map) return class_map;
550 // fixme this doesn't work yet
551 // class_map starts small, with only enough capacity for libobjc itself.
552 // If a second library is found by map_images(), class_hash is immediately
553 // resized to capacity 1024 to cut down on rehashes.
554 class_map = NXCreateMapTableFromZone(NXStrValueMapPrototype, 16,
555 _objc_internal_zone());
561 /***********************************************************************
563 * Returns the classname => class map for unrealized non-meta classes.
564 * Locking: runtimeLock must be held by the caller
565 **********************************************************************/
566 static NXMapTable *unrealizedClasses(void)
568 static NXMapTable *class_map = NULL;
570 OBJC_CHECK_LOCKED(&runtimeLock);
572 if (class_map) return class_map;
574 // fixme this doesn't work yet
575 // class_map starts small, with only enough capacity for libobjc itself.
576 // If a second library is found by map_images(), class_hash is immediately
577 // resized to capacity 1024 to cut down on rehashes.
578 class_map = NXCreateMapTableFromZone(NXStrValueMapPrototype, 16,
579 _objc_internal_zone());
585 /***********************************************************************
587 * Adds name => cls to the realized non-meta class map.
588 * Also removes name => cls from the unrealized non-meta class map.
589 * Locking: runtimeLock must be held by the caller
590 **********************************************************************/
591 static void addRealizedClass(class_t *cls, const char *name)
593 OBJC_CHECK_LOCKED(&runtimeLock);
595 old = NXMapInsert(realizedClasses(), name, cls);
596 assert(!isMetaClass(cls));
597 NXMapRemove(unrealizedClasses(), name);
601 /***********************************************************************
602 * removeRealizedClass
603 * Removes cls from the realized class map.
604 * Locking: runtimeLock must be held by the caller
605 **********************************************************************/
606 static void removeRealizedClass(class_t *cls)
608 OBJC_CHECK_LOCKED(&runtimeLock);
609 assert(isRealized(cls));
610 assert(!isMetaClass(cls));
611 NXMapRemove(realizedClasses(), cls->data->ro->name);
615 /***********************************************************************
617 * Adds name => cls to the unrealized non-meta class map.
618 * Locking: runtimeLock must be held by the caller
619 **********************************************************************/
620 static void addUnrealizedClass(class_t *cls, const char *name)
622 OBJC_CHECK_LOCKED(&runtimeLock);
624 old = NXMapInsert(unrealizedClasses(), name, cls);
625 assert(!isRealized(cls));
626 assert(!(cls->data->flags & RO_META));
630 /***********************************************************************
631 * uninitializedClasses
632 * Returns the metaclass => class map for un-+initialized classes
633 * Replaces the 32-bit cls = objc_getName(metacls) during +initialize.
634 * Locking: runtimeLock must be held by the caller
635 **********************************************************************/
636 static NXMapTable *uninitializedClasses(void)
638 static NXMapTable *class_map = NULL;
640 OBJC_CHECK_LOCKED(&runtimeLock);
642 if (class_map) return class_map;
644 // fixme this doesn't work yet
645 // class_map starts small, with only enough capacity for libobjc itself.
646 // If a second library is found by map_images(), class_hash is immediately
647 // resized to capacity 1024 to cut down on rehashes.
648 class_map = NXCreateMapTableFromZone(NXPtrValueMapPrototype, 16,
649 _objc_internal_zone());
655 /***********************************************************************
656 * addUninitializedClass
657 * Adds metacls => cls to the un-+initialized class map
658 * Locking: runtimeLock must be held by the caller
659 **********************************************************************/
660 static void addUninitializedClass(class_t *cls, class_t *metacls)
662 OBJC_CHECK_LOCKED(&runtimeLock);
664 old = NXMapInsert(uninitializedClasses(), metacls, cls);
665 assert(isRealized(metacls) ? isMetaClass(metacls) : metacls->data->flags & RO_META);
666 assert(! (isRealized(cls) ? isMetaClass(cls) : cls->data->flags & RO_META));
671 static void removeUninitializedClass(class_t *cls)
673 OBJC_CHECK_LOCKED(&runtimeLock);
674 NXMapRemove(uninitializedClasses(), cls->isa);
678 /***********************************************************************
679 * _class_getNonMetaClass
680 * Return the ordinary class for this class or metaclass.
681 * Used by +initialize.
682 * Locking: acquires runtimeLock
683 **********************************************************************/
684 __private_extern__ Class _class_getNonMetaClass(Class cls_gen)
686 class_t *cls = newcls(cls_gen);
687 OBJC_LOCK(&runtimeLock);
688 if (isMetaClass(cls)) {
689 cls = NXMapGet(uninitializedClasses(), cls);
692 OBJC_UNLOCK(&runtimeLock);
699 /***********************************************************************
701 * Returns the classname => future class map for unrealized future classes.
702 * Locking: runtimeLock must be held by the caller
703 **********************************************************************/
704 static NXMapTable *futureClasses(void)
706 OBJC_CHECK_LOCKED(&runtimeLock);
708 static NXMapTable *future_class_map = NULL;
710 if (future_class_map) return future_class_map;
712 // future_class_map is big enough to hold CF's classes and a few others
713 future_class_map = NXCreateMapTableFromZone(NXStrValueMapPrototype, 32,
714 _objc_internal_zone());
716 return future_class_map;
720 /***********************************************************************
722 * Installs cls as the class structure to use for the named class if it appears.
723 * Locking: runtimeLock must be held by the caller
724 **********************************************************************/
725 static void addFutureClass(const char *name, class_t *cls)
727 OBJC_CHECK_LOCKED(&runtimeLock);
730 _objc_inform("FUTURE: reserving %p for %s", cls, name);
734 old = NXMapKeyCopyingInsert(futureClasses(), name, cls);
739 /***********************************************************************
741 * Removes the named class from the unrealized future class list,
742 * because it has been realized.
743 * Locking: runtimeLock must be held by the caller
744 **********************************************************************/
745 static void removeFutureClass(const char *name)
747 OBJC_CHECK_LOCKED(&runtimeLock);
749 NXMapKeyFreeingRemove(futureClasses(), name);
753 /***********************************************************************
755 * Returns the oldClass => newClass map for realized future classes.
756 * Locking: remapLock must be held by the caller
757 **********************************************************************/
758 static OBJC_DECLARE_LOCK(remapLock);
759 static NXMapTable *remappedClasses(BOOL create)
761 static NXMapTable *remapped_class_map = NULL;
763 OBJC_CHECK_LOCKED(&remapLock);
765 if (remapped_class_map) return remapped_class_map;
767 if (!create) return NULL;
769 // remapped_class_map is big enough to hold CF's classes and a few others
770 remapped_class_map = NXCreateMapTableFromZone(NXPtrValueMapPrototype, 32,
771 _objc_internal_zone());
773 return remapped_class_map;
777 /***********************************************************************
779 * Returns YES if no classes have been remapped
780 * Locking: acquires remapLock
781 **********************************************************************/
782 static BOOL noClassesRemapped(void)
784 OBJC_LOCK(&remapLock);
785 BOOL result = (remappedClasses(NO) == NULL);
786 OBJC_UNLOCK(&remapLock);
791 /***********************************************************************
793 * newcls is a realized future class, replacing oldcls.
794 * Locking: acquires remapLock
795 **********************************************************************/
796 static void addRemappedClass(class_t *oldcls, class_t *newcls)
798 OBJC_LOCK(&remapLock);
801 _objc_inform("FUTURE: using %p instead of %p for %s",
802 oldcls, newcls, getName(newcls));
806 old = NXMapInsert(remappedClasses(YES), oldcls, newcls);
809 OBJC_UNLOCK(&remapLock);
813 /***********************************************************************
815 * Returns the live class pointer for cls, which may be pointing to
816 * a class struct that has been reallocated.
817 * Locking: acquires remapLock
818 **********************************************************************/
819 static class_t *remapClass(class_t *cls)
821 OBJC_LOCK(&remapLock);
822 class_t *newcls = NXMapGet(remappedClasses(YES), cls);
823 OBJC_UNLOCK(&remapLock);
824 return newcls ? newcls : cls;
828 /***********************************************************************
830 * Fix up a class ref, in case the class referenced has been reallocated.
831 * Locking: acquires remapLock
832 **********************************************************************/
833 static void remapClassRef(class_t **clsref)
835 class_t *newcls = remapClass(*clsref);
836 if (*clsref != newcls) *clsref = newcls;
840 /***********************************************************************
842 * Adds subcls as a subclass of supercls.
843 * Locking: runtimeLock must be held by the caller.
844 **********************************************************************/
845 static void addSubclass(class_t *supercls, class_t *subcls)
847 OBJC_CHECK_LOCKED(&runtimeLock);
849 if (supercls && subcls) {
850 assert(isRealized(supercls));
851 assert(isRealized(subcls));
852 subcls->data->nextSiblingClass = supercls->data->firstSubclass;
853 supercls->data->firstSubclass = subcls;
858 /***********************************************************************
860 * Removes subcls as a subclass of supercls.
861 * Locking: runtimeLock must be held by the caller.
862 **********************************************************************/
863 static void removeSubclass(class_t *supercls, class_t *subcls)
865 OBJC_CHECK_LOCKED(&runtimeLock);
866 assert(getSuperclass(subcls) == supercls);
869 for (cp = &supercls->data->firstSubclass;
870 *cp && *cp != subcls;
871 cp = &(*cp)->data->nextSiblingClass)
873 assert(*cp == subcls);
874 *cp = subcls->data->nextSiblingClass;
879 /***********************************************************************
881 * Returns the protocol name => protocol map for protocols.
882 * Locking: runtimeLock must be held by the caller
883 **********************************************************************/
884 static NXMapTable *protocols(void)
886 static NXMapTable *protocol_map = NULL;
888 OBJC_CHECK_LOCKED(&runtimeLock);
890 if (protocol_map) return protocol_map;
892 // fixme this doesn't work yet
893 // class_map starts small, with only enough capacity for libobjc itself.
894 // If a second library is found by map_images(), class_hash is immediately
895 // resized to capacity 1024 to cut down on rehashes.
896 protocol_map = NXCreateMapTableFromZone(NXStrValueMapPrototype, 16,
897 _objc_internal_zone());
903 /***********************************************************************
905 * Returns the live protocol pointer for proto, which may be pointing to
906 * a protocol struct that has been reallocated.
908 **********************************************************************/
909 static protocol_t *remapProtocol(protocol_t *proto)
911 // OBJC_LOCK(&remapLock);
912 protocol_t *newproto = NXMapGet(protocols(), proto->name);
913 // OBJC_UNLOCK(&remapLock);
914 return newproto ? newproto : proto;
918 /***********************************************************************
920 * Fix up a protocol ref, in case the protocol referenced has been reallocated.
922 **********************************************************************/
923 static void remapProtocolRef(protocol_t **protoref)
925 protocol_t *newproto = remapProtocol(*protoref);
926 if (*protoref != newproto) *protoref = newproto;
930 /***********************************************************************
932 * Slides a class's ivars to accommodate the given superclass size.
933 * Also slides ivar and weak GC layouts if provided.
934 * Ivars are NOT compacted to compensate for a superclass that shrunk.
935 * Locking: runtimeLock must be held by the caller.
936 **********************************************************************/
937 static void moveIvars(class_ro_t *ro, uint32_t superSize,
938 layout_bitmap *ivarBitmap, layout_bitmap *weakBitmap)
940 OBJC_CHECK_LOCKED(&runtimeLock);
946 assert(superSize > ro->instanceStart);
947 diff = superSize - ro->instanceStart;
949 *(uint32_t *)&ro->instanceStart += diff;
952 for (i = 0; i < ro->ivars->count; i++) {
953 ivar_t *ivar = ivar_list_nth(ro->ivars, i);
954 // naively slide ivar
955 uint32_t oldOffset = (uint32_t)*ivar->offset;
956 uint32_t newOffset = oldOffset + diff;
958 uint32_t alignMask = (1<<ivar->alignment)-1;
959 if (newOffset & alignMask) {
960 uint32_t alignedOffset = (newOffset + alignMask) & ~alignMask;
961 assert(alignedOffset > newOffset);
962 diff += alignedOffset - newOffset;
963 gcdiff += alignedOffset - newOffset;
964 newOffset = alignedOffset;
966 // newOffset is ready
967 *ivar->offset = newOffset;
968 // update ivar layouts
969 if (gcdiff != 0 && (oldOffset & 7) == 0) {
970 // this ivar's alignment hasn't been accounted for yet
972 layout_bitmap_slide(ivarBitmap,
973 (newOffset-gcdiff)>>3, newOffset>>3);
976 layout_bitmap_slide(weakBitmap,
977 (newOffset-gcdiff)>>3, newOffset>>3);
983 _objc_inform("IVARS: offset %u -> %u for %s (size %u, align %u)",
984 oldOffset, newOffset, ivar->name,
985 ivar->size, 1<<ivar->alignment);
990 *(uint32_t *)&ro->instanceSize += diff; // diff now includes alignment pad
993 // No ivars slid, but superclass changed size.
994 // Expand bitmap in preparation for layout_bitmap_splat().
995 if (ivarBitmap) layout_bitmap_grow(ivarBitmap, ro->instanceSize>>3);
996 if (weakBitmap) layout_bitmap_grow(weakBitmap, ro->instanceSize>>3);
1000 #error wrong word size used in this function
1005 /***********************************************************************
1007 * Look up an ivar by name.
1008 * Locking: runtimeLock must be held by the caller.
1009 **********************************************************************/
1010 static ivar_t *getIvar(class_t *cls, const char *name)
1012 OBJC_CHECK_LOCKED(&runtimeLock);
1014 const ivar_list_t *ivars;
1015 assert(isRealized(cls));
1016 if ((ivars = cls->data->ro->ivars)) {
1018 for (i = 0; i < ivars->count; i++) {
1019 struct ivar_t *ivar = ivar_list_nth(ivars, i);
1020 // ivar->name may be NULL for anonymous bitfields etc.
1021 if (ivar->name && 0 == strcmp(name, ivar->name)) {
1031 /***********************************************************************
1033 * Performs first-time initialization on class cls,
1034 * including allocating its read-write data.
1035 * Returns the real class structure for the class.
1036 * Locking: runtimeLock must be held by the caller
1037 **********************************************************************/
1038 static class_t *realizeClass(class_t *cls)
1040 OBJC_CHECK_LOCKED(&runtimeLock);
1042 const class_ro_t *ro;
1048 if (!cls) return NULL;
1049 if (isRealized(cls)) return cls;
1050 assert(cls == remapClass(cls));
1052 ro = (const class_ro_t *)cls->data;
1054 isMeta = (ro->flags & RO_META) ? YES : NO;
1056 if (PrintConnecting) {
1057 _objc_inform("CLASS: realizing class '%s' %s %p %p",
1058 ro->name, isMeta ? "(meta)" : "", cls, ro);
1061 // Allocate writeable class data
1062 rw = _calloc_internal(sizeof(class_rw_t), 1);
1063 rw->flags = RW_REALIZED;
1064 rw->version = isMeta ? 7 : 0; // old runtime went up to 6
1069 // Realize superclass and metaclass, if they aren't already.
1070 // This needs to be done after RW_REALIZED is set above, for root classes.
1071 supercls = realizeClass(remapClass(cls->superclass));
1072 metacls = realizeClass(remapClass(cls->isa));
1074 // Check for remapped superclass
1075 // fixme doesn't handle remapped metaclass
1076 assert(metacls == cls->isa);
1077 if (supercls != cls->superclass) {
1078 cls->superclass = supercls;
1081 /* debug: print them all
1084 for (i = 0; i < ro->ivars->count; i++) {
1085 ivar_t *ivar = ivar_list_nth(ro->ivars, i);
1086 _objc_inform("IVARS: %s.%s (offset %u, size %u, align %u)",
1087 ro->name, ivar->name,
1088 *ivar->offset, ivar->size, 1<<ivar->alignment);
1095 // Non-fragile ivars - reconcile this class with its superclass
1096 layout_bitmap ivarBitmap;
1097 layout_bitmap weakBitmap;
1098 BOOL layoutsChanged = NO;
1101 // fixme can optimize for "class has no new ivars", etc
1102 // WARNING: gcc c++ sets instanceStart/Size=0 for classes with
1103 // no local ivars, but does provide a layout bitmap.
1104 // Handle that case specially so layout_bitmap_create doesn't die
1105 // The other ivar sliding code below still works fine, and
1106 // the final result is a good class.
1107 if (ro->instanceStart == 0 && ro->instanceSize == 0) {
1108 // We can't use ro->ivarLayout because we don't know
1109 // how long it is. Force a new layout to be created.
1111 _objc_inform("IVARS: instanceStart/Size==0 for class %s; "
1112 "disregarding ivar layout", ro->name);
1115 layout_bitmap_create(NULL,
1116 supercls->data->ro->instanceSize,
1117 supercls->data->ro->instanceSize, NO);
1119 layout_bitmap_create(NULL,
1120 supercls->data->ro->instanceSize,
1121 supercls->data->ro->instanceSize, YES);
1122 layoutsChanged = YES;
1125 layout_bitmap_create(ro->ivarLayout,
1127 ro->instanceSize, NO);
1129 layout_bitmap_create(ro->weakIvarLayout,
1131 ro->instanceSize, YES);
1135 if (ro->instanceStart < supercls->data->ro->instanceSize) {
1136 // Superclass has changed size. This class's ivars must move.
1137 // Also slide layout bits in parallel.
1138 // This code is incapable of compacting the subclass to
1139 // compensate for a superclass that shrunk, so don't do that.
1141 _objc_inform("IVARS: sliding ivars for class %s "
1142 "(superclass was %u bytes, now %u)",
1143 ro->name, ro->instanceStart,
1144 supercls->data->ro->instanceSize);
1146 class_ro_t *ro_w = make_ro_writeable(rw);
1148 moveIvars(ro_w, supercls->data->ro->instanceSize,
1149 UseGC ? &ivarBitmap : NULL, UseGC ? &weakBitmap : NULL);
1150 layoutsChanged = YES;
1154 // Check superclass's layout against this class's layout.
1155 // This needs to be done even if the superclass is not bigger.
1156 layout_bitmap superBitmap =
1157 layout_bitmap_create(supercls->data->ro->ivarLayout,
1158 supercls->data->ro->instanceSize,
1159 supercls->data->ro->instanceSize, NO);
1160 layoutsChanged |= layout_bitmap_splat(ivarBitmap, superBitmap,
1162 layout_bitmap_free(superBitmap);
1165 layout_bitmap_create(supercls->data->ro->weakIvarLayout,
1166 supercls->data->ro->instanceSize,
1167 supercls->data->ro->instanceSize, YES);
1168 layoutsChanged |= layout_bitmap_splat(weakBitmap, superBitmap,
1170 layout_bitmap_free(superBitmap);
1172 if (layoutsChanged) {
1173 // Rebuild layout strings.
1175 _objc_inform("IVARS: gc layout changed for class %s",
1178 class_ro_t *ro_w = make_ro_writeable(rw);
1180 ro_w->ivarLayout = layout_string_create(ivarBitmap);
1181 ro_w->weakIvarLayout = layout_string_create(weakBitmap);
1184 layout_bitmap_free(ivarBitmap);
1185 layout_bitmap_free(weakBitmap);
1189 // Connect this class to its superclass's subclass lists
1191 addSubclass(supercls, cls);
1195 addRealizedClass(cls, cls->data->ro->name);
1197 // metaclasses don't go in the realized class map
1204 /***********************************************************************
1206 * Looks up a class by name with no hints, and realizes it.
1207 * Locking: runtimeLock must be held by the caller.
1208 **********************************************************************/
1209 static class_t *getClass(const char *name)
1211 OBJC_CHECK_LOCKED(&runtimeLock);
1215 // Try realized classes
1216 result = (class_t *)NXMapGet(realizedClasses(), name);
1217 if (result) return result;
1219 // Try unrealized classes
1220 result = (class_t *)NXMapGet(unrealizedClasses(), name);
1221 if (result) return result;
1224 // Try a classname symbol
1225 result = getClassBySymbol(NULL, name);
1227 result = realizeClass(remapClass(result));
1233 realizeAllClasses();
1234 result = (class_t *)NXMapGet(realizedClasses(), name);
1244 /***********************************************************************
1245 * realizeAllClassesInImage
1246 * Non-lazily realizes all unrealized classes in the given image.
1247 * Locking: runtimeLock must be held by the caller.
1248 **********************************************************************/
1249 static void realizeAllClassesInImage(header_info *hi)
1251 OBJC_CHECK_LOCKED(&runtimeLock);
1254 class_t **classlist;
1256 if (hi->allClassesRealized) return;
1258 classlist = _getObjc2ClassList(hi, &count);
1260 for (i = 0; i < count; i++) {
1261 realizeClass(remapClass(classlist[i]));
1264 hi->allClassesRealized = YES;
1268 /***********************************************************************
1270 * Non-lazily realizes all unrealized classes in all known images.
1271 * Locking: runtimeLock must be held by the caller.
1272 **********************************************************************/
1273 static void realizeAllClasses(void)
1275 OBJC_CHECK_LOCKED(&runtimeLock);
1278 for (hi = _objc_headerStart(); hi; hi = hi->next) {
1279 realizeAllClassesInImage(hi);
1284 /***********************************************************************
1285 * _objc_allocateFutureClass
1286 * Allocate an unresolved future class for the given class name.
1287 * Returns any existing allocation if one was already made.
1288 * Assumes the named class doesn't exist yet.
1289 * Locking: acquires runtimeLock
1290 **********************************************************************/
1291 __private_extern__ Class _objc_allocateFutureClass(const char *name)
1293 OBJC_LOCK(&runtimeLock);
1295 struct class_t *cls;
1296 NXMapTable *future_class_map = futureClasses();
1298 if ((cls = NXMapGet(future_class_map, name))) {
1299 // Already have a future class for this name.
1300 OBJC_UNLOCK(&runtimeLock);
1304 cls = _calloc_internal(sizeof(*cls), 1);
1305 addFutureClass(name, cls);
1307 OBJC_UNLOCK(&runtimeLock);
1312 /***********************************************************************
1314 **********************************************************************/
1315 void objc_setFutureClass(Class cls, const char *name)
1317 // fixme hack do nothing - NSCFString handled specially elsewhere
1321 static BOOL addrInSeg(const void *addr_ptr, const segmentType *segment,
1324 uintptr_t base = segment->vmaddr + slide;
1325 uintptr_t addr = (uintptr_t)addr_ptr;
1326 size_t size = segment->filesize;
1328 return (addr >= base && addr < base + size);
1331 static BOOL ptrInImageList(header_info **hList, uint32_t hCount,
1336 for (i = 0; i < hCount; i++) {
1337 header_info *hi = hList[i];
1338 if (addrInSeg(ptr, hi->dataSegmentHeader, hi->image_slide)) {
1347 #define FOREACH_SUBCLASS(c, cls, code) \
1349 OBJC_CHECK_LOCKED(&runtimeLock); \
1350 class_t *top = cls; \
1352 if (c) while (1) { \
1354 if (c->data->firstSubclass) { \
1355 c = c->data->firstSubclass; \
1357 while (!c->data->nextSiblingClass && c != top) { \
1358 c = getSuperclass(c); \
1360 if (c == top) break; \
1361 c = c->data->nextSiblingClass; \
1367 /***********************************************************************
1369 * Flushes caches for cls and its subclasses.
1370 * Locking: runtimeLock must be held by the caller.
1371 **********************************************************************/
1372 static void flushCaches(class_t *cls)
1374 OBJC_CHECK_LOCKED(&runtimeLock);
1376 FOREACH_SUBCLASS(c, cls, {
1377 flush_cache((Class)c);
1382 /***********************************************************************
1384 * Flushes caches for cls, its subclasses, and optionally its metaclass.
1385 * Locking: acquires runtimeLock
1386 **********************************************************************/
1387 __private_extern__ void flush_caches(Class cls, BOOL flush_meta)
1389 OBJC_LOCK(&runtimeLock);
1390 flushCaches(newcls(cls));
1391 if (flush_meta) flushCaches(newcls(cls)->isa);
1392 OBJC_UNLOCK(&runtimeLock);
1396 /***********************************************************************
1398 * Perform initial processing of the headers in the linked
1399 * list beginning with headerList.
1401 * Called by: map_images
1403 * Locking: acquires runtimeLock
1404 **********************************************************************/
1405 __private_extern__ void _read_images(header_info **hList, uint32_t hCount)
1411 class_t **resolvedFutureClasses = NULL;
1412 size_t resolvedFutureClassCount = 0;
1414 #define EACH_HEADER \
1416 hIndex < hCount && (hi = hList[hIndex]); \
1419 OBJC_LOCK(&runtimeLock);
1421 // Complain about images that contain old-ABI data
1422 // fixme new-ABI compiler still emits some bits into __OBJC segment
1425 if (_getObjcSelectorRefs(hi, &count) ||
1426 _getObjcModules(hi->mhdr, hi->image_slide, &count))
1428 _objc_inform("found old-ABI metadata in image %s !",
1429 hi->dl_info.dli_fname);
1434 static BOOL hackedNSCFString = NO;
1435 if (!hackedNSCFString) {
1436 // Insert future class __CFConstantStringClassReference == NSCFString
1437 void *dlh = dlopen("/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation", RTLD_LAZY | RTLD_NOLOAD | RTLD_FIRST);
1439 void *addr = dlsym(dlh, "__CFConstantStringClassReference");
1441 addFutureClass("NSCFString", (class_t *)addr);
1442 hackedNSCFString = YES;
1448 // Discover classes. Fix up unresolved future classes
1449 NXMapTable *future_class_map = futureClasses();
1451 class_t **classlist = _getObjc2ClassList(hi, &count);
1452 for (i = 0; i < count; i++) {
1453 const char *name = getName(classlist[i]);
1454 if (NXCountMapTable(future_class_map) > 0) {
1455 class_t *newCls = NXMapGet(future_class_map, name);
1457 memcpy(newCls, classlist[i], sizeof(class_t));
1458 removeFutureClass(name);
1459 addRemappedClass(classlist[i], newCls);
1460 classlist[i] = newCls;
1461 // Non-lazily realize the class below.
1462 resolvedFutureClasses = (class_t **)
1463 _realloc_internal(resolvedFutureClasses,
1464 (resolvedFutureClassCount+1)
1465 * sizeof(class_t *));
1466 resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
1469 addUnrealizedClass(classlist[i], name);
1470 addUninitializedClass(classlist[i], classlist[i]->isa);
1474 // Fix up remapped classes
1475 // classlist is up to date, but classrefs may not be
1477 if (!noClassesRemapped()) {
1479 class_t **classrefs = _getObjc2ClassRefs(hi, &count);
1480 for (i = 0; i < count; i++) {
1481 remapClassRef(&classrefs[i]);
1483 // fixme why doesn't test future1 catch the absence of this?
1484 classrefs = _getObjc2SuperRefs(hi, &count);
1485 for (i = 0; i < count; i++) {
1486 remapClassRef(&classrefs[i]);
1492 // Fix up @selector references
1495 SEL *sels = _getObjc2SelectorRefs(hi, &count);
1496 BOOL isBundle = hi->mhdr->filetype == MH_BUNDLE;
1497 for (i = 0; i < count; i++) {
1498 sels[i] = sel_registerNameNoLock((const char *)sels[i], isBundle);
1503 // Discover protocols. Fix up protocol refs.
1504 NXMapTable *protocol_map = protocols();
1506 extern struct class_t OBJC_CLASS_$_Protocol;
1507 Class cls = (Class)&OBJC_CLASS_$_Protocol;
1509 protocol_t **protocols = _getObjc2ProtocolList(hi, &count);
1510 // fixme duplicate protocol from bundle
1511 for (i = 0; i < count; i++) {
1512 if (!NXMapGet(protocol_map, protocols[i]->name)) {
1513 protocols[i]->isa = cls;
1514 NXMapKeyCopyingInsert(protocol_map,
1515 protocols[i]->name, protocols[i]);
1516 if (PrintProtocols) {
1517 _objc_inform("PROTOCOLS: protocol at %p is %s",
1518 protocols[i], protocols[i]->name);
1521 if (PrintProtocols) {
1522 _objc_inform("PROTOCOLS: protocol at %p is %s (duplicate)",
1523 protocols[i], protocols[i]->name);
1529 protocol_t **protocols;
1530 protocols = _getObjc2ProtocolRefs(hi, &count);
1531 for (i = 0; i < count; i++) {
1532 remapProtocolRef(&protocols[i]);
1535 protocols = _getObjc2ProtocolList(hi, &count);
1536 for (i = 0; i < count; i++) {
1537 protocol_t *protocol = NXMapGet(protocol_map, protocols[i]->name);
1539 if (protocol == protocols[i] && protocol->protocols) {
1540 if (PrintProtocols) {
1541 _objc_inform("PROTOCOLS: remapping superprotocols of %p %s",
1542 protocol, protocol->name);
1544 for (j = 0; j < protocol->protocols->count; j++) {
1545 remapProtocolRef(&protocol->protocols->list[j]);
1551 // Discover categories.
1553 category_t **catlist =
1554 _getObjc2CategoryList(hi, &count);
1555 for (i = 0; i < count; i++) {
1556 category_t *cat = catlist[i];
1557 // Do NOT use cat->cls! It may have been remapped.
1558 class_t *cls = remapClass(cat->cls);
1560 // Process this category.
1561 // First, register the category with its target class.
1562 // Then, flush the class's cache (and its subclasses) if
1563 // the class is methodized. The ptrInImageList() check
1564 // can discover !methodized without touching the class's memory.
1565 // GrP fixme class's memory is already touched.
1566 BOOL classExists = NO;
1567 if (cat->instanceMethods || cat->protocols
1568 || cat->instanceProperties)
1570 addUnattachedCategoryForClass(cat, cls);
1571 if (!ptrInImageList(hList, hCount, cls) &&
1577 if (PrintConnecting) {
1578 _objc_inform("CLASS: found category -%s(%s) %s\n",
1579 getName(cls), cat->name,
1580 classExists ? "on existing class" : "");
1584 if (cat->classMethods || cat->protocols
1585 /* || cat->classProperties */)
1587 addUnattachedCategoryForClass(cat, cls->isa);
1588 if (!ptrInImageList(hList, hCount, cls->isa) &&
1589 isRealized(cls->isa))
1591 flushCaches(cls->isa);
1593 if (PrintConnecting) {
1594 _objc_inform("CLASS: found category +%s(%s)",
1595 getName(cls), cat->name);
1602 // Realize non-lazy classes (for +load methods and static instances)
1605 class_t **classlist =
1606 _getObjc2NonlazyClassList(hi, &count);
1607 for (i = 0; i < count; i++) {
1608 realizeClass(remapClass(classlist[i]));
1612 // Realize newly-resolved future classes, in case CF manipulates them
1613 if (resolvedFutureClasses) {
1614 for (i = 0; i < resolvedFutureClassCount; i++) {
1615 realizeClass(resolvedFutureClasses[i]);
1617 _free_internal(resolvedFutureClasses);
1620 // +load handled by prepare_load_methods()
1623 OBJC_UNLOCK(&runtimeLock);
1629 /***********************************************************************
1630 * prepare_load_methods
1631 * Schedule +load for classes in this image, any un-+load-ed
1632 * superclasses in other images, and any categories in this image.
1633 **********************************************************************/
1634 // Recursively schedule +load for cls and any un-+load-ed superclasses.
1635 // cls must already be connected.
1636 static void schedule_class_load(class_t *cls)
1638 assert(isRealized(cls)); // _read_images should realize
1640 if (cls->data->flags & RW_LOADED) return;
1642 class_t *supercls = getSuperclass(cls);
1643 if (supercls) schedule_class_load(supercls);
1645 add_class_to_loadable_list((Class)cls);
1646 changeInfo(cls, RW_LOADED, 0);
1649 __private_extern__ void prepare_load_methods(header_info *hi)
1653 OBJC_LOCK(&runtimeLock);
1655 class_t **classlist =
1656 _getObjc2NonlazyClassList(hi, &count);
1657 for (i = 0; i < count; i++) {
1658 class_t *cls = remapClass(classlist[i]);
1659 schedule_class_load(cls);
1662 category_t **categorylist = _getObjc2NonlazyCategoryList(hi, &count);
1663 for (i = 0; i < count; i++) {
1664 category_t *cat = categorylist[i];
1665 // Do NOT use cat->cls! It may have been remapped.
1666 class_t *cls = remapClass(cat->cls);
1668 assert(isRealized(cls->isa));
1669 add_category_to_loadable_list((Category)cat);
1672 OBJC_UNLOCK(&runtimeLock);
1676 /***********************************************************************
1678 * Only handles MH_BUNDLE for now.
1679 **********************************************************************/
1680 __private_extern__ void _unload_image(header_info *hi)
1684 OBJC_LOCK(&runtimeLock);
1686 // Unload unattached categories and categories waiting for +load.
1688 category_t **catlist = _getObjc2CategoryList(hi, &count);
1689 for (i = 0; i < count; i++) {
1690 category_t *cat = catlist[i];
1691 class_t *cls = remapClass(cat->cls);
1692 // fixme for MH_DYLIB cat's class may have been unloaded already
1695 removeUnattachedCategoryForClass(cat, cls);
1698 remove_category_from_loadable_list((Category)cat);
1703 class_t **classlist = _getObjc2ClassList(hi, &count);
1704 for (i = 0; i < count; i++) {
1705 class_t *cls = classlist[i];
1706 const char *name = getName(cls);
1707 // fixme remapped classes?
1710 remove_class_from_loadable_list((Class)cls);
1712 // categories not yet attached to this class
1713 category_list *cats;
1714 cats = unattachedCategoriesForClass(cls);
1715 if (cats) free(cats);
1716 cats = unattachedCategoriesForClass(cls);
1717 if (cats) free(cats);
1721 if ((supercls = getSuperclass(cls))) {
1722 removeSubclass(supercls, cls);
1724 if ((supercls = getSuperclass(cls->isa))) {
1725 removeSubclass(supercls, cls->isa);
1729 NXMapRemove(unrealizedClasses(), name);
1730 NXMapRemove(realizedClasses(), name);
1731 NXMapRemove(uninitializedClasses(), cls->isa);
1734 if (isRealized(cls->isa)) unload_class(cls->isa);
1735 if (isRealized(cls)) unload_class(cls);
1738 // Clean up protocols.
1739 #warning fixme protocol unload
1741 // fixme DebugUnload
1743 OBJC_UNLOCK(&runtimeLock);
1747 /***********************************************************************
1748 * method_getDescription
1749 * Returns a pointer to this method's objc_method_description.
1751 **********************************************************************/
1752 struct objc_method_description *
1753 method_getDescription(Method m)
1755 if (!m) return NULL;
1756 return (struct objc_method_description *)newmethod(m);
1760 /***********************************************************************
1761 * method_getImplementation
1762 * Returns this method's IMP.
1764 **********************************************************************/
1766 method_getImplementation(Method m)
1768 if (!m) return NULL;
1769 if (newmethod(m)->name == (SEL)kRTAddress_ignoredSelector) {
1770 return (IMP)_objc_ignored_method;
1772 return newmethod(m)->imp;
1776 /***********************************************************************
1778 * Returns this method's selector.
1779 * The method must not be NULL.
1780 * The method must already have been fixed-up.
1782 **********************************************************************/
1784 method_getName(Method m_gen)
1786 struct method_t *m = newmethod(m_gen);
1787 if (!m) return NULL;
1788 assert((SEL)m->name == sel_registerName((char *)m->name));
1789 return (SEL)m->name;
1793 /***********************************************************************
1794 * method_getTypeEncoding
1795 * Returns this method's old-style type encoding string.
1796 * The method must not be NULL.
1798 **********************************************************************/
1800 method_getTypeEncoding(Method m)
1802 if (!m) return NULL;
1803 return newmethod(m)->types;
1807 /***********************************************************************
1808 * method_setImplementation
1809 * Sets this method's implementation to imp.
1810 * The previous implementation is returned.
1811 **********************************************************************/
1813 method_setImplementation(Method m, IMP imp)
1815 static OBJC_DECLARE_LOCK(impLock);
1818 OBJC_LOCK(&impLock);
1819 old = method_getImplementation(m);
1820 newmethod(m)->imp = imp;
1821 OBJC_UNLOCK(&impLock);
1823 // No cache flushing needed.
1824 // fixme update vtables if necessary
1825 // fixme update monomorphism if necessary
1830 /***********************************************************************
1832 * Realizes the given class.
1833 * Called by _class_lookupMethodAndLoadCache only.
1834 * Locking: acquires runtimeLock
1835 **********************************************************************/
1836 __private_extern__ void
1837 _class_realize(struct class_t *cls)
1839 OBJC_LOCK(&runtimeLock);
1841 OBJC_UNLOCK(&runtimeLock);
1846 /***********************************************************************
1850 **********************************************************************/
1852 ivar_getOffset(Ivar ivar)
1854 if (!ivar) return 0;
1855 return *newivar(ivar)->offset;
1859 /***********************************************************************
1863 **********************************************************************/
1865 ivar_getName(Ivar ivar)
1867 if (!ivar) return NULL;
1868 return newivar(ivar)->name;
1872 /***********************************************************************
1873 * ivar_getTypeEncoding
1876 **********************************************************************/
1878 ivar_getTypeEncoding(Ivar ivar)
1880 if (!ivar) return NULL;
1881 return newivar(ivar)->type;
1885 /***********************************************************************
1886 * _protocol_getMethod_nolock
1887 * Locking: runtimeLock must be held by the caller
1888 **********************************************************************/
1890 _protocol_getMethod_nolock(protocol_t *proto, SEL sel,
1891 BOOL isRequiredMethod, BOOL isInstanceMethod)
1893 OBJC_CHECK_LOCKED(&runtimeLock);
1896 if (!proto || !sel) return NULL;
1898 method_list_t *mlist = NULL;
1900 if (isRequiredMethod) {
1901 if (isInstanceMethod) {
1902 mlist = proto->instanceMethods;
1904 mlist = proto->classMethods;
1907 if (isInstanceMethod) {
1908 mlist = proto->optionalInstanceMethods;
1910 mlist = proto->optionalClassMethods;
1915 for (i = 0; i < mlist->count; i++) {
1916 method_t *m = method_list_nth(mlist, i);
1917 if (sel != m->name) {
1918 m->name = sel_registerName((char *)m->name);
1920 if (sel == m->name) {
1926 if (proto->protocols) {
1928 for (i = 0; i < proto->protocols->count; i++) {
1929 protocol_t *realProto = remapProtocol(proto->protocols->list[i]);
1930 m = _protocol_getMethod_nolock(realProto, sel,
1931 isRequiredMethod, isInstanceMethod);
1940 /***********************************************************************
1941 * _protocol_getMethod
1943 * Locking: acquires runtimeLock
1944 **********************************************************************/
1945 __private_extern__ Method
1946 _protocol_getMethod(Protocol *p, SEL sel, BOOL isRequiredMethod, BOOL isInstanceMethod)
1948 OBJC_LOCK(&runtimeLock);
1949 Method result = _protocol_getMethod_nolock(newprotocol(p), sel,
1952 OBJC_UNLOCK(&runtimeLock);
1957 /***********************************************************************
1959 * Returns the name of the given protocol.
1960 * Locking: runtimeLock must not be held by the caller
1961 **********************************************************************/
1963 protocol_getName(Protocol *proto)
1965 return newprotocol(proto)->name;
1969 /***********************************************************************
1970 * protocol_getInstanceMethodDescription
1971 * Returns the description of a named instance method.
1972 * Locking: runtimeLock must not be held by the caller
1973 **********************************************************************/
1974 struct objc_method_description
1975 protocol_getMethodDescription(Protocol *p, SEL aSel,
1976 BOOL isRequiredMethod, BOOL isInstanceMethod)
1979 _protocol_getMethod(p, aSel, isRequiredMethod, isInstanceMethod);
1980 if (m) return *method_getDescription(m);
1981 else return (struct objc_method_description){NULL, NULL};
1985 /***********************************************************************
1986 * protocol_conformsToProtocol
1987 * Returns YES if self conforms to other.
1988 * Locking: runtimeLock must not be held by the caller
1989 **********************************************************************/
1990 BOOL protocol_conformsToProtocol(Protocol *self_gen, Protocol *other_gen)
1992 protocol_t *self = newprotocol(self_gen);
1993 protocol_t *other = newprotocol(other_gen);
1995 if (!self || !other) {
1999 if (0 == strcmp(self->name, other->name)) {
2003 if (self->protocols) {
2005 for (i = 0; i < self->protocols->count; i++) {
2006 protocol_t *proto = self->protocols->list[i];
2007 if (0 == strcmp(other->name, proto->name)) {
2010 if (protocol_conformsToProtocol((Protocol *)proto, other_gen)) {
2020 /***********************************************************************
2022 * Return YES if two protocols are equal (i.e. conform to each other)
2023 * Locking: acquires runtimeLock
2024 **********************************************************************/
2025 BOOL protocol_isEqual(Protocol *self, Protocol *other)
2027 if (self == other) return YES;
2028 if (!self || !other) return NO;
2030 if (!protocol_conformsToProtocol(self, other)) return NO;
2031 if (!protocol_conformsToProtocol(other, self)) return NO;
2037 /***********************************************************************
2038 * protocol_copyMethodDescriptionList
2039 * Returns descriptions of a protocol's methods.
2040 * Locking: acquires runtimeLock
2041 **********************************************************************/
2042 struct objc_method_description *
2043 protocol_copyMethodDescriptionList(Protocol *p,
2044 BOOL isRequiredMethod,BOOL isInstanceMethod,
2045 unsigned int *outCount)
2047 struct protocol_t *proto = newprotocol(p);
2048 struct objc_method_description *result = NULL;
2049 unsigned int count = 0;
2052 if (outCount) *outCount = 0;
2056 OBJC_LOCK(&runtimeLock);
2058 method_list_t *mlist = NULL;
2060 if (isRequiredMethod) {
2061 if (isInstanceMethod) {
2062 mlist = proto->instanceMethods;
2064 mlist = proto->classMethods;
2067 if (isInstanceMethod) {
2068 mlist = proto->optionalInstanceMethods;
2070 mlist = proto->optionalClassMethods;
2076 count = mlist->count;
2077 result = calloc(count + 1, sizeof(struct objc_method_description));
2078 for (i = 0; i < count; i++) {
2079 method_t *m = method_list_nth(mlist, i);
2080 result[i].name = sel_registerName((const char *)m->name);
2081 result[i].types = (char *)m->types;
2085 OBJC_UNLOCK(&runtimeLock);
2087 if (outCount) *outCount = count;
2092 /***********************************************************************
2093 * protocol_getProperty
2095 * Locking: acquires runtimeLock
2096 **********************************************************************/
2098 _protocol_getProperty_nolock(protocol_t *proto, const char *name,
2099 BOOL isRequiredProperty, BOOL isInstanceProperty)
2101 if (!isRequiredProperty || !isInstanceProperty) {
2102 // Only required instance properties are currently supported
2106 struct objc_property_list *plist;
2107 if ((plist = proto->instanceProperties)) {
2109 for (i = 0; i < plist->count; i++) {
2110 Property prop = property_list_nth(plist, i);
2111 if (0 == strcmp(name, prop->name)) {
2117 if (proto->protocols) {
2119 for (i = 0; i < proto->protocols->count; i++) {
2121 _protocol_getProperty_nolock(proto->protocols->list[i], name,
2123 isInstanceProperty);
2124 if (prop) return prop;
2131 Property protocol_getProperty(Protocol *p, const char *name,
2132 BOOL isRequiredProperty, BOOL isInstanceProperty)
2136 if (!p || !name) return NULL;
2138 OBJC_LOCK(&runtimeLock);
2139 result = _protocol_getProperty_nolock(newprotocol(p), name,
2141 isInstanceProperty);
2142 OBJC_UNLOCK(&runtimeLock);
2148 /***********************************************************************
2149 * protocol_copyPropertyList
2151 * Locking: acquires runtimeLock
2152 **********************************************************************/
2153 Property *protocol_copyPropertyList(Protocol *proto, unsigned int *outCount)
2155 Property *result = NULL;
2158 if (outCount) *outCount = 0;
2162 OBJC_LOCK(&runtimeLock);
2164 struct objc_property_list *plist = newprotocol(proto)->instanceProperties;
2165 result = copyPropertyList(plist, outCount);
2167 OBJC_UNLOCK(&runtimeLock);
2173 /***********************************************************************
2174 * protocol_copyProtocolList
2175 * Copies this protocol's incorporated protocols.
2176 * Does not copy those protocol's incorporated protocols in turn.
2177 * Locking: acquires runtimeLock
2178 **********************************************************************/
2179 Protocol **protocol_copyProtocolList(Protocol *p, unsigned int *outCount)
2181 unsigned int count = 0;
2182 Protocol **result = NULL;
2183 protocol_t *proto = newprotocol(p);
2186 if (outCount) *outCount = 0;
2190 OBJC_LOCK(&runtimeLock);
2192 if (proto->protocols) {
2193 count = (unsigned int)proto->protocols->count;
2196 result = malloc((count+1) * sizeof(Protocol *));
2199 for (i = 0; i < count; i++) {
2200 result[i] = (Protocol *)remapProtocol(proto->protocols->list[i]);
2205 OBJC_UNLOCK(&runtimeLock);
2207 if (outCount) *outCount = count;
2212 /***********************************************************************
2214 * Returns pointers to all classes.
2215 * This requires all classes be realized, which is regretfully non-lazy.
2216 * Locking: acquires runtimeLock
2217 **********************************************************************/
2219 objc_getClassList(Class *buffer, int bufferLen)
2221 OBJC_LOCK(&runtimeLock);
2227 NXMapTable *classes = realizedClasses();
2228 NXMapTable *unrealized = unrealizedClasses();
2231 count = NXCountMapTable(classes) + NXCountMapTable(unrealized);
2232 OBJC_UNLOCK(&runtimeLock);
2236 if (bufferLen > NXCountMapTable(classes) &&
2237 NXCountMapTable(unrealized) != 0)
2240 realizeAllClasses();
2244 state = NXInitMapState(classes);
2245 while (count < bufferLen &&
2246 NXNextMapState(classes, &state,
2247 (const void **)&name, (const void **)&cls))
2249 buffer[count++] = (Class)cls;
2252 OBJC_UNLOCK(&runtimeLock);
2258 /***********************************************************************
2259 * objc_copyProtocolList
2260 * Returns pointers to all protocols.
2261 * Locking: acquires runtimeLock
2262 **********************************************************************/
2264 objc_copyProtocolList(unsigned int *outCount)
2266 OBJC_LOCK(&runtimeLock);
2272 NXMapTable *protocol_map = protocols();
2275 count = NXCountMapTable(protocol_map);
2277 OBJC_UNLOCK(&runtimeLock);
2278 if (outCount) *outCount = 0;
2282 result = calloc(1 + count, sizeof(Protocol *));
2285 state = NXInitMapState(protocol_map);
2286 while (NXNextMapState(protocol_map, &state,
2287 (const void **)&name, (const void **)&proto))
2289 result[i++] = proto;
2293 assert(i == count+1);
2295 OBJC_UNLOCK(&runtimeLock);
2297 if (outCount) *outCount = count;
2302 /***********************************************************************
2304 * Get a protocol by name, or return NULL
2305 * Locking: acquires runtimeLock
2306 **********************************************************************/
2307 Protocol *objc_getProtocol(const char *name)
2309 OBJC_LOCK(&runtimeLock);
2310 Protocol *result = (Protocol *)NXMapGet(protocols(), name);
2311 OBJC_UNLOCK(&runtimeLock);
2316 /***********************************************************************
2317 * class_copyMethodList
2319 * Locking: acquires runtimeLock
2320 **********************************************************************/
2322 class_copyMethodList(Class cls_gen, unsigned int *outCount)
2324 struct class_t *cls = newcls(cls_gen);
2325 chained_method_list *mlist;
2326 unsigned int count = 0;
2327 Method *result = NULL;
2330 if (outCount) *outCount = 0;
2334 OBJC_LOCK(&runtimeLock);
2336 assert(isRealized(cls));
2338 methodizeClass(cls);
2340 for (mlist = cls->data->methods; mlist; mlist = mlist->next) {
2341 count += mlist->count;
2346 result = malloc((count + 1) * sizeof(Method));
2349 for (mlist = cls->data->methods; mlist; mlist = mlist->next) {
2351 for (i = 0; i < mlist->count; i++) {
2352 result[m++] = (Method)&mlist->list[i];
2358 OBJC_UNLOCK(&runtimeLock);
2360 if (outCount) *outCount = count;
2365 /***********************************************************************
2366 * class_copyIvarList
2368 * Locking: acquires runtimeLock
2369 **********************************************************************/
2371 class_copyIvarList(Class cls_gen, unsigned int *outCount)
2373 struct class_t *cls = newcls(cls_gen);
2374 const ivar_list_t *ivars;
2375 Ivar *result = NULL;
2376 unsigned int count = 0;
2380 if (outCount) *outCount = 0;
2384 OBJC_LOCK(&runtimeLock);
2386 assert(isRealized(cls));
2388 if ((ivars = cls->data->ro->ivars) && (count = ivars->count)) {
2389 result = malloc((count+1) * sizeof(Ivar));
2391 for (i = 0; i < ivars->count; i++) {
2392 result[i] = (Ivar)ivar_list_nth(ivars, i);
2397 OBJC_UNLOCK(&runtimeLock);
2399 if (outCount) *outCount = count;
2404 /***********************************************************************
2405 * class_copyPropertyList. Returns a heap block containing the
2406 * properties declared in the class, or NULL if the class
2407 * declares no properties. Caller must free the block.
2408 * Does not copy any superclass's properties.
2409 * Locking: acquires runtimeLock
2410 **********************************************************************/
2412 class_copyPropertyList(Class cls_gen, unsigned int *outCount)
2414 struct class_t *cls = newcls(cls_gen);
2415 chained_property_list *plist;
2416 unsigned int count = 0;
2417 Property *result = NULL;
2420 if (outCount) *outCount = 0;
2424 OBJC_LOCK(&runtimeLock);
2426 assert(isRealized(cls));
2428 // Attach any categories because they may provide more properties
2429 methodizeClass(cls);
2431 for (plist = cls->data->properties; plist; plist = plist->next) {
2432 count += plist->count;
2437 result = malloc((count + 1) * sizeof(Property));
2440 for (plist = cls->data->properties; plist; plist = plist->next) {
2442 for (i = 0; i < plist->count; i++) {
2443 result[p++] = (Property)&plist->list[i];
2449 OBJC_UNLOCK(&runtimeLock);
2451 if (outCount) *outCount = count;
2456 /***********************************************************************
2457 * _class_getLoadMethod
2459 * Called only from add_class_to_loadable_list.
2460 * Locking: runtimeLock must be held by the caller.
2461 **********************************************************************/
2462 __private_extern__ IMP
2463 _class_getLoadMethod(Class cls_gen)
2465 OBJC_CHECK_LOCKED(&runtimeLock);
2467 struct class_t *cls = newcls(cls_gen);
2468 const method_list_t *mlist;
2471 assert(isRealized(cls));
2472 assert(isRealized(cls->isa));
2473 assert(!isMethodized(cls));
2474 assert(!isMethodized(cls->isa));
2475 assert(!isMetaClass(cls));
2476 assert(isMetaClass(cls->isa));
2478 mlist = cls->isa->data->ro->baseMethods;
2479 if (mlist) for (i = 0; i < mlist->count; i++) {
2480 method_t *m = method_list_nth(mlist, i);
2481 if (0 == strcmp((const char *)m->name, "load")) {
2490 /***********************************************************************
2492 * Returns a category's name.
2494 **********************************************************************/
2495 __private_extern__ const char *
2496 _category_getName(Category cat)
2498 return newcategory(cat)->name;
2502 /***********************************************************************
2503 * _category_getClassName
2504 * Returns a category's class's name
2505 * Called only from add_category_to_loadable_list and
2506 * remove_category_from_loadable_list.
2507 * Locking: runtimeLock must be held by the caller
2508 **********************************************************************/
2509 __private_extern__ const char *
2510 _category_getClassName(Category cat)
2512 OBJC_CHECK_LOCKED(&runtimeLock);
2513 // cat->cls may have been remapped
2514 return getName(remapClass(newcategory(cat)->cls));
2518 /***********************************************************************
2519 * _category_getClass
2520 * Returns a category's class
2521 * Called only by call_category_loads.
2523 **********************************************************************/
2524 __private_extern__ Class
2525 _category_getClass(Category cat)
2527 // cat->cls may have been remapped
2528 struct class_t *result = remapClass(newcategory(cat)->cls);
2529 assert(isRealized(result)); // ok for call_category_loads' usage
2530 return (Class)result;
2534 /***********************************************************************
2535 * _category_getLoadMethod
2537 * Called only from add_category_to_loadable_list
2538 * Locking: runtimeLock must be held by the caller
2539 **********************************************************************/
2540 __private_extern__ IMP
2541 _category_getLoadMethod(Category cat)
2543 OBJC_CHECK_LOCKED(&runtimeLock);
2545 const method_list_t *mlist;
2548 mlist = newcategory(cat)->classMethods;
2549 if (mlist) for (i = 0; i < mlist->count; i++) {
2550 method_t *m = method_list_nth(mlist, i);
2551 if (0 == strcmp((const char *)m->name, "load")) {
2560 /***********************************************************************
2561 * class_copyProtocolList
2563 * Locking: acquires runtimeLock
2564 **********************************************************************/
2566 class_copyProtocolList(Class cls_gen, unsigned int *outCount)
2568 struct class_t *cls = newcls(cls_gen);
2570 struct protocol_list_t **p;
2571 unsigned int count = 0;
2573 Protocol **result = NULL;
2576 if (outCount) *outCount = 0;
2580 OBJC_LOCK(&runtimeLock);
2582 assert(isRealized(cls));
2584 // Attach any categories because they may provide more protocols
2585 methodizeClass(cls);
2587 for (p = cls->data->protocols; p && *p; p++) {
2588 count += (uint32_t)(*p)->count;
2592 result = malloc((count+1) * sizeof(Protocol *));
2594 for (p = cls->data->protocols; p && *p; p++) {
2595 for (i = 0; i < (*p)->count; i++) {
2596 *r++ = (Protocol *)remapProtocol((*p)->list[i]);
2602 OBJC_UNLOCK(&runtimeLock);
2604 if (outCount) *outCount = count;
2609 /***********************************************************************
2610 * _objc_copyClassNamesForImage
2612 * Locking: acquires runtimeLock
2613 **********************************************************************/
2614 __private_extern__ const char **
2615 _objc_copyClassNamesForImage(header_info *hi, unsigned int *outCount)
2618 class_t **classlist;
2621 OBJC_LOCK(&runtimeLock);
2623 classlist = _getObjc2ClassList(hi, &count);
2624 names = malloc((count+1) * sizeof(const char *));
2626 for (i = 0; i < count; i++) {
2627 names[i] = getName(classlist[i]);
2629 names[count] = NULL;
2631 OBJC_UNLOCK(&runtimeLock);
2633 if (outCount) *outCount = (unsigned int)count;
2638 /***********************************************************************
2642 **********************************************************************/
2643 __private_extern__ Cache
2644 _class_getCache(Class cls)
2646 return newcls(cls)->cache;
2650 /***********************************************************************
2651 * _class_getInstanceSize
2654 **********************************************************************/
2655 __private_extern__ size_t
2656 _class_getInstanceSize(Class cls)
2659 return instanceSize(newcls(cls));
2663 instanceSize(struct class_t *cls)
2666 assert(isRealized(cls));
2667 // fixme rdar://5244378
2668 return (uint32_t)((cls->data->ro->instanceSize + 7) & ~7UL);
2672 /***********************************************************************
2676 **********************************************************************/
2678 class_getVersion(Class cls)
2681 assert(isRealized(newcls(cls)));
2682 return newcls(cls)->data->version;
2686 /***********************************************************************
2690 **********************************************************************/
2691 __private_extern__ void
2692 _class_setCache(Class cls, Cache cache)
2694 newcls(cls)->cache = cache;
2698 /***********************************************************************
2702 **********************************************************************/
2704 class_setVersion(Class cls, int version)
2707 assert(isRealized(newcls(cls)));
2708 newcls(cls)->data->version = version;
2712 /***********************************************************************
2715 * Locking: acquires runtimeLock
2716 **********************************************************************/
2717 __private_extern__ const char *_class_getName(Class cls)
2719 if (!cls) return "nil";
2720 // fixme hack OBJC_LOCK(&runtimeLock);
2721 const char *name = getName(newcls(cls));
2722 // OBJC_UNLOCK(&runtimeLock);
2727 /***********************************************************************
2730 * Locking: runtimeLock must be held by the caller
2731 **********************************************************************/
2733 getName(struct class_t *cls)
2735 // fixme hack OBJC_CHECK_LOCKED(&runtimeLock);
2738 if (isRealized(cls)) {
2739 return cls->data->ro->name;
2741 return ((const struct class_ro_t *)cls->data)->name;
2746 /***********************************************************************
2747 * _class_getMethodNoSuper_nolock
2749 * Locking: runtimeLock must be held by the caller
2750 **********************************************************************/
2752 _class_getMethodNoSuper_nolock(struct class_t *cls, SEL sel)
2754 OBJC_CHECK_LOCKED(&runtimeLock);
2756 chained_method_list *mlist;
2759 assert(isRealized(cls));
2763 methodizeClass(cls);
2765 for (mlist = cls->data->methods; mlist; mlist = mlist->next) {
2766 for (i = 0; i < mlist->count; i++) {
2767 method_t *m = &mlist->list[i];
2768 if (m->name == sel) return (Method)m;
2776 /***********************************************************************
2777 * _class_getMethodNoSuper
2779 * Locking: acquires runtimeLock
2780 **********************************************************************/
2781 __private_extern__ Method
2782 _class_getMethodNoSuper(Class cls, SEL sel)
2784 OBJC_LOCK(&runtimeLock);
2785 Method result = _class_getMethodNoSuper_nolock(newcls(cls), sel);
2786 OBJC_UNLOCK(&runtimeLock);
2791 /***********************************************************************
2794 * Locking: acquires runtimeLock
2795 **********************************************************************/
2796 __private_extern__ Method _class_getMethod(Class cls, SEL sel)
2803 assert(isRealized(newcls(cls)));
2805 while (cls && ((m = _class_getMethodNoSuper(cls, sel))) == NULL) {
2806 cls = class_getSuperclass(cls);
2813 /***********************************************************************
2816 * Locking: acquires runtimeLock
2817 **********************************************************************/
2818 Property class_getProperty(Class cls_gen, const char *name)
2820 Property result = NULL;
2821 chained_property_list *plist;
2822 struct class_t *cls = newcls(cls_gen);
2824 if (!cls || !name) return NULL;
2826 OBJC_LOCK(&runtimeLock);
2828 assert(isRealized(cls));
2829 methodizeClass(cls);
2831 for ( ; cls; cls = getSuperclass(cls)) {
2832 for (plist = cls->data->properties; plist; plist = plist->next) {
2834 for (i = 0; i < plist->count; i++) {
2835 if (0 == strcmp(name, plist->list[i].name)) {
2836 result = &plist->list[i];
2844 OBJC_UNLOCK(&runtimeLock);
2850 /***********************************************************************
2852 **********************************************************************/
2853 __private_extern__ BOOL _class_isMetaClass(Class cls)
2855 if (!cls) return NO;
2856 return isMetaClass(newcls(cls));
2860 isMetaClass(struct class_t *cls)
2863 assert(isRealized(cls));
2864 return (cls->data->ro->flags & RO_META) ? YES : NO;
2868 __private_extern__ Class _class_getMeta(Class cls)
2871 if (isMetaClass(newcls(cls))) return cls;
2872 else return ((id)cls)->isa;
2876 /***********************************************************************
2878 **********************************************************************/
2879 __private_extern__ BOOL
2880 _class_isInitializing(Class cls_gen)
2882 struct class_t *cls = newcls(_class_getMeta(cls_gen));
2883 return (cls->data->flags & RW_INITIALIZING) ? YES : NO;
2887 /***********************************************************************
2889 **********************************************************************/
2890 __private_extern__ BOOL
2891 _class_isInitialized(Class cls_gen)
2893 struct class_t *cls = newcls(_class_getMeta(cls_gen));
2894 return (cls->data->flags & RW_INITIALIZED) ? YES : NO;
2898 /***********************************************************************
2900 **********************************************************************/
2901 __private_extern__ void
2902 _class_setInitializing(Class cls_gen)
2904 struct class_t *cls = newcls(_class_getMeta(cls_gen));
2905 changeInfo(cls, RW_INITIALIZING, 0);
2909 /***********************************************************************
2911 **********************************************************************/
2912 __private_extern__ void
2913 _class_setInitialized(Class cls_gen)
2915 struct class_t *cls = newcls(_class_getMeta(cls_gen));
2916 changeInfo(cls, RW_INITIALIZED, RW_INITIALIZING);
2920 /***********************************************************************
2922 **********************************************************************/
2923 __private_extern__ BOOL
2924 _class_shouldGrowCache(Class cls)
2926 return YES; // fixme good or bad for memory use?
2930 /***********************************************************************
2932 **********************************************************************/
2933 __private_extern__ void
2934 _class_setGrowCache(Class cls, BOOL grow)
2936 // fixme good or bad for memory use?
2940 /***********************************************************************
2944 **********************************************************************/
2945 __private_extern__ BOOL
2946 _class_isLoadable(Class cls)
2948 assert(isRealized(newcls(cls)));
2949 return YES; // any class registered for +load is definitely loadable
2953 /***********************************************************************
2955 **********************************************************************/
2956 __private_extern__ BOOL
2957 _class_hasCxxStructorsNoSuper(Class cls)
2959 assert(isRealized(newcls(cls)));
2960 return (newcls(cls)->data->ro->flags & RO_HAS_CXX_STRUCTORS) ? YES : NO;
2964 /***********************************************************************
2966 **********************************************************************/
2967 __private_extern__ BOOL
2968 _class_shouldFinalizeOnMainThread(Class cls)
2970 assert(isRealized(newcls(cls)));
2971 return (newcls(cls)->data->flags & RW_FINALIZE_ON_MAIN_THREAD) ? YES : NO;
2975 /***********************************************************************
2977 **********************************************************************/
2978 __private_extern__ void
2979 _class_setFinalizeOnMainThread(Class cls)
2981 assert(isRealized(newcls(cls)));
2982 changeInfo(newcls(cls), RW_FINALIZE_ON_MAIN_THREAD, 0);
2986 /***********************************************************************
2988 * fixme assert realized to get superclass remapping?
2989 **********************************************************************/
2990 __private_extern__ Class
2991 _class_getSuperclass(Class cls)
2993 return (Class)getSuperclass(newcls(cls));
2996 static struct class_t *
2997 getSuperclass(struct class_t *cls)
2999 if (!cls) return NULL;
3000 return cls->superclass;
3004 /***********************************************************************
3005 * class_getIvarLayout
3006 * Called by the garbage collector.
3007 * The class must be NULL or already realized.
3009 **********************************************************************/
3011 class_getIvarLayout(Class cls_gen)
3013 class_t *cls = newcls(cls_gen);
3014 if (cls) return (const char *)cls->data->ro->ivarLayout;
3019 /***********************************************************************
3020 * class_getWeakIvarLayout
3021 * Called by the garbage collector.
3022 * The class must be NULL or already realized.
3024 **********************************************************************/
3026 class_getWeakIvarLayout(Class cls_gen)
3028 class_t *cls = newcls(cls_gen);
3029 if (cls) return (const char *)cls->data->ro->weakIvarLayout;
3034 /***********************************************************************
3035 * class_setIvarLayout
3036 * Changes the class's GC scan layout.
3037 * NULL layout means no unscanned ivars
3038 * The class must be under construction.
3039 * fixme: sanity-check layout vs instance size?
3040 * fixme: sanity-check layout vs superclass?
3041 * Locking: acquires runtimeLock
3042 **********************************************************************/
3044 class_setIvarLayout(Class cls_gen, const char *layout)
3046 class_t *cls = newcls(cls_gen);
3049 OBJC_LOCK(&runtimeLock);
3051 // Can only change layout of in-construction classes.
3052 // note: if modifications to post-construction classes were
3053 // allowed, there would be a race below (us vs. concurrent GC scan)
3054 if (!(cls->data->flags & RW_CONSTRUCTING)) {
3055 _objc_inform("*** Can't set ivar layout for already-registered "
3056 "class '%s'", getName(cls));
3057 OBJC_UNLOCK(&runtimeLock);
3061 class_ro_t *ro_w = make_ro_writeable(cls->data);
3063 try_free(ro_w->ivarLayout);
3064 ro_w->ivarLayout = (unsigned char *)_strdup_internal(layout);
3066 OBJC_UNLOCK(&runtimeLock);
3070 /***********************************************************************
3071 * class_setWeakIvarLayout
3072 * Changes the class's GC weak layout.
3073 * NULL layout means no weak ivars
3074 * The class must be under construction.
3075 * fixme: sanity-check layout vs instance size?
3076 * fixme: sanity-check layout vs superclass?
3077 * Locking: acquires runtimeLock
3078 **********************************************************************/
3080 class_setWeakIvarLayout(Class cls_gen, const char *layout)
3082 class_t *cls = newcls(cls_gen);
3085 OBJC_LOCK(&runtimeLock);
3087 // Can only change layout of in-construction classes.
3088 // note: if modifications to post-construction classes were
3089 // allowed, there would be a race below (us vs. concurrent GC scan)
3090 if (!(cls->data->flags & RW_CONSTRUCTING)) {
3091 _objc_inform("*** Can't set weak ivar layout for already-registered "
3092 "class '%s'", getName(cls));
3093 OBJC_UNLOCK(&runtimeLock);
3097 class_ro_t *ro_w = make_ro_writeable(cls->data);
3099 try_free(ro_w->weakIvarLayout);
3100 ro_w->weakIvarLayout = (unsigned char *)_strdup_internal(layout);
3102 OBJC_UNLOCK(&runtimeLock);
3106 /***********************************************************************
3107 * _class_getVariable
3109 * Locking: acquires runtimeLock
3110 **********************************************************************/
3111 __private_extern__ Ivar
3112 _class_getVariable(Class cls, const char *name)
3114 OBJC_LOCK(&runtimeLock);
3116 for ( ; cls != Nil; cls = class_getSuperclass(cls)) {
3117 struct ivar_t *ivar = getIvar(newcls(cls), name);
3119 OBJC_UNLOCK(&runtimeLock);
3124 OBJC_UNLOCK(&runtimeLock);
3130 /***********************************************************************
3131 * class_conformsToProtocol
3133 * Locking: acquires runtimeLock
3134 **********************************************************************/
3135 BOOL class_conformsToProtocol(Class cls_gen, Protocol *proto)
3137 Protocol **protocols;
3138 unsigned int count, i;
3143 protocols = class_copyProtocolList(cls_gen, &count);
3145 for (i = 0; i < count; i++) {
3146 if (protocols[i] == proto ||
3147 protocol_conformsToProtocol(protocols[i], proto))
3154 if (protocols) free(protocols);
3160 /***********************************************************************
3163 * Locking: acquires runtimeLock
3164 **********************************************************************/
3166 _class_addMethod(Class cls_gen, SEL name, IMP imp,
3167 const char *types, BOOL replace)
3169 struct class_t *cls = newcls(cls_gen);
3172 if (!types) types = "";
3174 OBJC_LOCK(&runtimeLock);
3176 assert(isRealized(cls));
3177 // methodizeClass(cls); _class_getMethodNoSuper() does this below
3180 if ((m = _class_getMethodNoSuper_nolock(cls, name))) {
3183 result = method_getImplementation(m);
3185 method_setImplementation(m, imp);
3189 chained_method_list *newlist;
3190 newlist = _calloc_internal(sizeof(*newlist) + sizeof(method_t), 1);
3192 newlist->list[0].name = name;
3193 newlist->list[0].types = strdup(types);
3194 newlist->list[0].imp = imp;
3196 newlist->next = cls->data->methods;
3197 cls->data->methods = newlist;
3202 OBJC_UNLOCK(&runtimeLock);
3209 class_addMethod(Class cls, SEL name, IMP imp, const char *types)
3211 if (!cls) return NO;
3213 IMP old = _class_addMethod(cls, name, imp, types, NO);
3214 return old ? NO : YES;
3219 class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
3221 if (!cls) return NULL;
3223 return _class_addMethod(cls, name, imp, types, YES);
3227 /***********************************************************************
3229 * Adds an ivar to a class.
3230 * Locking: acquires runtimeLock
3231 **********************************************************************/
3233 class_addIvar(Class cls_gen, const char *name, size_t size,
3234 uint8_t alignment, const char *type)
3236 struct class_t *cls = newcls(cls_gen);
3238 if (!cls) return NO;
3240 if (!type) type = "";
3241 if (name && 0 == strcmp(name, "")) name = NULL;
3243 OBJC_LOCK(&runtimeLock);
3245 assert(isRealized(cls));
3247 // No class variables
3248 if (isMetaClass(cls)) {
3249 OBJC_UNLOCK(&runtimeLock);
3253 // Can only add ivars to in-construction classes.
3254 if (!(cls->data->flags & RW_CONSTRUCTING)) {
3255 OBJC_UNLOCK(&runtimeLock);
3259 // Check for existing ivar with this name, unless it's anonymous.
3260 // Check for too-big ivar.
3261 // fixme check for superclass ivar too?
3262 if ((name && getIvar(cls, name)) || size > UINT32_MAX) {
3263 OBJC_UNLOCK(&runtimeLock);
3267 class_ro_t *ro_w = make_ro_writeable(cls->data);
3269 // fixme allocate less memory here
3271 ivar_list_t *oldlist, *newlist;
3272 if ((oldlist = (ivar_list_t *)cls->data->ro->ivars)) {
3273 size_t oldsize = ivar_list_size(oldlist);
3274 newlist = _calloc_internal(oldsize + oldlist->entsize, 1);
3275 memcpy(newlist, oldlist, oldsize);
3276 _free_internal(oldlist);
3278 newlist = _calloc_internal(sizeof(ivar_list_t), 1);
3279 newlist->entsize = (uint32_t)sizeof(ivar_t);
3282 uint32_t offset = instanceSize(cls);
3283 uint32_t alignMask = (1<<alignment)-1;
3284 offset = (offset + alignMask) & ~alignMask;
3286 ivar_t *ivar = ivar_list_nth(newlist, newlist->count++);
3287 ivar->offset = _malloc_internal(sizeof(*ivar->offset));
3288 *ivar->offset = offset;
3289 ivar->name = name ? _strdup_internal(name) : NULL;
3290 ivar->type = _strdup_internal(type);
3291 ivar->alignment = alignment;
3292 ivar->size = (uint32_t)size;
3294 ro_w->ivars = newlist;
3295 ro_w->instanceSize = (uint32_t)(offset + size);
3297 // Ivar layout updated in registerClass.
3299 OBJC_UNLOCK(&runtimeLock);
3305 /***********************************************************************
3307 * Adds a protocol to a class.
3308 * Locking: acquires runtimeLock
3309 **********************************************************************/
3310 BOOL class_addProtocol(Class cls_gen, Protocol *protocol_gen)
3312 class_t *cls = newcls(cls_gen);
3313 protocol_t *protocol = newprotocol(protocol_gen);
3314 protocol_list_t *plist;
3315 protocol_list_t **plistp;
3317 if (!cls) return NO;
3318 if (class_conformsToProtocol(cls_gen, protocol_gen)) return NO;
3320 OBJC_LOCK(&runtimeLock);
3322 assert(isRealized(cls));
3325 plist = _malloc_internal(sizeof(protocol_list_t) + sizeof(protocol_t *));
3327 plist->list[0] = protocol;
3329 unsigned int count = 0;
3330 for (plistp = cls->data->protocols; plistp && *plistp; plistp++) {
3334 cls->data->protocols =
3335 _realloc_internal(cls->data->protocols,
3336 (count+2) * sizeof(protocol_list_t *));
3337 cls->data->protocols[count] = plist;
3338 cls->data->protocols[count+1] = NULL;
3342 OBJC_UNLOCK(&runtimeLock);
3348 /***********************************************************************
3350 * Look up a class by name, and realize it.
3351 * Locking: acquires runtimeLock
3352 * GrP fixme zerolink needs class handler for objc_getClass
3353 **********************************************************************/
3354 __private_extern__ id
3355 look_up_class(const char *name,
3356 BOOL includeUnconnected __attribute__((unused)),
3357 BOOL includeClassHandler __attribute__((unused)))
3359 if (!name) return nil;
3361 OBJC_LOCK(&runtimeLock);
3362 id result = (id)getClass(name);
3363 realizeClass(result);
3364 OBJC_UNLOCK(&runtimeLock);
3369 /***********************************************************************
3370 * objc_duplicateClass
3372 * Locking: acquires runtimeLock
3373 **********************************************************************/
3375 objc_duplicateClass(Class original_gen, const char *name,
3378 struct class_t *original = newcls(original_gen);
3379 chained_method_list **m;
3380 struct class_t *duplicate;
3382 OBJC_LOCK(&runtimeLock);
3384 assert(isRealized(original));
3385 methodizeClass(original);
3386 assert(!isMetaClass(original));
3388 duplicate = (struct class_t *)
3389 calloc(instanceSize(original->isa) + extraBytes, 1);
3390 if (instanceSize(original->isa) < sizeof(class_t)) {
3391 _objc_inform("busted! %s\n", original->data->ro->name);
3395 duplicate->isa = original->isa;
3396 duplicate->superclass = original->superclass;
3397 duplicate->cache = (Cache)&_objc_empty_cache;
3398 #warning GrP fixme vtable
3399 // duplicate->vtable = (IMP *)&_objc_empty_vtable;
3401 duplicate->data = _calloc_internal(sizeof(*original->data), 1);
3402 duplicate->data->flags = original->data->flags | RW_COPIED_RO;
3403 duplicate->data->version = original->data->version;
3404 duplicate->data->firstSubclass = NULL;
3405 duplicate->data->nextSiblingClass = NULL;
3407 duplicate->data->ro =
3408 _memdup_internal(original->data->ro, sizeof(*original->data->ro));
3409 *(char **)&duplicate->data->ro->name = _strdup_internal(name);
3411 duplicate->data->methods = original->data->methods;
3412 for (m = &duplicate->data->methods; *m != NULL; m = &(*m)->next) {
3413 *m = _memdup_internal(*m, chained_mlist_size(*m));
3416 // fixme dies when categories are added to the base
3417 duplicate->data->properties = original->data->properties;
3418 duplicate->data->protocols = original->data->protocols;
3420 if (duplicate->superclass) {
3421 addSubclass(duplicate->superclass, duplicate);
3424 addRealizedClass(duplicate, duplicate->data->ro->name);
3426 if (PrintConnecting) {
3427 _objc_inform("CLASS: realizing class '%s' (duplicate of %s) %p %p",
3428 name, original->data->ro->name,
3429 duplicate, duplicate->data->ro);
3432 OBJC_UNLOCK(&runtimeLock);
3434 return (Class)duplicate;
3438 /***********************************************************************
3439 * objc_allocateClassPair
3441 * Locking: acquires runtimeLock
3442 **********************************************************************/
3443 Class objc_allocateClassPair(Class superclass_gen, const char *name,
3446 class_t *superclass = newcls(superclass_gen);
3447 class_t *cls, *meta;
3448 class_ro_t *cls_ro_w, *meta_ro_w;
3450 OBJC_LOCK(&runtimeLock);
3452 if (getClass(name)) {
3453 OBJC_UNLOCK(&runtimeLock);
3456 // fixme reserve class against simmultaneous allocation
3458 if (superclass) assert(isRealized(superclass));
3460 if (superclass && superclass->data->flags & RW_CONSTRUCTING) {
3461 // Can't make subclass of an in-construction class
3462 OBJC_UNLOCK(&runtimeLock);
3466 // Allocate new classes.
3468 cls = _calloc_internal(instanceSize(superclass->isa) + extraBytes, 1);
3469 meta = _calloc_internal(instanceSize(superclass->isa->isa) + extraBytes, 1);
3471 cls = _calloc_internal(sizeof(class_t) + extraBytes, 1);
3472 meta = _calloc_internal(sizeof(class_t) + extraBytes, 1);
3475 cls->data = _calloc_internal(sizeof(class_rw_t), 1);
3476 meta->data = _calloc_internal(sizeof(class_rw_t), 1);
3477 cls_ro_w = _calloc_internal(sizeof(class_ro_t), 1);
3478 meta_ro_w = _calloc_internal(sizeof(class_ro_t), 1);
3479 cls->data->ro = cls_ro_w;
3480 meta->data->ro = meta_ro_w;
3483 cls->cache = (Cache)&_objc_empty_cache;
3484 meta->cache = (Cache)&_objc_empty_cache;
3485 cls->vtable = (IMP *)&_objc_empty_vtable;
3486 meta->vtable = (IMP *)&_objc_empty_vtable;
3488 cls->data->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED;
3489 meta->data->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED;
3490 cls->data->version = 0;
3491 meta->data->version = 7;
3493 cls_ro_w->flags = 0;
3494 meta_ro_w->flags = RO_META;
3496 cls_ro_w->flags |= RO_ROOT;
3497 meta_ro_w->flags |= RO_ROOT;
3500 cls_ro_w->instanceStart = instanceSize(superclass);
3501 meta_ro_w->instanceStart = instanceSize(superclass->isa);
3502 cls_ro_w->instanceSize = cls_ro_w->instanceStart;
3503 meta_ro_w->instanceSize = meta_ro_w->instanceStart;
3505 cls_ro_w->instanceStart = 0;
3506 meta_ro_w->instanceStart = (uint32_t)sizeof(class_t);
3507 cls_ro_w->instanceSize = (uint32_t)sizeof(id); // just an isa
3508 meta_ro_w->instanceSize = meta_ro_w->instanceStart;
3511 cls_ro_w->name = _strdup_internal(name);
3512 meta_ro_w->name = _strdup_internal(name);
3514 // Connect to superclasses and metaclasses
3517 meta->isa = superclass->isa->isa;
3518 cls->superclass = superclass;
3519 meta->superclass = superclass->isa;
3520 addSubclass(superclass, cls);
3521 addSubclass(superclass->isa, meta);
3524 cls->superclass = Nil;
3525 meta->superclass = cls;
3526 addSubclass(cls, meta);
3529 OBJC_UNLOCK(&runtimeLock);
3535 /***********************************************************************
3536 * objc_registerClassPair
3538 * Locking: acquires runtimeLock
3539 **********************************************************************/
3540 void objc_registerClassPair(Class cls_gen)
3542 class_t *cls = newcls(cls_gen);
3544 OBJC_LOCK(&runtimeLock);
3546 if ((cls->data->flags & RW_CONSTRUCTED) ||
3547 (cls->isa->data->flags & RW_CONSTRUCTED))
3549 _objc_inform("objc_registerClassPair: class '%s' was already "
3550 "registered!", cls->data->ro->name);
3551 OBJC_UNLOCK(&runtimeLock);
3555 if (!(cls->data->flags & RW_CONSTRUCTING) ||
3556 !(cls->isa->data->flags & RW_CONSTRUCTING))
3558 _objc_inform("objc_registerClassPair: class '%s' was not "
3559 "allocated with objc_allocateClassPair!",
3560 cls->data->ro->name);
3561 OBJC_UNLOCK(&runtimeLock);
3565 // Build ivar layouts
3567 struct class_t *supercls = getSuperclass(cls);
3568 class_ro_t *ro_w = (class_ro_t *)cls->data->ro;
3570 if (ro_w->ivarLayout) {
3571 // Class builder already called class_setIvarLayout.
3573 else if (!supercls) {
3574 // Root class. Scan conservatively (should be isa ivar only).
3575 // ivar_layout is already NULL.
3577 else if (ro_w->ivars == NULL) {
3578 // No local ivars. Use superclass's layouts.
3579 ro_w->ivarLayout = (unsigned char *)
3580 _strdup_internal((char *)supercls->data->ro->ivarLayout);
3583 // Has local ivars. Build layouts based on superclass.
3584 layout_bitmap bitmap =
3585 layout_bitmap_create(supercls->data->ro->ivarLayout,
3586 instanceSize(supercls),
3587 instanceSize(cls), NO);
3589 for (i = 0; i < ro_w->ivars->count; i++) {
3590 ivar_t *iv = ivar_list_nth(ro_w->ivars, i);
3591 layout_bitmap_set_ivar(bitmap, iv->type, *iv->offset);
3593 ro_w->ivarLayout = layout_string_create(bitmap);
3594 layout_bitmap_free(bitmap);
3597 if (ro_w->weakIvarLayout) {
3598 // Class builder already called class_setWeakIvarLayout.
3600 else if (!supercls) {
3601 // Root class. No weak ivars (should be isa ivar only).
3602 // weak_ivar_layout is already NULL.
3604 else if (ro_w->ivars == NULL) {
3605 // No local ivars. Use superclass's layout.
3606 ro_w->weakIvarLayout = (unsigned char *)
3607 _strdup_internal((char *)supercls->data->ro->weakIvarLayout);
3610 // Has local ivars. Build layout based on superclass.
3611 // No way to add weak ivars yet.
3612 ro_w->weakIvarLayout = (unsigned char *)
3613 _strdup_internal((char *)supercls->data->ro->weakIvarLayout);
3617 // Clear "under construction" bit, set "done constructing" bit
3618 cls->data->flags &= ~RW_CONSTRUCTING;
3619 cls->isa->data->flags &= ~RW_CONSTRUCTING;
3620 cls->data->flags |= RW_CONSTRUCTED;
3621 cls->isa->data->flags |= RW_CONSTRUCTED;
3623 // Add to realized and uninitialized classes
3624 addRealizedClass(cls, cls->data->ro->name);
3625 addUninitializedClass(cls, cls->isa);
3627 OBJC_UNLOCK(&runtimeLock);
3631 static void unload_class(class_t *cls)
3635 chained_method_list *mlist = cls->data->methods;
3637 chained_method_list *dead = mlist;
3638 mlist = mlist->next;
3639 for (i = 0; i < dead->count; i++) {
3640 try_free(dead->list[i].types);
3645 const ivar_list_t *ilist = cls->data->ro->ivars;
3647 for (i = 0; i < ilist->count; i++) {
3648 const ivar_t *ivar = ivar_list_nth(ilist, i);
3649 try_free(ivar->offset);
3650 try_free(ivar->name);
3651 try_free(ivar->type);
3656 protocol_list_t **plistp = cls->data->protocols;
3657 for (plistp = cls->data->protocols; plistp && *plistp; plistp++) {
3660 try_free(cls->data->protocols);
3665 try_free(cls->data->ro->ivarLayout);
3666 try_free(cls->data->ro->weakIvarLayout);
3667 try_free(cls->data->ro->name);
3668 try_free(cls->data->ro);
3669 try_free(cls->data);
3670 if (cls->cache != (Cache)&_objc_empty_cache) _cache_free(cls->cache);
3674 void objc_disposeClassPair(Class cls_gen)
3676 class_t *cls = newcls(cls_gen);
3678 OBJC_LOCK(&runtimeLock);
3680 if (!(cls->data->flags & (RW_CONSTRUCTED|RW_CONSTRUCTING)) ||
3681 !(cls->isa->data->flags & (RW_CONSTRUCTED|RW_CONSTRUCTING)))
3683 // class not allocated with objc_allocateClassPair
3684 // disposing still-unregistered class is OK!
3685 _objc_inform("objc_disposeClassPair: class '%s' was not "
3686 "allocated with objc_allocateClassPair!",
3687 cls->data->ro->name);
3688 OBJC_UNLOCK(&runtimeLock);
3692 if (isMetaClass(cls)) {
3693 _objc_inform("objc_disposeClassPair: class '%s' is a metaclass, "
3694 "not a class!", cls->data->ro->name);
3695 OBJC_UNLOCK(&runtimeLock);
3699 class_t *supercls = getSuperclass(cls);
3701 // Shouldn't have any live subclasses.
3702 if (cls->data->firstSubclass) {
3703 _objc_inform("objc_disposeClassPair: class '%s' still has subclasses, "
3704 "including '%s'!", cls->data->ro->name,
3705 getName(cls->data->firstSubclass));
3707 if (cls->isa->data->firstSubclass) {
3708 _objc_inform("objc_disposeClassPair: class '%s' still has subclasses, "
3709 "including '%s'!", cls->data->ro->name,
3710 getName(cls->isa->data->firstSubclass));
3713 // Remove from superclass's subclass list
3714 // Note that cls and cls->isa may have different lists.
3716 removeSubclass(getSuperclass(cls), cls);
3717 removeSubclass(getSuperclass(cls->isa), cls->isa);
3720 // Remove from class hashes
3721 removeRealizedClass(cls);
3722 removeUninitializedClass(cls);
3724 // Deallocate memory
3725 unload_class(cls->isa);
3728 OBJC_UNLOCK(&runtimeLock);
3733 /***********************************************************************
3734 * class_createInstanceFromZone
3737 **********************************************************************/
3739 class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone)
3741 if (cls) assert(isRealized(newcls(cls)));
3742 return _internal_class_createInstanceFromZone(cls, extraBytes, zone);
3746 /***********************************************************************
3747 * class_createInstance
3750 **********************************************************************/
3752 class_createInstance(Class cls, size_t extraBytes)
3754 return class_createInstanceFromZone(cls, extraBytes, NULL);
3758 /***********************************************************************
3759 * object_copyFromZone
3762 **********************************************************************/
3764 object_copyFromZone(id oldObj, size_t extraBytes, void *zone)
3769 if (!oldObj) return nil;
3771 size = _class_getInstanceSize(oldObj->isa) + extraBytes;
3772 obj = malloc_zone_calloc(zone, size, 1);
3773 if (!obj) return nil;
3775 // fixme this doesn't handle C++ ivars correctly (#4619414)
3776 bcopy(oldObj, obj, size);
3782 /***********************************************************************
3786 **********************************************************************/
3788 object_copy(id oldObj, size_t extraBytes)
3790 return object_copyFromZone(oldObj, extraBytes, malloc_default_zone());
3794 /***********************************************************************
3798 **********************************************************************/
3800 object_dispose(id obj)
3802 return _internal_object_dispose(obj);
3806 /***********************************************************************
3807 * _class_getFreedObjectClass
3810 **********************************************************************/
3811 __private_extern__ Class
3812 _class_getFreedObjectClass(void)
3814 return Nil; // fixme
3817 /***********************************************************************
3818 * _class_getNonexistentObjectClass
3821 **********************************************************************/
3822 __private_extern__ Class
3823 _class_getNonexistentObjectClass(void)
3825 return Nil; // fixme
3828 /***********************************************************************
3829 * _objc_getFreedObjectClass
3832 **********************************************************************/
3833 Class _objc_getFreedObjectClass (void)
3835 return _class_getFreedObjectClass();
3838 extern id objc_msgSend_fixup(id, SEL, ...);
3839 extern id objc_msgSend_fixedup(id, SEL, ...);
3840 extern id objc_msgSendSuper2_fixup(id, SEL, ...);
3841 extern id objc_msgSendSuper2_fixedup(id, SEL, ...);
3842 extern id objc_msgSend_stret_fixup(id, SEL, ...);
3843 extern id objc_msgSend_stret_fixedup(id, SEL, ...);
3844 extern id objc_msgSendSuper2_stret_fixup(id, SEL, ...);
3845 extern id objc_msgSendSuper2_stret_fixedup(id, SEL, ...);
3847 /***********************************************************************
3848 * _objc_fixupMessageRef
3849 * Fixes up message ref *msg.
3850 * obj is the receiver. supr is NULL for non-super messages
3851 * Locking: acquires runtimeLock
3852 **********************************************************************/
3853 __private_extern__ IMP
3854 _objc_fixupMessageRef(id obj, struct objc_super2 *supr, message_ref *msg)
3859 OBJC_CHECK_UNLOCKED(&runtimeLock);
3862 // normal message - search obj->isa for the method implementation
3863 isa = (class_t *)obj->isa;
3865 if (!isRealized(isa)) {
3866 // obj is a class object, isa is its metaclass
3868 OBJC_LOCK(&runtimeLock);
3869 if (!isRealized(isa)) {
3870 cls = realizeClass((class_t *)obj);
3872 // shouldn't have instances of unrealized classes!
3873 assert(isMetaClass(isa));
3874 // shouldn't be relocating classes here!
3875 assert(cls == (class_t *)obj);
3877 OBJC_UNLOCK(&runtimeLock);
3881 // this is objc_msgSend_super, and supr->current_class->superclass
3882 // is the class to search for the method implementation
3883 assert(isRealized((class_t *)supr->current_class));
3884 isa = getSuperclass((class_t *)supr->current_class);
3887 msg->sel = sel_registerName((const char *)msg->sel);
3888 imp = _class_lookupMethodAndLoadCache((Class)isa, msg->sel);
3890 if (msg->imp == (IMP)&objc_msgSend_fixup) {
3891 msg->imp = (IMP)&objc_msgSend_fixedup;
3893 else if (msg->imp == (IMP)&objc_msgSendSuper2_fixup) {
3894 msg->imp = (IMP)&objc_msgSendSuper2_fixedup;
3896 else if (msg->imp == (IMP)&objc_msgSend_stret_fixup) {
3897 msg->imp = (IMP)&objc_msgSend_stret_fixedup;
3899 else if (msg->imp == (IMP)&objc_msgSendSuper2_stret_fixup) {
3900 msg->imp = (IMP)&objc_msgSendSuper2_stret_fixedup;
3903 // The ref may already have been fixed up, either by another thread,
3904 // or by +initialize via class_lookupMethodAndLoadCache above.
3910 #warning fixme delete after #4586306
3911 Class class_poseAs(Class imposter, Class original)
3913 _objc_fatal("Don't call class_poseAs.");
3918 static class_t *setSuperclass(class_t *cls, class_t *newSuper)
3922 OBJC_CHECK_LOCKED(&runtimeLock);
3924 oldSuper = cls->superclass;
3925 removeSubclass(oldSuper, cls);
3926 removeSubclass(oldSuper->isa, cls->isa);
3928 cls->superclass = newSuper;
3929 cls->isa->superclass = newSuper->isa;
3930 addSubclass(newSuper, cls);
3931 addSubclass(newSuper->isa, cls->isa);
3934 flushCaches(cls->isa);
3940 Class class_setSuperclass(Class cls_gen, Class newSuper_gen)
3942 class_t *cls = newcls(cls_gen);
3943 class_t *newSuper = newcls(newSuper_gen);
3946 OBJC_LOCK(&runtimeLock);
3947 oldSuper = setSuperclass(cls, newSuper);
3948 OBJC_UNLOCK(&runtimeLock);
3950 return (Class)oldSuper;