2 * Copyright (c) 1999-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 old-ABI classes and images.
27 **********************************************************************/
29 /***********************************************************************
30 * Class loading and connecting (GrP 2004-2-11)
32 * When images are loaded (during program startup or otherwise), the
33 * runtime needs to load classes and categories from the images, connect
34 * classes to superclasses and categories to parent classes, and call
37 * The Objective-C runtime can cope with classes arriving in any order.
38 * That is, a class may be discovered by the runtime before some
39 * superclass is known. To handle out-of-order class loads, the
40 * runtime uses a "pending class" system.
43 * Panther and earlier: many classes arrived out-of-order because of
44 * the poorly-ordered callback from dyld. However, the runtime's
45 * pending mechanism only handled "missing superclass" and not
46 * "present superclass but missing higher class". See Radar #3225652.
47 * Tiger: The runtime's pending mechanism was augmented to handle
48 * arbitrary missing classes. In addition, dyld was rewritten and
49 * now sends the callbacks in strictly bottom-up link order.
50 * The pending mechanism may now be needed only for rare and
51 * hard to construct programs.
52 * (End historical note)
54 * A class when first seen in an image is considered "unconnected".
55 * It is stored in `unconnected_class_hash`. If all of the class's
56 * superclasses exist and are already "connected", then the new class
57 * can be connected to its superclasses and moved to `class_hash` for
58 * normal use. Otherwise, the class waits in `unconnected_class_hash`
59 * until the superclasses finish connecting.
61 * A "connected" class is
62 * (1) in `class_hash`,
63 * (2) connected to its superclasses,
64 * (3) has no unconnected superclasses,
65 * (4) is otherwise initialized and ready for use, and
66 * (5) is eligible for +load if +load has not already been called.
68 * An "unconnected" class is
69 * (1) in `unconnected_class_hash`,
70 * (2) not connected to its superclasses,
71 * (3) has an immediate superclass which is either missing or unconnected,
72 * (4) is not ready for use, and
73 * (5) is not yet eligible for +load.
75 * Image mapping is NOT CURRENTLY THREAD-SAFE with respect to just about
76 * * * anything. Image mapping IS RE-ENTRANT in several places: superclass
77 * lookup may cause ZeroLink to load another image, and +load calls may
78 * cause dyld to load another image.
80 * Image mapping sequence:
82 * Read all classes in all new images.
83 * Add them all to unconnected_class_hash.
84 * Note any +load implementations before categories are attached.
85 * Fix up any pended classrefs referring to them.
86 * Attach any pending categories.
87 * Read all categories in all new images.
88 * Attach categories whose parent class exists (connected or not),
90 * Mark them all eligible for +load (if implemented), even if the
91 * parent class is missing.
92 * Try to connect all classes in all new images.
93 * If the superclass is missing, pend the class
94 * If the superclass is unconnected, try to recursively connect it
95 * If the superclass is connected:
97 * mark the class eligible for +load, if implemented
98 * connect any pended subclasses of the class
99 * Resolve selector refs and class refs in all new images.
100 * Class refs whose classes still do not exist are pended.
101 * Fix up protocol objects in all new images.
102 * Call +load for classes and categories.
103 * May include classes or categories that are not in these images,
104 * but are newly eligible because of these image.
105 * Class +loads will be called superclass-first because of the
106 * superclass-first nature of the connecting process.
107 * Category +load needs to be deferred until the parent class is
108 * connected and has had its +load called.
110 * Performance: all classes are read before any categories are read.
111 * Fewer categories need be pended for lack of a parent class.
113 * Performance: all categories are attempted to be attached before
114 * any classes are connected. Fewer class caches need be flushed.
115 * (Unconnected classes and their respective subclasses are guaranteed
116 * to be un-messageable, so their caches will be empty.)
118 * Performance: all classes are read before any classes are connected.
119 * Fewer classes need be pended for lack of a superclass.
121 * Correctness: all selector and class refs are fixed before any
122 * protocol fixups or +load methods. libobjc itself contains selector
123 * and class refs which are used in protocol fixup and +load.
125 * Correctness: +load methods are scheduled in bottom-up link order.
126 * This constraint is in addition to superclass order. Some +load
127 * implementations expect to use another class in a linked-to library,
128 * even if the two classes don't share a direct superclass relationship.
130 * Correctness: all classes are scanned for +load before any categories
131 * are attached. Otherwise, if a category implements +load and its class
132 * has no class methods, the class's +load scan would find the category's
133 * +load method, which would then be called twice.
135 **********************************************************************/
139 #include <mach/mach.h>
140 #include <mach-o/ldsyms.h>
141 #include <mach-o/dyld.h>
145 #import "objc-private.h"
146 #import "objc-loadmethod.h"
147 #import "hashtable2.h"
150 /* NXHashTable SPI */
151 extern unsigned _NXHashCapacity(NXHashTable *table);
152 extern void _NXHashRehashToCapacity(NXHashTable *table, unsigned newCapacity);
155 typedef struct _objc_unresolved_category
157 struct _objc_unresolved_category *next;
158 struct old_category *cat; // may be NULL
160 } _objc_unresolved_category;
162 typedef struct _PendingSubclass
164 struct old_class *subclass; // subclass to finish connecting; may be NULL
165 struct _PendingSubclass *next;
168 typedef struct _PendingClassRef
170 struct old_class **ref; // class reference to fix up; may be NULL
171 // (ref & 1) is a metaclass reference
172 struct _PendingClassRef *next;
176 static uintptr_t classHash(void *info, Class data);
177 static int classIsEqual(void *info, Class name, Class cls);
178 static int _objc_defaultClassHandler(const char *clsName);
179 static BOOL class_is_connected(struct old_class *cls);
180 static inline NXMapTable *pendingClassRefsMapTable(void);
181 static inline NXMapTable *pendingSubclassesMapTable(void);
182 static void pendClassInstallation(struct old_class *cls, const char *superName);
183 static void pendClassReference(struct old_class **ref, const char *className, BOOL isMeta);
184 static void resolve_references_to_class(struct old_class *cls);
185 static void resolve_subclasses_of_class(struct old_class *cls);
186 static void really_connect_class(struct old_class *cls, struct old_class *supercls);
187 static BOOL connect_class(struct old_class *cls);
188 static inline BOOL map_selrefs(SEL *src, SEL *dst, size_t size, BOOL copy);
189 static void map_method_descs (struct objc_method_description_list * methods, BOOL copy);
190 static void _objcTweakMethodListPointerForClass(struct old_class *cls);
191 static inline void _objc_add_category(struct old_class *cls, struct old_category *category, int version);
192 static BOOL _objc_add_category_flush_caches(struct old_class *cls, struct old_category *category, int version);
193 static _objc_unresolved_category *reverse_cat(_objc_unresolved_category *cat);
194 static void resolve_categories_for_class(struct old_class *cls);
195 static BOOL _objc_register_category(struct old_category *cat, int version);
198 // Function called when a class is loaded from an image
199 __private_extern__ void (*callbackFunction)(Class, const char *) = 0;
201 // Lock for class and protocol hashtables
202 // classLock > cacheUpdateLock
203 __private_extern__ OBJC_DECLARE_LOCK (classLock);
205 // Hash table of classes
206 __private_extern__ NXHashTable * class_hash NOBSS = 0;
207 static NXHashTablePrototype classHashPrototype =
209 (uintptr_t (*) (const void *, const void *)) classHash,
210 (int (*)(const void *, const void *, const void *)) classIsEqual,
214 // Hash table of unconnected classes
215 static NXHashTable *unconnected_class_hash NOBSS = NULL;
217 // Exported copy of class_hash variable (hook for debugging tools)
218 NXHashTable *_objc_debug_class_hash = NULL;
220 // Category and class registries
221 // Keys are COPIES of strings, to prevent stale pointers with unloaded bundles
222 // Use NXMapKeyCopyingInsert and NXMapKeyFreeingRemove
223 static NXMapTable * category_hash = NULL;
225 // Keys are COPIES of strings, to prevent stale pointers with unloaded bundles
226 // Use NXMapKeyCopyingInsert and NXMapKeyFreeingRemove
227 static NXMapTable * pendingClassRefsMap = NULL;
228 static NXMapTable * pendingSubclassesMap = NULL;
231 static NXMapTable *protocol_map = NULL; // name -> protocol
232 static NXMapTable *protocol_ext_map = NULL; // protocol -> protocol ext
234 // Function pointer objc_getClass calls through when class is not found
235 static int (*objc_classHandler) (const char *) = _objc_defaultClassHandler;
237 // Function pointer called by objc_getClass and objc_lookupClass when
238 // class is not found. _objc_classLoader is called before objc_classHandler.
239 static BOOL (*_objc_classLoader)(const char *) = NULL;
242 /***********************************************************************
243 * inform_duplicate. Complain about duplicate class implementations.
244 **********************************************************************/
245 static void inform_duplicate(struct old_class *oldCls, struct old_class *cls)
247 const header_info *oldHeader = _headerForClass((Class)oldCls);
248 const header_info *newHeader = _headerForClass((Class)cls);
249 const char *oldName = _nameForHeader(oldHeader->mhdr);
250 const char *newName = _nameForHeader(newHeader->mhdr);
252 _objc_inform ("Class %s is implemented in both %s and %s. "
253 "Using implementation from %s.",
254 oldCls->name, oldName, newName, newName);
258 /***********************************************************************
259 * objc_dump_class_hash. Log names of all known classes.
260 **********************************************************************/
261 __private_extern__ void objc_dump_class_hash(void)
270 state = NXInitHashState (table);
271 while (NXNextHashState (table, &state, (void **) &data))
272 printf ("class %d: %s\n", ++count, _class_getName(data));
276 /***********************************************************************
277 * _objc_init_class_hash. Return the class lookup table, create it if
279 **********************************************************************/
280 __private_extern__ void _objc_init_class_hash(void)
282 // Do nothing if class hash table already exists
286 // class_hash starts small, with only enough capacity for libobjc itself.
287 // If a second library is found by map_images(), class_hash is immediately
288 // resized to capacity 1024 to cut down on rehashes.
289 // Old numbers: A smallish Foundation+AppKit program will have
290 // about 520 classes. Larger apps (like IB or WOB) have more like
291 // 800 classes. Some customers have massive quantities of classes.
292 // Foundation-only programs aren't likely to notice the ~6K loss.
293 class_hash = NXCreateHashTableFromZone (classHashPrototype,
296 _objc_internal_zone ());
297 _objc_debug_class_hash = class_hash;
301 /***********************************************************************
302 * objc_getClassList. Return the known classes.
303 **********************************************************************/
304 int objc_getClassList(Class *buffer, int bufferLen)
310 OBJC_LOCK(&classLock);
311 num = NXCountHashTable(class_hash);
312 if (NULL == buffer) {
313 OBJC_UNLOCK(&classLock);
317 state = NXInitHashState(class_hash);
318 while (cnt < bufferLen &&
319 NXNextHashState(class_hash, &state, (void **)&class))
321 buffer[cnt++] = class;
323 OBJC_UNLOCK(&classLock);
328 /***********************************************************************
329 * objc_copyProtocolList
330 * Returns pointers to all protocols.
331 * Locking: acquires classLock
332 **********************************************************************/
334 objc_copyProtocolList(unsigned int *outCount)
336 OBJC_LOCK(&classLock);
344 count = NXCountMapTable(protocol_map);
346 OBJC_UNLOCK(&classLock);
347 if (outCount) *outCount = 0;
351 result = calloc(1 + count, sizeof(Protocol *));
354 state = NXInitMapState(protocol_map);
355 while (NXNextMapState(protocol_map, &state,
356 (const void **)&name, (const void **)&proto))
362 assert(i == count+1);
364 OBJC_UNLOCK(&classLock);
366 if (outCount) *outCount = count;
371 /***********************************************************************
372 * objc_getClasses. Return class lookup table.
374 * NOTE: This function is very dangerous, since you cannot safely use
375 * the hashtable without locking it, and the lock is private!
376 **********************************************************************/
377 void *objc_getClasses(void)
379 OBJC_WARN_DEPRECATED;
381 // Return the class lookup hash table
386 /***********************************************************************
388 **********************************************************************/
389 static uintptr_t classHash(void *info, Class data)
391 // Nil classes hash to zero
395 // Call through to real hash function
396 return _objc_strhash (_class_getName(data));
399 /***********************************************************************
400 * classIsEqual. Returns whether the class names match. If we ever
401 * check more than the name, routines like objc_lookUpClass have to
403 **********************************************************************/
404 static int classIsEqual(void *info, Class name, Class cls)
406 // Standard string comparison
407 // Our local inlined version is significantly shorter on PPC and avoids the
408 // mflr/mtlr and dyld_stub overhead when calling strcmp.
409 return _objc_strcmp(_class_getName(name), _class_getName(cls)) == 0;
413 // Unresolved future classes
414 static NXHashTable *future_class_hash = NULL;
416 // Resolved future<->original classes
417 static NXMapTable *future_class_to_original_class_map = NULL;
418 static NXMapTable *original_class_to_future_class_map = NULL;
420 // CF requests about 20 future classes; HIToolbox requests one.
421 #define FUTURE_COUNT 32
424 /***********************************************************************
425 * setOriginalClassForFutureClass
426 * Record resolution of a future class.
427 **********************************************************************/
428 static void setOriginalClassForFutureClass(struct old_class *futureClass,
429 struct old_class *originalClass)
431 if (!future_class_to_original_class_map) {
432 future_class_to_original_class_map =
433 NXCreateMapTableFromZone (NXPtrValueMapPrototype, FUTURE_COUNT,
434 _objc_internal_zone ());
435 original_class_to_future_class_map =
436 NXCreateMapTableFromZone (NXPtrValueMapPrototype, FUTURE_COUNT,
437 _objc_internal_zone ());
440 NXMapInsert (future_class_to_original_class_map,
441 futureClass, originalClass);
442 NXMapInsert (original_class_to_future_class_map,
443 originalClass, futureClass);
446 _objc_inform("FUTURE: using %p instead of %p for %s", futureClass, originalClass, originalClass->name);
450 /***********************************************************************
451 * getOriginalClassForFutureClass
452 * getFutureClassForOriginalClass
453 * Switch between a future class and its corresponding original class.
454 * The future class is the one actually in use.
455 * The original class is the one from disk.
456 **********************************************************************/
458 static struct old_class *
459 getOriginalClassForFutureClass(struct old_class *futureClass)
461 if (!future_class_to_original_class_map) return Nil;
462 return NXMapGet (future_class_to_original_class_map, futureClass);
465 static struct old_class *
466 getFutureClassForOriginalClass(struct old_class *originalClass)
468 if (!original_class_to_future_class_map) return Nil;
469 return NXMapGet (original_class_to_future_class_map, originalClass);
473 /***********************************************************************
475 * Initialize the memory in *cls with an unresolved future class with the
476 * given name. The memory is recorded in future_class_hash.
477 **********************************************************************/
478 static void makeFutureClass(struct old_class *cls, const char *name)
480 // CF requests about 20 future classes, plus HIToolbox has one.
481 if (!future_class_hash) {
483 NXCreateHashTableFromZone(classHashPrototype, FUTURE_COUNT,
484 NULL, _objc_internal_zone());
487 cls->name = _strdup_internal(name);
488 NXHashInsert(future_class_hash, cls);
491 _objc_inform("FUTURE: reserving %p for %s", cls, name);
496 /***********************************************************************
497 * _objc_allocateFutureClass
498 * Allocate an unresolved future class for the given class name.
499 * Returns any existing allocation if one was already made.
500 * Assumes the named class doesn't exist yet.
502 **********************************************************************/
503 __private_extern__ Class _objc_allocateFutureClass(const char *name)
505 struct old_class *cls;
507 if (future_class_hash) {
508 struct old_class query;
510 if ((cls = NXHashGet(future_class_hash, &query))) {
511 // Already have a future class for this name.
516 cls = _calloc_internal(sizeof(*cls), 1);
517 makeFutureClass(cls, name);
522 /***********************************************************************
523 * objc_setFutureClass.
524 * Like objc_getFutureClass, but uses the provided memory block.
525 * If the class already exists, a posing-like substitution is performed.
527 **********************************************************************/
528 void objc_setFutureClass(Class cls, const char *name)
530 struct old_class *oldcls;
531 struct old_class *newcls = (struct old_class *)cls; // Not a real class!
533 if ((oldcls = _class_asOld(look_up_class(name, NO/*unconnected*/, NO/*classhandler*/)))) {
534 setOriginalClassForFutureClass(newcls, oldcls);
536 memcpy(newcls, oldcls, sizeof(struct objc_class));
537 newcls->info &= ~CLS_EXT;
539 OBJC_LOCK(&classLock);
540 NXHashRemove(class_hash, oldcls);
541 change_class_references(newcls, oldcls, nil, YES);
542 NXHashInsert(class_hash, newcls);
543 OBJC_UNLOCK(&classLock);
545 makeFutureClass(newcls, name);
550 /***********************************************************************
551 * _objc_defaultClassHandler. Default objc_classHandler. Does nothing.
552 **********************************************************************/
553 static int _objc_defaultClassHandler(const char *clsName)
555 // Return zero so objc_getClass doesn't bother re-searching
559 /***********************************************************************
560 * objc_setClassHandler. Set objc_classHandler to the specified value.
562 * NOTE: This should probably deal with userSuppliedHandler being NULL,
563 * because the objc_classHandler caller does not check... it would bus
564 * error. It would make sense to handle NULL by restoring the default
565 * handler. Is anyone hacking with this, though?
566 **********************************************************************/
567 void objc_setClassHandler(int (*userSuppliedHandler)(const char *))
569 OBJC_WARN_DEPRECATED;
571 objc_classHandler = userSuppliedHandler;
575 /***********************************************************************
576 * _objc_setClassLoader
577 * Similar to objc_setClassHandler, but objc_classLoader is used for
578 * both objc_getClass() and objc_lookupClass(), and objc_classLoader
579 * pre-empts objc_classHandler.
580 **********************************************************************/
581 void _objc_setClassLoader(BOOL (*newClassLoader)(const char *))
583 _objc_classLoader = newClassLoader;
587 /***********************************************************************
589 * Get a protocol by name, or NULL.
590 **********************************************************************/
591 Protocol *objc_getProtocol(const char *name)
594 if (!protocol_map) return NULL;
595 OBJC_LOCK(&classLock);
596 result = (Protocol *)NXMapGet(protocol_map, name);
597 OBJC_UNLOCK(&classLock);
602 /***********************************************************************
604 * Map a class name to a class using various methods.
605 * This is the common implementation of objc_lookUpClass and objc_getClass,
606 * and is also used internally to get additional search options.
609 * 2. unconnected_class_hash (optional)
610 * 3. classLoader callback
611 * 4. classHandler callback (optional)
612 **********************************************************************/
613 __private_extern__ id look_up_class(const char *aClassName, BOOL includeUnconnected, BOOL includeClassHandler)
615 BOOL includeClassLoader = YES; // class loader cannot be skipped
617 struct old_class query;
619 query.name = aClassName;
623 if (!result && class_hash) {
624 // Check ordinary classes
625 OBJC_LOCK (&classLock);
626 result = (id)NXHashGet(class_hash, &query);
627 OBJC_UNLOCK (&classLock);
630 if (!result && includeUnconnected && unconnected_class_hash) {
631 // Check not-yet-connected classes
632 OBJC_LOCK(&classLock);
633 result = (id)NXHashGet(unconnected_class_hash, &query);
634 OBJC_UNLOCK(&classLock);
637 if (!result && includeClassLoader && _objc_classLoader) {
638 // Try class loader callback
639 if ((*_objc_classLoader)(aClassName)) {
640 // Re-try lookup without class loader
641 includeClassLoader = NO;
646 if (!result && includeClassHandler && objc_classHandler) {
647 // Try class handler callback
648 if ((*objc_classHandler)(aClassName)) {
649 // Re-try lookup without class handler or class loader
650 includeClassLoader = NO;
651 includeClassHandler = NO;
660 /***********************************************************************
661 * class_is_connected.
662 * Returns TRUE if class cls is connected.
663 * A connected class has either a connected superclass or a NULL superclass,
664 * and is present in class_hash.
665 **********************************************************************/
666 static BOOL class_is_connected(struct old_class *cls)
669 OBJC_LOCK(&classLock);
670 result = NXHashMember(class_hash, cls);
671 OBJC_UNLOCK(&classLock);
676 /***********************************************************************
678 * Returns TRUE if class cls is ready for its +load method to be called.
679 * A class is ready for +load if it is connected.
680 **********************************************************************/
681 __private_extern__ BOOL _class_isLoadable(Class cls)
683 return class_is_connected(_class_asOld(cls));
687 /***********************************************************************
688 * pendingClassRefsMapTable. Return a pointer to the lookup table for
689 * pending class refs.
690 **********************************************************************/
691 static inline NXMapTable *pendingClassRefsMapTable(void)
693 // Allocate table if needed
694 if (!pendingClassRefsMap) {
695 pendingClassRefsMap =
696 NXCreateMapTableFromZone(NXStrValueMapPrototype,
697 10, _objc_internal_zone ());
700 // Return table pointer
701 return pendingClassRefsMap;
705 /***********************************************************************
706 * pendingSubclassesMapTable. Return a pointer to the lookup table for
707 * pending subclasses.
708 **********************************************************************/
709 static inline NXMapTable *pendingSubclassesMapTable(void)
711 // Allocate table if needed
712 if (!pendingSubclassesMap) {
713 pendingSubclassesMap =
714 NXCreateMapTableFromZone(NXStrValueMapPrototype,
715 10, _objc_internal_zone ());
718 // Return table pointer
719 return pendingSubclassesMap;
723 /***********************************************************************
724 * pendClassInstallation
725 * Finish connecting class cls when its superclass becomes connected.
726 * Check for multiple pends of the same class because connect_class does not.
727 **********************************************************************/
728 static void pendClassInstallation(struct old_class *cls, const char *superName)
731 PendingSubclass *pending;
732 PendingSubclass *oldList;
735 // Create and/or locate pending class lookup table
736 table = pendingSubclassesMapTable ();
738 // Make sure this class isn't already in the pending list.
739 oldList = NXMapGet (table, superName);
740 for (l = oldList; l != NULL; l = l->next) {
741 if (l->subclass == cls) return; // already here, nothing to do
744 // Create entry referring to this class
745 pending = _malloc_internal(sizeof(PendingSubclass));
746 pending->subclass = cls;
748 // Link new entry into head of list of entries for this class
749 pending->next = oldList;
751 // (Re)place entry list in the table
752 (void) NXMapKeyCopyingInsert (table, superName, pending);
756 /***********************************************************************
758 * Fix up a class ref when the class with the given name becomes connected.
759 **********************************************************************/
760 static void pendClassReference(struct old_class **ref, const char *className, BOOL isMeta)
763 PendingClassRef *pending;
765 // Create and/or locate pending class lookup table
766 table = pendingClassRefsMapTable ();
768 // Create entry containing the class reference
769 pending = _malloc_internal(sizeof(PendingClassRef));
772 pending->ref = (struct old_class **)((uintptr_t)pending->ref | 1);
775 // Link new entry into head of list of entries for this class
776 pending->next = NXMapGet (table, className);
778 // (Re)place entry list in the table
779 (void) NXMapKeyCopyingInsert (table, className, pending);
781 if (PrintConnecting) {
782 _objc_inform("CONNECT: pended reference to class '%s%s' at %p",
783 className, isMeta ? " (meta)" : "", (void *)ref);
788 /***********************************************************************
789 * resolve_references_to_class
790 * Fix up any pending class refs to this class.
791 **********************************************************************/
792 static void resolve_references_to_class(struct old_class *cls)
794 PendingClassRef *pending;
796 if (!pendingClassRefsMap) return; // no unresolved refs for any class
798 pending = NXMapGet(pendingClassRefsMap, cls->name);
799 if (!pending) return; // no unresolved refs for this class
801 NXMapKeyFreeingRemove(pendingClassRefsMap, cls->name);
803 if (PrintConnecting) {
804 _objc_inform("CONNECT: resolving references to class '%s'", cls->name);
808 PendingClassRef *next = pending->next;
810 BOOL isMeta = ((uintptr_t)pending->ref & 1) ? YES : NO;
811 struct old_class **ref =
812 (struct old_class **)((uintptr_t)pending->ref & ~(uintptr_t)1);
813 *ref = isMeta ? cls->isa : cls;
815 _free_internal(pending);
819 if (NXCountMapTable(pendingClassRefsMap) == 0) {
820 NXFreeMapTable(pendingClassRefsMap);
821 pendingClassRefsMap = NULL;
826 /***********************************************************************
827 * resolve_subclasses_of_class
828 * Fix up any pending subclasses of this class.
829 **********************************************************************/
830 static void resolve_subclasses_of_class(struct old_class *cls)
832 PendingSubclass *pending;
834 if (!pendingSubclassesMap) return; // no unresolved subclasses
836 pending = NXMapGet(pendingSubclassesMap, cls->name);
837 if (!pending) return; // no unresolved subclasses for this class
839 NXMapKeyFreeingRemove(pendingSubclassesMap, cls->name);
841 // Destroy the pending table if it's now empty, to save memory.
842 if (NXCountMapTable(pendingSubclassesMap) == 0) {
843 NXFreeMapTable(pendingSubclassesMap);
844 pendingSubclassesMap = NULL;
847 if (PrintConnecting) {
848 _objc_inform("CONNECT: resolving subclasses of class '%s'", cls->name);
852 PendingSubclass *next = pending->next;
853 if (pending->subclass) connect_class(pending->subclass);
854 _free_internal(pending);
860 /***********************************************************************
861 * really_connect_class
862 * Connect cls to superclass supercls unconditionally.
863 * Also adjust the class hash tables and handle pended subclasses.
865 * This should be called from connect_class() ONLY.
866 **********************************************************************/
867 static void really_connect_class(struct old_class *cls,
868 struct old_class *supercls)
870 struct old_class *oldCls;
872 // Connect superclass pointers.
873 set_superclass(cls, supercls);
875 cls->info |= CLS_CONNECTED;
877 OBJC_LOCK(&classLock);
879 // Update hash tables.
880 NXHashRemove(unconnected_class_hash, cls);
881 oldCls = NXHashInsert(class_hash, cls);
883 // Delete unconnected_class_hash if it is now empty.
884 if (NXCountHashTable(unconnected_class_hash) == 0) {
885 NXFreeHashTable(unconnected_class_hash);
886 unconnected_class_hash = NULL;
889 OBJC_UNLOCK(&classLock);
891 // Warn if the new class has the same name as a previously-installed class.
892 // The new class is kept and the old class is discarded.
894 inform_duplicate(oldCls, cls);
897 // Connect newly-connectable subclasses
898 resolve_subclasses_of_class(cls);
900 // GC debugging: make sure all classes with -dealloc also have -finalize
901 if (DebugFinalizers) {
902 extern IMP findIMPInClass(struct old_class *cls, SEL sel);
903 if (findIMPInClass(cls, sel_getUid("dealloc")) &&
904 ! findIMPInClass(cls, sel_getUid("finalize")))
906 _objc_inform("GC: class '%s' implements -dealloc but not -finalize", cls->name);
910 // Debugging: if this class has ivars, make sure this class's ivars don't
911 // overlap with its super's. This catches some broken fragile base classes.
912 // Do not use super->instance_size vs. self->ivar[0] to check this.
913 // Ivars may be packed across instance_size boundaries.
914 if (DebugFragileSuperclasses && cls->ivars && cls->ivars->ivar_count) {
915 struct old_class *ivar_cls = supercls;
917 // Find closest superclass that has some ivars, if one exists.
919 (!ivar_cls->ivars || ivar_cls->ivars->ivar_count == 0))
921 ivar_cls = ivar_cls->super_class;
925 // Compare superclass's last ivar to this class's first ivar
926 struct old_ivar *super_ivar =
927 &ivar_cls->ivars->ivar_list[ivar_cls->ivars->ivar_count - 1];
928 struct old_ivar *self_ivar =
929 &cls->ivars->ivar_list[0];
931 // fixme could be smarter about super's ivar size
932 if (self_ivar->ivar_offset <= super_ivar->ivar_offset) {
933 _objc_inform("WARNING: ivars of superclass '%s' and "
934 "subclass '%s' overlap; superclass may have "
935 "changed since subclass was compiled",
936 ivar_cls->name, cls->name);
943 /***********************************************************************
945 * Connect class cls to its superclasses, if possible.
946 * If cls becomes connected, move it from unconnected_class_hash
947 * to connected_class_hash.
948 * Returns TRUE if cls is connected.
949 * Returns FALSE if cls could not be connected for some reason
950 * (missing superclass or still-unconnected superclass)
951 **********************************************************************/
952 static BOOL connect_class(struct old_class *cls)
954 if (class_is_connected(cls)) {
955 // This class is already connected to its superclass.
959 else if (cls->super_class == NULL) {
960 // This class is a root class.
961 // Connect it to itself.
963 if (PrintConnecting) {
964 _objc_inform("CONNECT: class '%s' now connected (root class)",
968 really_connect_class(cls, NULL);
972 // This class is not a root class and is not yet connected.
973 // Connect it if its superclass and root class are already connected.
974 // Otherwise, add this class to the to-be-connected list,
975 // pending the completion of its superclass and root class.
977 // At this point, cls->super_class and cls->isa->isa are still STRINGS
978 char *supercls_name = (char *)cls->super_class;
979 struct old_class *supercls;
981 // YES unconnected, YES class handler
982 if (NULL == (supercls = _class_asOld(look_up_class(supercls_name, YES, YES)))) {
983 // Superclass does not exist yet.
984 // pendClassInstallation will handle duplicate pends of this class
985 pendClassInstallation(cls, supercls_name);
987 if (PrintConnecting) {
988 _objc_inform("CONNECT: class '%s' NOT connected (missing super)", cls->name);
993 if (! connect_class(supercls)) {
994 // Superclass exists but is not yet connected.
995 // pendClassInstallation will handle duplicate pends of this class
996 pendClassInstallation(cls, supercls_name);
998 if (PrintConnecting) {
999 _objc_inform("CONNECT: class '%s' NOT connected (unconnected super)", cls->name);
1004 // Superclass exists and is connected.
1005 // Connect this class to the superclass.
1007 if (PrintConnecting) {
1008 _objc_inform("CONNECT: class '%s' now connected", cls->name);
1011 really_connect_class(cls, supercls);
1017 /***********************************************************************
1018 * _objc_read_categories_from_image.
1019 * Read all categories from the given image.
1020 * Install them on their parent classes, or register them for later
1022 * Returns YES if some method caches now need to be flushed.
1023 **********************************************************************/
1024 static BOOL _objc_read_categories_from_image (header_info * hi)
1028 BOOL needFlush = NO;
1030 if (_objcHeaderIsReplacement(hi)) {
1031 // Ignore any categories in this image
1036 // Major loop - process all modules in the header
1039 // NOTE: The module and category lists are traversed backwards
1040 // to preserve the pre-10.4 processing order. Changing the order
1041 // would have a small chance of introducing binary compatibility bugs.
1042 midx = hi->mod_count;
1043 while (midx-- > 0) {
1047 // Nothing to do for a module without a symbol table
1048 if (mods[midx].symtab == NULL)
1051 // Total entries in symbol table (class entries followed
1052 // by category entries)
1053 total = mods[midx].symtab->cls_def_cnt +
1054 mods[midx].symtab->cat_def_cnt;
1056 // Minor loop - register all categories from given module
1058 while (index-- > mods[midx].symtab->cls_def_cnt) {
1059 struct old_category *cat = mods[midx].symtab->defs[index];
1060 needFlush |= _objc_register_category(cat, (int)mods[midx].version);
1068 /***********************************************************************
1069 * _objc_read_classes_from_image.
1070 * Read classes from the given image, perform assorted minor fixups,
1071 * scan for +load implementation.
1072 * Does not connect classes to superclasses.
1073 * Does attach pended categories to the classes.
1074 * Adds all classes to unconnected_class_hash. class_hash is unchanged.
1075 **********************************************************************/
1076 static void _objc_read_classes_from_image(header_info *hi)
1081 int isBundle = (hi->mhdr->filetype == MH_BUNDLE);
1083 if (_objcHeaderIsReplacement(hi)) {
1084 // Ignore any classes in this image
1088 // class_hash starts small, enough only for libobjc itself.
1089 // If other Objective-C libraries are found, immediately resize
1090 // class_hash, assuming that Foundation and AppKit are about
1091 // to add lots of classes.
1092 OBJC_LOCK(&classLock);
1093 if (hi->mhdr != (headerType *)&_mh_dylib_header && _NXHashCapacity(class_hash) < 1024) {
1094 _NXHashRehashToCapacity(class_hash, 1024);
1096 OBJC_UNLOCK(&classLock);
1098 // Major loop - process all modules in the image
1100 for (midx = 0; midx < hi->mod_count; midx += 1)
1102 // Skip module containing no classes
1103 if (mods[midx].symtab == NULL)
1106 // Minor loop - process all the classes in given module
1107 for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
1109 struct old_class *newCls, *oldCls;
1111 // Locate the class description pointer
1112 newCls = mods[midx].symtab->defs[index];
1114 // Classes loaded from Mach-O bundles can be unloaded later.
1115 // Nothing uses this class yet, so _class_setInfo is not needed.
1116 if (isBundle) newCls->info |= CLS_FROM_BUNDLE;
1117 if (isBundle) newCls->isa->info |= CLS_FROM_BUNDLE;
1119 // Use common static empty cache instead of NULL
1120 if (newCls->cache == NULL)
1121 newCls->cache = (Cache) &_objc_empty_cache;
1122 if (newCls->isa->cache == NULL)
1123 newCls->isa->cache = (Cache) &_objc_empty_cache;
1125 // Set metaclass version
1126 newCls->isa->version = mods[midx].version;
1128 // methodLists is NULL or a single list, not an array
1129 newCls->info |= CLS_NO_METHOD_ARRAY|CLS_NO_PROPERTY_ARRAY;
1130 newCls->isa->info |= CLS_NO_METHOD_ARRAY|CLS_NO_PROPERTY_ARRAY;
1132 // class has no subclasses for cache flushing
1133 newCls->info |= CLS_LEAF;
1134 newCls->isa->info |= CLS_LEAF;
1136 if (mods[midx].version >= 6) {
1137 // class structure has ivar_layout and ext fields
1138 newCls->info |= CLS_EXT;
1139 newCls->isa->info |= CLS_EXT;
1142 // Check for +load implementation before categories are attached
1143 if (_class_hasLoadMethod((Class)newCls)) {
1144 newCls->isa->info |= CLS_HAS_LOAD_METHOD;
1147 // Install into unconnected_class_hash.
1148 OBJC_LOCK(&classLock);
1150 if (future_class_hash) {
1151 struct old_class *futureCls =
1152 NXHashRemove(future_class_hash, newCls);
1154 // Another class structure for this class was already
1155 // prepared by objc_getFutureClass(). Use it instead.
1156 _free_internal((char *)futureCls->name);
1157 memcpy(futureCls, newCls, sizeof(*newCls));
1158 setOriginalClassForFutureClass(futureCls, newCls);
1161 if (NXCountHashTable(future_class_hash) == 0) {
1162 NXFreeHashTable(future_class_hash);
1163 future_class_hash = NULL;
1168 if (!unconnected_class_hash) {
1169 unconnected_class_hash =
1170 NXCreateHashTableFromZone(classHashPrototype, 128,
1171 NULL, _objc_internal_zone());
1174 oldCls = NXHashInsert(unconnected_class_hash, newCls);
1176 // Duplicate classes loaded.
1177 // newCls has been inserted over oldCls,
1178 // same as really_connect_class
1179 inform_duplicate(oldCls, newCls);
1182 OBJC_UNLOCK(&classLock);
1184 // Fix up pended class refs to this class, if any
1185 resolve_references_to_class(newCls);
1187 // Attach pended categories for this class, if any
1188 resolve_categories_for_class(newCls);
1194 /***********************************************************************
1195 * _objc_connect_classes_from_image.
1196 * Connect the classes in the given image to their superclasses,
1197 * or register them for later connection if any superclasses are missing.
1198 **********************************************************************/
1199 static void _objc_connect_classes_from_image(header_info *hi)
1204 BOOL replacement = _objcHeaderIsReplacement(hi);
1206 // Major loop - process all modules in the image
1208 for (midx = 0; midx < hi->mod_count; midx += 1)
1210 // Skip module containing no classes
1211 if (mods[midx].symtab == NULL)
1214 // Minor loop - process all the classes in given module
1215 for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
1217 struct old_class *cls = mods[midx].symtab->defs[index];
1218 if (! replacement) {
1220 struct old_class *futureCls = getFutureClassForOriginalClass(cls);
1222 // objc_getFutureClass() requested a different class
1223 // struct. Fix up the original struct's super_class
1224 // field for [super ...] use, but otherwise perform
1225 // fixups on the new class struct only.
1226 const char *super_name = (const char *) cls->super_class;
1227 if (super_name) cls->super_class = _class_asOld(objc_getClass(super_name));
1230 connected = connect_class(cls);
1231 if (connected && callbackFunction) {
1232 (*callbackFunction)((Class)cls, 0);
1235 // Replacement image - fix up super_class only (#3704817)
1236 // And metaclass's super_class (#5351107)
1237 const char *super_name = (const char *) cls->super_class;
1239 cls->super_class = _class_asOld(objc_getClass(super_name));
1240 // metaclass's superclass is superclass's metaclass
1241 cls->isa->super_class = cls->super_class->isa;
1243 // Replacement for a root class
1244 // cls->super_class already NULL
1245 // root metaclass's superclass is root class
1246 cls->isa->super_class = cls;
1254 /***********************************************************************
1255 * _objc_map_class_refs_for_image. Convert the class ref entries from
1256 * a class name string pointer to a class pointer. If the class does
1257 * not yet exist, the reference is added to a list of pending references
1258 * to be fixed up at a later date.
1259 **********************************************************************/
1260 static void fix_class_ref(struct old_class **ref, const char *name, BOOL isMeta)
1262 struct old_class *cls;
1264 // Get pointer to class of this name
1265 // YES unconnected, YES class loader
1266 cls = _class_asOld(look_up_class(name, YES, YES));
1268 // Referenced class exists. Fix up the reference.
1269 *ref = isMeta ? cls->isa : cls;
1271 // Referenced class does not exist yet. Insert a placeholder
1272 // class and fix up the reference later.
1273 pendClassReference (ref, name, isMeta);
1274 *ref = (struct old_class *)_class_getNonexistentObjectClass();
1278 static void _objc_map_class_refs_for_image (header_info * hi)
1280 struct old_class **cls_refs;
1284 // Locate class refs in image
1285 cls_refs = _getObjcClassRefs (hi, &count);
1287 // Process each class ref
1288 for (index = 0; index < count; index += 1) {
1289 // Ref is initially class name char*
1290 const char *name = (const char *) cls_refs[index];
1292 // rdar://5453039 is the entire page zero, or just this pointer
1293 uintptr_t *p = (uintptr_t *)(((uintptr_t)&cls_refs[index]) & ~0xfff);
1294 uintptr_t *end = (uintptr_t *)(((uintptr_t)p)+0x1000);
1296 for ( ; p < end; p++) {
1302 _objc_inform_on_crash("rdar://5453039 page around %p IS%s clear",
1303 &cls_refs[index], clear ? "" : " NOT");
1304 // crash in the usual spot so CrashTracer coalesces it
1306 fix_class_ref(&cls_refs[index], name, NO /*never meta*/);
1312 /***********************************************************************
1313 * _objc_remove_pending_class_refs_in_image
1314 * Delete any pending class ref fixups for class refs in the given image,
1315 * because the image is about to be unloaded.
1316 **********************************************************************/
1317 static void removePendingReferences(struct old_class **refs, size_t count)
1319 struct old_class **end = refs + count;
1322 if (!pendingClassRefsMap) return;
1324 // Search the pending class ref table for class refs in this range.
1325 // The class refs may have already been stomped with nonexistentClass,
1326 // so there's no way to recover the original class name.
1329 PendingClassRef *pending;
1330 NXMapState state = NXInitMapState(pendingClassRefsMap);
1331 while(NXNextMapState(pendingClassRefsMap, &state,
1332 (const void **)&key, (const void **)&pending))
1334 for ( ; pending != NULL; pending = pending->next) {
1335 if (pending->ref >= refs && pending->ref < end) {
1336 pending->ref = NULL;
1342 static void _objc_remove_pending_class_refs_in_image(header_info *hi)
1344 struct old_class **cls_refs;
1347 // Locate class refs in this image
1348 cls_refs = _getObjcClassRefs(hi, &count);
1349 removePendingReferences(cls_refs, count);
1353 /***********************************************************************
1354 * map_selrefs. For each selector in the specified array,
1355 * replace the name pointer with a uniqued selector.
1356 * If copy is TRUE, all selector data is always copied. This is used
1357 * for registering selectors from unloadable bundles, so the selector
1358 * can still be used after the bundle's data segment is unmapped.
1359 * Returns YES if dst was written to, NO if it was unchanged.
1360 **********************************************************************/
1361 static inline BOOL map_selrefs(SEL *src, SEL *dst, size_t size, BOOL copy)
1364 size_t cnt = size / sizeof(SEL);
1369 // Process each selector
1370 for (index = 0; index < cnt; index += 1)
1374 // Lookup pointer to uniqued string
1375 sel = sel_registerNameNoLock((const char *) src[index], copy);
1377 // Replace this selector with uniqued one (avoid
1378 // modifying the VM page if this would be a NOP)
1379 if (dst[index] != sel) {
1391 /***********************************************************************
1392 * map_message_refs. For each message ref in the specified array,
1393 * replace the name pointer with a uniqued selector.
1394 * If copy is TRUE, all selector data is always copied. This is used
1395 * for registering selectors from unloadable bundles, so the selector
1396 * can still be used after the bundle's data segment is unmapped.
1397 * Returns YES if dst was written to, NO if it was unchanged.
1398 **********************************************************************/
1399 static inline BOOL map_message_refs(message_ref *src, message_ref *dst, size_t size, BOOL copy)
1402 size_t cnt = size / sizeof(message_ref);
1407 // Process each selector
1408 for (index = 0; index < cnt; index += 1)
1412 // Lookup pointer to uniqued string
1413 sel = sel_registerNameNoLock((const char *) src[index].sel, copy);
1415 // Replace this selector with uniqued one (avoid
1416 // modifying the VM page if this would be a NOP)
1417 if (dst[index].sel != sel) {
1418 dst[index].sel = sel;
1429 /***********************************************************************
1430 * map_method_descs. For each method in the specified method list,
1431 * replace the name pointer with a uniqued selector.
1432 * If copy is TRUE, all selector data is always copied. This is used
1433 * for registering selectors from unloadable bundles, so the selector
1434 * can still be used after the bundle's data segment is unmapped.
1435 **********************************************************************/
1436 static void map_method_descs (struct objc_method_description_list * methods, BOOL copy)
1440 if (!methods) return;
1444 // Process each method
1445 for (index = 0; index < methods->count; index += 1)
1447 struct objc_method_description * method;
1450 // Get method entry to fix up
1451 method = &methods->list[index];
1453 // Lookup pointer to uniqued string
1454 sel = sel_registerNameNoLock((const char *) method->name, copy);
1456 // Replace this selector with uniqued one (avoid
1457 // modifying the VM page if this would be a NOP)
1458 if (method->name != sel)
1466 /***********************************************************************
1468 * Returns the protocol extension for the given protocol.
1469 * Returns NULL if the protocol has no extension.
1470 **********************************************************************/
1471 static struct old_protocol_ext *ext_for_protocol(struct old_protocol *proto)
1473 if (!proto) return NULL;
1474 if (!protocol_ext_map) return NULL;
1475 else return (struct old_protocol_ext *)NXMapGet(protocol_ext_map, proto);
1479 /***********************************************************************
1481 * Search a protocol method list for a selector.
1482 **********************************************************************/
1483 static struct objc_method_description *
1484 lookup_method(struct objc_method_description_list *mlist, SEL aSel)
1488 for (i = 0; i < mlist->count; i++) {
1489 if (mlist->list[i].name == aSel) {
1490 return mlist->list+i;
1498 /***********************************************************************
1499 * lookup_protocol_method
1500 * Recursively search for a selector in a protocol
1501 * (and all incorporated protocols)
1502 **********************************************************************/
1503 __private_extern__ struct objc_method_description *
1504 lookup_protocol_method(struct old_protocol *proto, SEL aSel,
1505 BOOL isRequiredMethod, BOOL isInstanceMethod)
1507 struct objc_method_description *m = NULL;
1508 struct old_protocol_ext *ext;
1510 if (isRequiredMethod) {
1511 if (isInstanceMethod) {
1512 m = lookup_method(proto->instance_methods, aSel);
1514 m = lookup_method(proto->class_methods, aSel);
1516 } else if ((ext = ext_for_protocol(proto))) {
1517 if (isInstanceMethod) {
1518 m = lookup_method(ext->optional_instance_methods, aSel);
1520 m = lookup_method(ext->optional_class_methods, aSel);
1524 if (!m && proto->protocol_list) {
1526 for (i = 0; !m && i < proto->protocol_list->count; i++) {
1527 m = lookup_protocol_method(proto->protocol_list->list[i], aSel,
1528 isRequiredMethod, isInstanceMethod);
1536 /***********************************************************************
1538 * Returns the name of the given protocol.
1539 **********************************************************************/
1540 const char *protocol_getName(Protocol *p)
1542 struct old_protocol *proto = oldprotocol(p);
1543 if (!proto) return "nil";
1544 return proto->protocol_name;
1548 /***********************************************************************
1549 * protocol_getMethodDescription
1550 * Returns the description of a named method.
1551 * Searches either required or optional methods.
1552 * Searches either instance or class methods.
1553 **********************************************************************/
1554 struct objc_method_description
1555 protocol_getMethodDescription(Protocol *p, SEL aSel,
1556 BOOL isRequiredMethod, BOOL isInstanceMethod)
1558 struct old_protocol *proto = oldprotocol(p);
1559 if (!proto) return (struct objc_method_description){NULL, NULL};
1561 struct objc_method_description *desc =
1562 lookup_protocol_method(proto, aSel,
1563 isRequiredMethod, isInstanceMethod);
1564 if (desc) return *desc;
1565 else return (struct objc_method_description){NULL, NULL};
1569 /***********************************************************************
1570 * protocol_copyMethodDescriptionList
1571 * Returns an array of method descriptions from a protocol.
1572 * Copies either required or optional methods.
1573 * Copies either instance or class methods.
1574 **********************************************************************/
1575 struct objc_method_description *
1576 protocol_copyMethodDescriptionList(Protocol *p,
1577 BOOL isRequiredMethod,
1578 BOOL isInstanceMethod,
1579 unsigned int *outCount)
1581 struct objc_method_description_list *mlist = NULL;
1582 struct old_protocol *proto = oldprotocol(p);
1583 struct old_protocol_ext *ext;
1586 if (outCount) *outCount = 0;
1590 if (isRequiredMethod) {
1591 if (isInstanceMethod) {
1592 mlist = proto->instance_methods;
1594 mlist = proto->class_methods;
1596 } else if ((ext = ext_for_protocol(proto))) {
1597 if (isInstanceMethod) {
1598 mlist = ext->optional_instance_methods;
1600 mlist = ext->optional_class_methods;
1605 if (outCount) *outCount = 0;
1610 unsigned int count = mlist->count;
1611 struct objc_method_description *result =
1612 calloc(count + 1, sizeof(struct objc_method_description));
1613 for (i = 0; i < count; i++) {
1614 result[i] = mlist->list[i];
1617 if (outCount) *outCount = count;
1622 Property protocol_getProperty(Protocol *p, const char *name,
1623 BOOL isRequiredProperty, BOOL isInstanceProperty)
1625 struct old_protocol *proto = oldprotocol(p);
1627 if (!proto || !name) return NULL;
1629 if (!isRequiredProperty || !isInstanceProperty) {
1630 // Only required instance properties are currently supported
1634 struct old_protocol_ext *ext;
1635 if ((ext = ext_for_protocol(proto))) {
1636 struct objc_property_list *plist;
1637 if ((plist = ext->instance_properties)) {
1639 for (i = 0; i < plist->count; i++) {
1640 Property prop = property_list_nth(plist, i);
1641 if (0 == strcmp(name, prop->name)) {
1648 struct old_protocol_list *plist;
1649 if ((plist = proto->protocol_list)) {
1651 for (i = 0; i < plist->count; i++) {
1653 protocol_getProperty((Protocol *)plist->list[i], name,
1654 isRequiredProperty, isInstanceProperty);
1655 if (prop) return prop;
1663 Property *protocol_copyPropertyList(Protocol *p, unsigned int *outCount)
1665 Property *result = NULL;
1666 struct old_protocol_ext *ext;
1668 struct old_protocol *proto = oldprotocol(p);
1669 if (! (ext = ext_for_protocol(proto))) {
1670 if (outCount) *outCount = 0;
1674 struct objc_property_list *plist = ext->instance_properties;
1675 result = copyPropertyList(plist, outCount);
1681 /***********************************************************************
1682 * protocol_copyProtocolList
1683 * Copies this protocol's incorporated protocols.
1684 * Does not copy those protocol's incorporated protocols in turn.
1685 **********************************************************************/
1686 Protocol **protocol_copyProtocolList(Protocol *p, unsigned int *outCount)
1688 unsigned int count = 0;
1689 Protocol **result = NULL;
1690 struct old_protocol *proto = oldprotocol(p);
1693 if (outCount) *outCount = 0;
1697 if (proto->protocol_list) {
1698 count = (unsigned int)proto->protocol_list->count;
1701 result = malloc((count+1) * sizeof(Protocol *));
1704 for (i = 0; i < count; i++) {
1705 result[i] = (Protocol *)proto->protocol_list->list[i];
1710 if (outCount) *outCount = count;
1715 BOOL protocol_conformsToProtocol(Protocol *self_gen, Protocol *other_gen)
1717 struct old_protocol *self = oldprotocol(self_gen);
1718 struct old_protocol *other = oldprotocol(other_gen);
1720 if (!self || !other) {
1724 if (0 == strcmp(self->protocol_name, other->protocol_name)) {
1728 if (self->protocol_list) {
1730 for (i = 0; i < self->protocol_list->count; i++) {
1731 struct old_protocol *proto = self->protocol_list->list[i];
1732 if (0 == strcmp(other->protocol_name, proto->protocol_name)) {
1735 if (protocol_conformsToProtocol((Protocol *)proto, other_gen)) {
1745 BOOL protocol_isEqual(Protocol *self, Protocol *other)
1747 if (self == other) return YES;
1748 if (!self || !other) return NO;
1750 if (!protocol_conformsToProtocol(self, other)) return NO;
1751 if (!protocol_conformsToProtocol(other, self)) return NO;
1757 /***********************************************************************
1758 * _objc_fixup_protocol_objects_for_image. For each protocol in the
1759 * specified image, selectorize the method names and add to the protocol hash.
1760 **********************************************************************/
1762 static BOOL versionIsExt(uintptr_t version, const char *names, size_t size)
1764 // CodeWarrior used isa field for string "Protocol"
1765 // from section __OBJC,__class_names. rdar://4951638
1766 // gcc (10.4 and earlier) used isa field for version number;
1767 // the only version number used on Mac OS X was 2.
1768 // gcc (10.5 and later) uses isa field for ext pointer
1770 if (version < 4096) {
1774 if (version >= (uintptr_t)names && version < (uintptr_t)(names + size)) {
1781 static void fix_protocol(struct old_protocol *proto, Class protocolClass,
1782 BOOL isBundle, const char *names, size_t names_size)
1784 #warning GrP fixme hack
1787 uintptr_t version = (uintptr_t)proto->isa;
1789 // Set the protocol's isa
1790 proto->isa = protocolClass;
1792 // Fix up method lists
1793 // fixme share across duplicates
1794 map_method_descs (proto->instance_methods, isBundle);
1795 map_method_descs (proto->class_methods, isBundle);
1797 // Fix up ext, if any
1798 if (versionIsExt(version, names, names_size)) {
1799 struct old_protocol_ext *ext = (struct old_protocol_ext *)version;
1800 NXMapInsert(protocol_ext_map, proto, ext);
1801 map_method_descs (ext->optional_instance_methods, isBundle);
1802 map_method_descs (ext->optional_class_methods, isBundle);
1805 // Record the protocol it if we don't have one with this name yet
1806 // fixme bundles - copy protocol
1808 if (!NXMapGet(protocol_map, proto->protocol_name)) {
1809 NXMapKeyCopyingInsert(protocol_map, proto->protocol_name, proto);
1810 if (PrintProtocols) {
1811 _objc_inform("PROTOCOLS: protocol at %p is %s",
1812 proto, proto->protocol_name);
1815 // duplicate - do nothing
1816 if (PrintProtocols) {
1817 _objc_inform("PROTOCOLS: protocol at %p is %s (duplicate)",
1818 proto, proto->protocol_name);
1823 static void _objc_fixup_protocol_objects_for_image (header_info * hi)
1825 Class protocolClass = objc_getClass("Protocol");
1827 struct old_protocol *protos;
1828 int isBundle = hi->mhdr->filetype == MH_BUNDLE;
1832 OBJC_LOCK(&classLock);
1834 // Allocate the protocol registry if necessary.
1835 if (!protocol_map) {
1837 NXCreateMapTableFromZone(NXStrValueMapPrototype, 32,
1838 _objc_internal_zone());
1840 if (!protocol_ext_map) {
1842 NXCreateMapTableFromZone(NXPtrValueMapPrototype, 32,
1843 _objc_internal_zone());
1846 protos = _getObjcProtocols(hi, &count);
1847 names = _getObjcClassNames(hi, &names_size);
1848 for (i = 0; i < count; i++) {
1849 fix_protocol(&protos[i], protocolClass, isBundle, names, names_size);
1852 OBJC_UNLOCK(&classLock);
1856 /***********************************************************************
1857 * _objc_fixup_selector_refs. Register all of the selectors in each
1858 * image, and fix them all up.
1859 **********************************************************************/
1860 static void _objc_fixup_selector_refs (const header_info *hi)
1865 // Fix up selector refs
1866 sels = _getObjcSelectorRefs (hi, &count);
1868 map_selrefs(sels, sels, count * sizeof(SEL),
1869 hi->mhdr->filetype == MH_BUNDLE);
1874 /***********************************************************************
1876 * Perform metadata processing for hCount images starting with firstNewHeader
1877 **********************************************************************/
1878 __private_extern__ void _read_images(header_info **hList, uint32_t hCount)
1882 if (!class_hash) _objc_init_class_hash();
1884 // Parts of this order are important for correctness or performance.
1886 // Read classes from all images.
1887 for (i = 0; i < hCount; i++) {
1888 _objc_read_classes_from_image(hList[i]);
1891 // Read categories from all images.
1892 BOOL needFlush = NO;
1893 for (i = 0; i < hCount; i++) {
1894 needFlush |= _objc_read_categories_from_image(hList[i]);
1896 if (needFlush) flush_marked_caches();
1898 // Connect classes from all images.
1899 for (i = 0; i < hCount; i++) {
1900 _objc_connect_classes_from_image(hList[i]);
1903 // Fix up class refs, selector refs, and protocol objects from all images.
1904 for (i = 0; i < hCount; i++) {
1905 _objc_map_class_refs_for_image(hList[i]);
1906 _objc_fixup_selector_refs(hList[i]);
1907 _objc_fixup_protocol_objects_for_image(hList[i]);
1912 /***********************************************************************
1913 * prepare_load_methods
1914 * Schedule +load for classes in this image, any un-+load-ed
1915 * superclasses in other images, and any categories in this image.
1916 **********************************************************************/
1917 // Recursively schedule +load for cls and any un-+load-ed superclasses.
1918 // cls must already be connected.
1919 static void schedule_class_load(struct old_class *cls)
1921 if (cls->info & CLS_LOADED) return;
1922 if (cls->super_class) schedule_class_load(cls->super_class);
1923 add_class_to_loadable_list((Class)cls);
1924 cls->info |= CLS_LOADED;
1927 __private_extern__ void prepare_load_methods(header_info *hi)
1933 if (_objcHeaderIsReplacement(hi)) {
1934 // Ignore any classes in this image
1938 // Major loop - process all modules in the image
1940 for (midx = 0; midx < hi->mod_count; midx += 1)
1944 // Skip module containing no classes
1945 if (mods[midx].symtab == NULL)
1948 // Minor loop - process all the classes in given module
1949 for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
1951 // Locate the class description pointer
1952 struct old_class *cls = mods[midx].symtab->defs[index];
1953 if (cls->info & CLS_CONNECTED) {
1954 schedule_class_load(cls);
1960 // Major loop - process all modules in the header
1963 // NOTE: The module and category lists are traversed backwards
1964 // to preserve the pre-10.4 processing order. Changing the order
1965 // would have a small chance of introducing binary compatibility bugs.
1966 midx = hi->mod_count;
1967 while (midx-- > 0) {
1970 Symtab symtab = mods[midx].symtab;
1972 // Nothing to do for a module without a symbol table
1973 if (mods[midx].symtab == NULL)
1975 // Total entries in symbol table (class entries followed
1976 // by category entries)
1977 total = mods[midx].symtab->cls_def_cnt +
1978 mods[midx].symtab->cat_def_cnt;
1980 // Minor loop - register all categories from given module
1982 while (index-- > mods[midx].symtab->cls_def_cnt) {
1983 struct old_category *cat = symtab->defs[index];
1984 add_category_to_loadable_list((Category)cat);
1990 /***********************************************************************
1991 * _objc_remove_classes_in_image
1992 * Remove all classes in the given image from the runtime, because
1993 * the image is about to be unloaded.
1994 * Things to clean up:
1996 * unconnected_class_hash
1997 * pending subclasses list (only if class is still unconnected)
1998 * loadable class list
1999 * class's method caches
2000 * class refs in all other images
2001 **********************************************************************/
2002 // Re-pend any class references in refs that point into [start..end)
2003 static void rependClassReferences(struct old_class **refs, size_t count,
2004 uintptr_t start, uintptr_t end)
2010 // Process each class ref
2011 for (i = 0; i < count; i++) {
2012 if ((uintptr_t)(refs[i]) >= start && (uintptr_t)(refs[i]) < end) {
2013 pendClassReference(&refs[i], refs[i]->name,
2014 (refs[i]->info & CLS_META) ? YES : NO);
2015 refs[i] = (struct old_class *)_class_getNonexistentObjectClass();
2021 static void try_free(const void *p)
2023 if (p && malloc_size(p)) free((void *)p);
2026 // Deallocate all memory in a method list
2027 static void unload_mlist(struct old_method_list *mlist)
2030 if (mlist->obsolete == _OBJC_FIXED_UP) {
2031 for (i = 0; i < mlist->method_count; i++) {
2032 try_free(mlist->method_list[i].method_types);
2039 // Deallocate all memory in a class.
2040 __private_extern__ void unload_class(struct old_class *cls)
2045 for (i = 0; i < cls->ivars->ivar_count; i++) {
2046 try_free(cls->ivars->ivar_list[i].ivar_name);
2047 try_free(cls->ivars->ivar_list[i].ivar_type);
2049 try_free(cls->ivars);
2052 // Free fixed-up method lists and method list array
2053 if (cls->methodLists) {
2054 // more than zero method lists
2055 if (cls->info & CLS_NO_METHOD_ARRAY) {
2057 unload_mlist((struct old_method_list *)cls->methodLists);
2060 // more than one method list
2061 struct old_method_list **mlistp;
2062 for (mlistp = cls->methodLists;
2063 *mlistp != NULL && *mlistp != END_OF_METHODS_LIST;
2066 unload_mlist(*mlistp);
2068 free(cls->methodLists);
2072 // Free protocol list
2073 struct old_protocol_list *protos = cls->protocols;
2075 struct old_protocol_list *dead = protos;
2076 protos = protos->next;
2080 // Free method cache
2081 if (cls->cache && cls->cache != &_objc_empty_cache) {
2082 _cache_free(cls->cache);
2085 if ((cls->info & CLS_EXT)) {
2087 // Free property lists and property list array
2088 if (cls->ext->propertyLists) {
2089 // more than zero property lists
2090 if (cls->info & CLS_NO_PROPERTY_ARRAY) {
2091 // one property list
2092 try_free(cls->ext->propertyLists);
2094 // more than one property list
2095 struct objc_property_list **plistp;
2096 for (plistp = cls->ext->propertyLists;
2102 try_free(cls->ext->propertyLists);
2106 // Free weak ivar layout
2107 try_free(cls->ext->weak_ivar_layout);
2113 // Free non-weak ivar layout
2114 try_free(cls->ivar_layout);
2118 try_free(cls->name);
2125 static void _objc_remove_classes_in_image(header_info *hi)
2131 OBJC_LOCK(&classLock);
2133 // Major loop - process all modules in the image
2135 for (midx = 0; midx < hi->mod_count; midx += 1)
2137 // Skip module containing no classes
2138 if (mods[midx].symtab == NULL)
2141 // Minor loop - process all the classes in given module
2142 for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
2144 struct old_class *cls;
2146 // Locate the class description pointer
2147 cls = mods[midx].symtab->defs[index];
2149 // Remove from loadable class list, if present
2150 remove_class_from_loadable_list((Class)cls);
2152 // Remove from unconnected_class_hash and pending subclasses
2153 if (unconnected_class_hash && NXHashMember(unconnected_class_hash, cls)) {
2154 NXHashRemove(unconnected_class_hash, cls);
2155 if (pendingSubclassesMap) {
2156 // Find this class in its superclass's pending list
2157 char *supercls_name = (char *)cls->super_class;
2158 PendingSubclass *pending =
2159 NXMapGet(pendingSubclassesMap, supercls_name);
2160 for ( ; pending != NULL; pending = pending->next) {
2161 if (pending->subclass == cls) {
2162 pending->subclass = Nil;
2169 // Remove from class_hash
2170 NXHashRemove(class_hash, cls);
2172 // Free heap memory pointed to by the class
2173 unload_class(cls->isa);
2179 // Search all other images for class refs that point back to this range.
2180 // Un-fix and re-pend any such class refs.
2182 // Get the location of the dying image's __OBJC segment
2183 uintptr_t seg = hi->objcSegmentHeader->vmaddr + hi->image_slide;
2184 size_t seg_size = hi->objcSegmentHeader->filesize;
2186 header_info *other_hi;
2187 for (other_hi = _objc_headerStart();
2189 other_hi = other_hi->next)
2191 struct old_class **other_refs;
2193 if (other_hi == hi) continue; // skip the image being unloaded
2195 // Fix class refs in the other image
2196 other_refs = _getObjcClassRefs(other_hi, &count);
2197 rependClassReferences(other_refs, count, seg, seg+seg_size);
2200 OBJC_UNLOCK(&classLock);
2204 /***********************************************************************
2205 * _objc_remove_categories_in_image
2206 * Remove all categories in the given image from the runtime, because
2207 * the image is about to be unloaded.
2208 * Things to clean up:
2209 * unresolved category list
2210 * loadable category list
2211 **********************************************************************/
2212 static void _objc_remove_categories_in_image(header_info *hi)
2217 // Major loop - process all modules in the header
2220 for (midx = 0; midx < hi->mod_count; midx++) {
2223 Symtab symtab = mods[midx].symtab;
2225 // Nothing to do for a module without a symbol table
2226 if (symtab == NULL) continue;
2228 // Total entries in symbol table (class entries followed
2229 // by category entries)
2230 total = symtab->cls_def_cnt + symtab->cat_def_cnt;
2232 // Minor loop - check all categories from given module
2233 for (index = symtab->cls_def_cnt; index < total; index++) {
2234 struct old_category *cat = symtab->defs[index];
2236 // Clean up loadable category list
2237 remove_category_from_loadable_list((Category)cat);
2239 // Clean up category_hash
2240 if (category_hash) {
2241 _objc_unresolved_category *cat_entry =
2242 NXMapGet(category_hash, cat->class_name);
2243 for ( ; cat_entry != NULL; cat_entry = cat_entry->next) {
2244 if (cat_entry->cat == cat) {
2245 cat_entry->cat = NULL;
2255 /***********************************************************************
2257 * Various paranoid debugging checks that look for poorly-behaving
2258 * unloadable bundles.
2259 * Called by _objc_unmap_image when OBJC_UNLOAD_DEBUG is set.
2260 **********************************************************************/
2261 static void unload_paranoia(header_info *hi)
2263 // Get the location of the dying image's __OBJC segment
2264 uintptr_t seg = hi->objcSegmentHeader->vmaddr + hi->image_slide;
2265 size_t seg_size = hi->objcSegmentHeader->filesize;
2267 _objc_inform("UNLOAD DEBUG: unloading image '%s' [%p..%p]",
2268 _nameForHeader(hi->mhdr), (void *)seg, (void*)(seg+seg_size));
2270 OBJC_LOCK(&classLock);
2272 // Make sure the image contains no categories on surviving classes.
2277 // Major loop - process all modules in the header
2280 for (midx = 0; midx < hi->mod_count; midx++) {
2283 Symtab symtab = mods[midx].symtab;
2285 // Nothing to do for a module without a symbol table
2286 if (symtab == NULL) continue;
2288 // Total entries in symbol table (class entries followed
2289 // by category entries)
2290 total = symtab->cls_def_cnt + symtab->cat_def_cnt;
2292 // Minor loop - check all categories from given module
2293 for (index = symtab->cls_def_cnt; index < total; index++) {
2294 struct old_category *cat = symtab->defs[index];
2295 struct old_class query;
2297 query.name = cat->class_name;
2298 if (NXHashMember(class_hash, &query)) {
2299 _objc_inform("UNLOAD DEBUG: dying image contains category '%s(%s)' on surviving class '%s'!", cat->class_name, cat->category_name, cat->class_name);
2305 // Make sure no surviving class is in the dying image.
2306 // Make sure no surviving class has a superclass in the dying image.
2307 // fixme check method implementations too
2309 struct old_class *cls;
2312 state = NXInitHashState(class_hash);
2313 while (NXNextHashState(class_hash, &state, (void **)&cls)) {
2314 if ((vm_address_t)cls >= seg &&
2315 (vm_address_t)cls < seg+seg_size)
2317 _objc_inform("UNLOAD DEBUG: dying image contains surviving class '%s'!", cls->name);
2320 if ((vm_address_t)cls->super_class >= seg &&
2321 (vm_address_t)cls->super_class < seg+seg_size)
2323 _objc_inform("UNLOAD DEBUG: dying image contains superclass '%s' of surviving class '%s'!", cls->super_class->name, cls->name);
2328 OBJC_UNLOCK(&classLock);
2332 /***********************************************************************
2334 * Only handles MH_BUNDLE for now.
2335 **********************************************************************/
2336 __private_extern__ void _unload_image(header_info *hi)
2339 // Remove image's classes from the class list and free auxiliary data.
2340 // Remove image's unresolved or loadable categories and free auxiliary data
2341 // Remove image's unresolved class refs.
2342 _objc_remove_classes_in_image(hi);
2343 _objc_remove_categories_in_image(hi);
2344 _objc_remove_pending_class_refs_in_image(hi);
2346 // Perform various debugging checks if requested.
2347 if (DebugUnload) unload_paranoia(hi);
2351 /***********************************************************************
2352 * objc_addClass. Add the specified class to the table of known classes,
2353 * after doing a little verification and fixup.
2354 **********************************************************************/
2355 void objc_addClass (Class cls_gen)
2357 struct old_class *cls = _class_asOld(cls_gen);
2359 OBJC_WARN_DEPRECATED;
2361 // Synchronize access to hash table
2362 OBJC_LOCK (&classLock);
2364 // Make sure both the class and the metaclass have caches!
2365 // Clear all bits of the info fields except CLS_CLASS and CLS_META.
2366 // Normally these bits are already clear but if someone tries to cons
2367 // up their own class on the fly they might need to be cleared.
2368 if (cls->cache == NULL) {
2369 cls->cache = (Cache) &_objc_empty_cache;
2370 cls->info = CLS_CLASS;
2373 if (cls->isa->cache == NULL) {
2374 cls->isa->cache = (Cache) &_objc_empty_cache;
2375 cls->isa->info = CLS_META;
2378 // methodLists should be:
2379 // 1. NULL (Tiger and later only)
2380 // 2. A -1 terminated method list array
2381 // In either case, CLS_NO_METHOD_ARRAY remains clear.
2382 // If the user manipulates the method list directly,
2383 // they must use the magic private format.
2385 // Add the class to the table
2386 (void) NXHashInsert (class_hash, cls);
2388 // Superclass is no longer a leaf for cache flushing
2389 if (cls->super_class && (cls->super_class->info & CLS_LEAF)) {
2390 _class_clearInfo((Class)cls->super_class, CLS_LEAF);
2391 _class_clearInfo((Class)cls->super_class->isa, CLS_LEAF);
2395 OBJC_UNLOCK (&classLock);
2398 /***********************************************************************
2399 * _objcTweakMethodListPointerForClass.
2400 * Change the class's method list pointer to a method list array.
2401 * Does nothing if the method list pointer is already a method list array.
2402 * If the class is currently in use, methodListLock must be held by the caller.
2403 **********************************************************************/
2404 static void _objcTweakMethodListPointerForClass(struct old_class *cls)
2406 struct old_method_list * originalList;
2407 const int initialEntries = 4;
2409 struct old_method_list ** ptr;
2411 // Do nothing if methodLists is already an array.
2412 if (cls->methodLists && !(cls->info & CLS_NO_METHOD_ARRAY)) return;
2414 // Remember existing list
2415 originalList = (struct old_method_list *) cls->methodLists;
2417 // Allocate and zero a method list array
2418 mallocSize = sizeof(struct old_method_list *) * initialEntries;
2419 ptr = (struct old_method_list **) _calloc_internal(1, mallocSize);
2421 // Insert the existing list into the array
2422 ptr[initialEntries - 1] = END_OF_METHODS_LIST;
2423 ptr[0] = originalList;
2425 // Replace existing list with array
2426 cls->methodLists = ptr;
2427 _class_clearInfo((Class)cls, CLS_NO_METHOD_ARRAY);
2431 /***********************************************************************
2432 * _objc_insertMethods.
2433 * Adds methods to a class.
2434 * Does not flush any method caches.
2435 * Does not take any locks.
2436 * If the class is already in use, use class_addMethods() instead.
2437 **********************************************************************/
2438 __private_extern__ void _objc_insertMethods(struct old_class *cls,
2439 struct old_method_list *mlist,
2440 struct old_category *cat)
2442 struct old_method_list ***list;
2443 struct old_method_list **ptr;
2448 if (!cls->methodLists) {
2449 // cls has no methods - simply use this method list
2450 cls->methodLists = (struct old_method_list **)mlist;
2451 _class_setInfo((Class)cls, CLS_NO_METHOD_ARRAY);
2455 // Log any existing methods being replaced
2456 if (PrintReplacedMethods) {
2458 for (i = 0; i < mlist->method_count; i++) {
2459 extern IMP findIMPInClass(struct old_class *cls, SEL sel);
2460 SEL sel = sel_registerName((char *)mlist->method_list[i].method_name);
2461 IMP newImp = mlist->method_list[i].method_imp;
2464 if ((oldImp = findIMPInClass(cls, sel))) {
2465 _objc_inform("REPLACED: %c[%s %s] %s%s (IMP was %p, now %p)",
2466 ISMETA(cls) ? '+' : '-',
2467 cls->name, sel_getName(sel),
2468 cat ? "by category " : "",
2469 cat ? cat->category_name : "",
2475 // Create method list array if necessary
2476 _objcTweakMethodListPointerForClass(cls);
2478 list = &cls->methodLists;
2480 // Locate unused entry for insertion point
2482 while ((*ptr != 0) && (*ptr != END_OF_METHODS_LIST))
2485 // If array is full, add to it
2486 if (*ptr == END_OF_METHODS_LIST)
2488 // Calculate old and new dimensions
2489 endIndex = ptr - *list;
2490 oldSize = (endIndex + 1) * sizeof(void *);
2491 newSize = oldSize + sizeof(struct old_method_list *); // only increase by 1
2493 // Grow the method list array by one.
2494 // This block may be from user code; don't use _realloc_internal
2495 *list = (struct old_method_list **)realloc(*list, newSize);
2497 // Zero out addition part of new array
2498 bzero (&((*list)[endIndex]), newSize - oldSize);
2500 // Place new end marker
2501 (*list)[(newSize/sizeof(void *)) - 1] = END_OF_METHODS_LIST;
2503 // Insertion point corresponds to old array end
2504 ptr = &((*list)[endIndex]);
2507 // Right shift existing entries by one
2508 bcopy (*list, (*list) + 1, ((void *) ptr) - ((void *) *list));
2510 // Insert at method list at beginning of array
2514 /***********************************************************************
2515 * _objc_removeMethods.
2516 * Remove methods from a class.
2517 * Does not take any locks.
2518 * Does not flush any method caches.
2519 * If the class is currently in use, use class_removeMethods() instead.
2520 **********************************************************************/
2521 __private_extern__ void _objc_removeMethods(struct old_class *cls,
2522 struct old_method_list *mlist)
2524 struct old_method_list ***list;
2525 struct old_method_list **ptr;
2527 if (cls->methodLists == NULL) {
2528 // cls has no methods
2531 if (cls->methodLists == (struct old_method_list **)mlist) {
2532 // mlist is the class's only method list - erase it
2533 cls->methodLists = NULL;
2536 if (cls->info & CLS_NO_METHOD_ARRAY) {
2537 // cls has only one method list, and this isn't it - do nothing
2541 // cls has a method list array - search it
2543 list = &cls->methodLists;
2545 // Locate list in the array
2547 while (*ptr != mlist) {
2548 // fix for radar # 2538790
2549 if ( *ptr == END_OF_METHODS_LIST ) return;
2553 // Remove this entry
2556 // Left shift the following entries
2557 while (*(++ptr) != END_OF_METHODS_LIST)
2562 /***********************************************************************
2563 * _objc_add_category. Install the specified category's methods and
2564 * protocols into the class it augments.
2565 * The class is assumed not to be in use yet: no locks are taken and
2566 * no method caches are flushed.
2567 **********************************************************************/
2568 static inline void _objc_add_category(struct old_class *cls, struct old_category *category, int version)
2570 if (PrintConnecting) {
2571 _objc_inform("CONNECT: attaching category '%s (%s)'", cls->name, category->category_name);
2574 // Augment instance methods
2575 if (category->instance_methods)
2576 _objc_insertMethods (cls, category->instance_methods, category);
2578 // Augment class methods
2579 if (category->class_methods)
2580 _objc_insertMethods (cls->isa, category->class_methods, category);
2582 // Augment protocols
2583 if ((version >= 5) && category->protocols)
2585 if (cls->isa->version >= 5)
2587 category->protocols->next = cls->protocols;
2588 cls->protocols = category->protocols;
2589 cls->isa->protocols = category->protocols;
2593 _objc_inform ("unable to add protocols from category %s...\n", category->category_name);
2594 _objc_inform ("class `%s' must be recompiled\n", category->class_name);
2598 // Augment properties
2599 if (version >= 7 && category->instance_properties) {
2600 if (cls->isa->version >= 6) {
2601 _class_addProperties(cls, category->instance_properties);
2603 _objc_inform ("unable to add properties from category %s...\n", category->category_name);
2604 _objc_inform ("class `%s' must be recompiled\n", category->class_name);
2609 /***********************************************************************
2610 * _objc_add_category_flush_caches. Install the specified category's
2611 * methods into the class it augments, and flush the class' method cache.
2612 * Return YES if some method caches now need to be flushed.
2613 **********************************************************************/
2614 static BOOL _objc_add_category_flush_caches(struct old_class *cls, struct old_category *category, int version)
2616 BOOL needFlush = NO;
2618 // Install the category's methods into its intended class
2619 OBJC_LOCK(&methodListLock);
2620 _objc_add_category (cls, category, version);
2621 OBJC_UNLOCK(&methodListLock);
2623 // Queue for cache flushing so category's methods can get called
2624 if (category->instance_methods) {
2625 _class_setInfo((Class)cls, CLS_FLUSH_CACHE);
2628 if (category->class_methods) {
2629 _class_setInfo((Class)cls->isa, CLS_FLUSH_CACHE);
2637 /***********************************************************************
2639 * Reverse the given linked list of pending categories.
2640 * The pending category list is built backwards, and needs to be
2641 * reversed before actually attaching the categories to a class.
2642 * Returns the head of the new linked list.
2643 **********************************************************************/
2644 static _objc_unresolved_category *reverse_cat(_objc_unresolved_category *cat)
2646 if (!cat) return NULL;
2648 _objc_unresolved_category *prev = NULL;
2649 _objc_unresolved_category *cur = cat;
2650 _objc_unresolved_category *ahead = cat->next;
2663 /***********************************************************************
2664 * resolve_categories_for_class.
2665 * Install all existing categories intended for the specified class.
2666 * cls must be a true class and not a metaclass.
2667 **********************************************************************/
2668 static void resolve_categories_for_class(struct old_class *cls)
2670 _objc_unresolved_category * pending;
2671 _objc_unresolved_category * next;
2673 // Nothing to do if there are no categories at all
2674 if (!category_hash) return;
2676 // Locate and remove first element in category list
2677 // associated with this class
2678 pending = NXMapKeyFreeingRemove (category_hash, cls->name);
2680 // Traverse the list of categories, if any, registered for this class
2682 // The pending list is built backwards. Reverse it and walk forwards.
2683 pending = reverse_cat(pending);
2687 // Install the category
2688 // use the non-flush-cache version since we are only
2689 // called from the class intialization code
2690 _objc_add_category(cls, pending->cat, (int)pending->version);
2693 // Delink and reclaim this registration
2694 next = pending->next;
2695 _free_internal(pending);
2701 /***********************************************************************
2702 * _objc_resolve_categories_for_class.
2703 * Public version of resolve_categories_for_class. This was
2704 * exported pre-10.4 for Omni et al. to workaround a problem
2705 * with too-lazy category attachment.
2706 * cls should be a class, but this function can also cope with metaclasses.
2707 **********************************************************************/
2708 void _objc_resolve_categories_for_class(Class cls_gen)
2710 struct old_class *cls = _class_asOld(cls_gen);
2712 // If cls is a metaclass, get the class.
2713 // resolve_categories_for_class() requires a real class to work correctly.
2715 if (strncmp(cls->name, "_%", 2) == 0) {
2716 // Posee's meta's name is smashed and isn't in the class_hash,
2717 // so objc_getClass doesn't work.
2718 char *baseName = strchr(cls->name, '%'); // get posee's real name
2719 cls = _class_asOld(objc_getClass(baseName));
2721 cls = _class_asOld(objc_getClass(cls->name));
2725 resolve_categories_for_class(cls);
2729 /***********************************************************************
2730 * _objc_register_category.
2731 * Process a category read from an image.
2732 * If the category's class exists, attach the category immediately.
2733 * Classes that need cache flushing are marked but not flushed.
2734 * If the category's class does not exist yet, pend the category for
2735 * later attachment. Pending categories are attached in the order
2736 * they were discovered.
2737 * Returns YES if some method caches now need to be flushed.
2738 **********************************************************************/
2739 static BOOL _objc_register_category(struct old_category *cat, int version)
2741 _objc_unresolved_category * new_cat;
2742 _objc_unresolved_category * old;
2743 struct old_class *theClass;
2745 // If the category's class exists, attach the category.
2746 if ((theClass = _class_asOld(objc_lookUpClass(cat->class_name)))) {
2747 return _objc_add_category_flush_caches(theClass, cat, version);
2750 // If the category's class exists but is unconnected,
2751 // then attach the category to the class but don't bother
2752 // flushing any method caches (because they must be empty).
2753 // YES unconnected, NO class_handler
2754 if ((theClass = _class_asOld(look_up_class(cat->class_name, YES, NO)))) {
2755 _objc_add_category(theClass, cat, version);
2760 // Category's class does not exist yet.
2761 // Save the category for later attachment.
2763 if (PrintConnecting) {
2764 _objc_inform("CONNECT: pending category '%s (%s)'", cat->class_name, cat->category_name);
2767 // Create category lookup table if needed
2769 category_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype,
2771 _objc_internal_zone ());
2773 // Locate an existing list of categories, if any, for the class.
2774 old = NXMapGet (category_hash, cat->class_name);
2776 // Register the category to be fixed up later.
2777 // The category list is built backwards, and is reversed again
2778 // by resolve_categories_for_class().
2779 new_cat = _malloc_internal(sizeof(_objc_unresolved_category));
2780 new_cat->next = old;
2782 new_cat->version = version;
2783 (void) NXMapKeyCopyingInsert (category_hash, cat->class_name, new_cat);
2789 __private_extern__ const char **
2790 _objc_copyClassNamesForImage(header_info *hi, unsigned int *outCount)
2803 for (m = 0; m < hi->mod_count; m++) {
2806 if (!mods[m].symtab) continue;
2808 for (d = 0; d < mods[m].symtab->cls_def_cnt; d++) {
2809 struct old_class *cls = mods[m].symtab->defs[d];
2810 // fixme what about future-ified classes?
2811 if (class_is_connected(cls)) {
2812 if (count == allocated) {
2813 allocated = allocated*2 + 16;
2814 list = realloc(list, allocated * sizeof(char *));
2816 list[count++] = cls->name;
2822 // NULL-terminate non-empty list
2823 if (count == allocated) {
2824 allocated = allocated+1;
2825 list = realloc(list, allocated * sizeof(char *));
2830 if (outCount) *outCount = count;