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);
876 // For paranoia, this is a conservative update: only non-strong -> strong
877 // is corrected. Any bugs will be leaks instead of crashes.
878 // rdar://5791689 covers any less-paranoid more-complete fix.
879 if (UseGC && supercls &&
880 (cls->info & CLS_EXT) && (supercls->info & CLS_EXT))
882 BOOL layoutsChanged = NO;
883 layout_bitmap ivarBitmap =
884 layout_bitmap_create(cls->ivar_layout,
886 cls->instance_size, NO);
888 layout_bitmap superBitmap =
889 layout_bitmap_create(supercls->ivar_layout,
890 supercls->instance_size,
891 supercls->instance_size, NO);
892 layoutsChanged |= layout_bitmap_or(ivarBitmap, superBitmap, cls->name);
893 layout_bitmap_free(superBitmap);
895 if (layoutsChanged) {
896 // Rebuild layout strings.
898 _objc_inform("IVARS: gc layout changed for class %s (super %s)",
899 cls->name, supercls->name);
901 cls->ivar_layout = layout_string_create(ivarBitmap);
904 layout_bitmap_free(ivarBitmap);
908 cls->info |= CLS_CONNECTED;
910 OBJC_LOCK(&classLock);
912 // Update hash tables.
913 NXHashRemove(unconnected_class_hash, cls);
914 oldCls = NXHashInsert(class_hash, cls);
916 // Delete unconnected_class_hash if it is now empty.
917 if (NXCountHashTable(unconnected_class_hash) == 0) {
918 NXFreeHashTable(unconnected_class_hash);
919 unconnected_class_hash = NULL;
922 OBJC_UNLOCK(&classLock);
924 // Warn if the new class has the same name as a previously-installed class.
925 // The new class is kept and the old class is discarded.
927 inform_duplicate(oldCls, cls);
930 // Connect newly-connectable subclasses
931 resolve_subclasses_of_class(cls);
933 // GC debugging: make sure all classes with -dealloc also have -finalize
934 if (DebugFinalizers) {
935 extern IMP findIMPInClass(struct old_class *cls, SEL sel);
936 if (findIMPInClass(cls, sel_getUid("dealloc")) &&
937 ! findIMPInClass(cls, sel_getUid("finalize")))
939 _objc_inform("GC: class '%s' implements -dealloc but not -finalize", cls->name);
943 // Debugging: if this class has ivars, make sure this class's ivars don't
944 // overlap with its super's. This catches some broken fragile base classes.
945 // Do not use super->instance_size vs. self->ivar[0] to check this.
946 // Ivars may be packed across instance_size boundaries.
947 if (DebugFragileSuperclasses && cls->ivars && cls->ivars->ivar_count) {
948 struct old_class *ivar_cls = supercls;
950 // Find closest superclass that has some ivars, if one exists.
952 (!ivar_cls->ivars || ivar_cls->ivars->ivar_count == 0))
954 ivar_cls = ivar_cls->super_class;
958 // Compare superclass's last ivar to this class's first ivar
959 struct old_ivar *super_ivar =
960 &ivar_cls->ivars->ivar_list[ivar_cls->ivars->ivar_count - 1];
961 struct old_ivar *self_ivar =
962 &cls->ivars->ivar_list[0];
964 // fixme could be smarter about super's ivar size
965 if (self_ivar->ivar_offset <= super_ivar->ivar_offset) {
966 _objc_inform("WARNING: ivars of superclass '%s' and "
967 "subclass '%s' overlap; superclass may have "
968 "changed since subclass was compiled",
969 ivar_cls->name, cls->name);
976 /***********************************************************************
978 * Connect class cls to its superclasses, if possible.
979 * If cls becomes connected, move it from unconnected_class_hash
980 * to connected_class_hash.
981 * Returns TRUE if cls is connected.
982 * Returns FALSE if cls could not be connected for some reason
983 * (missing superclass or still-unconnected superclass)
984 **********************************************************************/
985 static BOOL connect_class(struct old_class *cls)
987 if (class_is_connected(cls)) {
988 // This class is already connected to its superclass.
992 else if (cls->super_class == NULL) {
993 // This class is a root class.
994 // Connect it to itself.
996 if (PrintConnecting) {
997 _objc_inform("CONNECT: class '%s' now connected (root class)",
1001 really_connect_class(cls, NULL);
1005 // This class is not a root class and is not yet connected.
1006 // Connect it if its superclass and root class are already connected.
1007 // Otherwise, add this class to the to-be-connected list,
1008 // pending the completion of its superclass and root class.
1010 // At this point, cls->super_class and cls->isa->isa are still STRINGS
1011 char *supercls_name = (char *)cls->super_class;
1012 struct old_class *supercls;
1014 // YES unconnected, YES class handler
1015 if (NULL == (supercls = _class_asOld(look_up_class(supercls_name, YES, YES)))) {
1016 // Superclass does not exist yet.
1017 // pendClassInstallation will handle duplicate pends of this class
1018 pendClassInstallation(cls, supercls_name);
1020 if (PrintConnecting) {
1021 _objc_inform("CONNECT: class '%s' NOT connected (missing super)", cls->name);
1026 if (! connect_class(supercls)) {
1027 // Superclass exists but is not yet connected.
1028 // pendClassInstallation will handle duplicate pends of this class
1029 pendClassInstallation(cls, supercls_name);
1031 if (PrintConnecting) {
1032 _objc_inform("CONNECT: class '%s' NOT connected (unconnected super)", cls->name);
1037 // Superclass exists and is connected.
1038 // Connect this class to the superclass.
1040 if (PrintConnecting) {
1041 _objc_inform("CONNECT: class '%s' now connected", cls->name);
1044 really_connect_class(cls, supercls);
1050 /***********************************************************************
1051 * _objc_read_categories_from_image.
1052 * Read all categories from the given image.
1053 * Install them on their parent classes, or register them for later
1055 * Returns YES if some method caches now need to be flushed.
1056 **********************************************************************/
1057 static BOOL _objc_read_categories_from_image (header_info * hi)
1061 BOOL needFlush = NO;
1063 if (_objcHeaderIsReplacement(hi)) {
1064 // Ignore any categories in this image
1069 // Major loop - process all modules in the header
1072 // NOTE: The module and category lists are traversed backwards
1073 // to preserve the pre-10.4 processing order. Changing the order
1074 // would have a small chance of introducing binary compatibility bugs.
1075 midx = hi->mod_count;
1076 while (midx-- > 0) {
1080 // Nothing to do for a module without a symbol table
1081 if (mods[midx].symtab == NULL)
1084 // Total entries in symbol table (class entries followed
1085 // by category entries)
1086 total = mods[midx].symtab->cls_def_cnt +
1087 mods[midx].symtab->cat_def_cnt;
1089 // Minor loop - register all categories from given module
1091 while (index-- > mods[midx].symtab->cls_def_cnt) {
1092 struct old_category *cat = mods[midx].symtab->defs[index];
1093 needFlush |= _objc_register_category(cat, (int)mods[midx].version);
1101 /***********************************************************************
1102 * _objc_read_classes_from_image.
1103 * Read classes from the given image, perform assorted minor fixups,
1104 * scan for +load implementation.
1105 * Does not connect classes to superclasses.
1106 * Does attach pended categories to the classes.
1107 * Adds all classes to unconnected_class_hash. class_hash is unchanged.
1108 **********************************************************************/
1109 static void _objc_read_classes_from_image(header_info *hi)
1114 int isBundle = (hi->mhdr->filetype == MH_BUNDLE);
1116 if (_objcHeaderIsReplacement(hi)) {
1117 // Ignore any classes in this image
1121 // class_hash starts small, enough only for libobjc itself.
1122 // If other Objective-C libraries are found, immediately resize
1123 // class_hash, assuming that Foundation and AppKit are about
1124 // to add lots of classes.
1125 OBJC_LOCK(&classLock);
1126 if (hi->mhdr != (headerType *)&_mh_dylib_header && _NXHashCapacity(class_hash) < 1024) {
1127 _NXHashRehashToCapacity(class_hash, 1024);
1129 OBJC_UNLOCK(&classLock);
1131 // Major loop - process all modules in the image
1133 for (midx = 0; midx < hi->mod_count; midx += 1)
1135 // Skip module containing no classes
1136 if (mods[midx].symtab == NULL)
1139 // Minor loop - process all the classes in given module
1140 for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
1142 struct old_class *newCls, *oldCls;
1144 // Locate the class description pointer
1145 newCls = mods[midx].symtab->defs[index];
1147 // Classes loaded from Mach-O bundles can be unloaded later.
1148 // Nothing uses this class yet, so _class_setInfo is not needed.
1149 if (isBundle) newCls->info |= CLS_FROM_BUNDLE;
1150 if (isBundle) newCls->isa->info |= CLS_FROM_BUNDLE;
1152 // Use common static empty cache instead of NULL
1153 if (newCls->cache == NULL)
1154 newCls->cache = (Cache) &_objc_empty_cache;
1155 if (newCls->isa->cache == NULL)
1156 newCls->isa->cache = (Cache) &_objc_empty_cache;
1158 // Set metaclass version
1159 newCls->isa->version = mods[midx].version;
1161 // methodLists is NULL or a single list, not an array
1162 newCls->info |= CLS_NO_METHOD_ARRAY|CLS_NO_PROPERTY_ARRAY;
1163 newCls->isa->info |= CLS_NO_METHOD_ARRAY|CLS_NO_PROPERTY_ARRAY;
1165 // class has no subclasses for cache flushing
1166 newCls->info |= CLS_LEAF;
1167 newCls->isa->info |= CLS_LEAF;
1169 if (mods[midx].version >= 6) {
1170 // class structure has ivar_layout and ext fields
1171 newCls->info |= CLS_EXT;
1172 newCls->isa->info |= CLS_EXT;
1175 // Check for +load implementation before categories are attached
1176 if (_class_hasLoadMethod((Class)newCls)) {
1177 newCls->isa->info |= CLS_HAS_LOAD_METHOD;
1180 // Install into unconnected_class_hash.
1181 OBJC_LOCK(&classLock);
1183 if (future_class_hash) {
1184 struct old_class *futureCls =
1185 NXHashRemove(future_class_hash, newCls);
1187 // Another class structure for this class was already
1188 // prepared by objc_getFutureClass(). Use it instead.
1189 _free_internal((char *)futureCls->name);
1190 memcpy(futureCls, newCls, sizeof(*newCls));
1191 setOriginalClassForFutureClass(futureCls, newCls);
1194 if (NXCountHashTable(future_class_hash) == 0) {
1195 NXFreeHashTable(future_class_hash);
1196 future_class_hash = NULL;
1201 if (!unconnected_class_hash) {
1202 unconnected_class_hash =
1203 NXCreateHashTableFromZone(classHashPrototype, 128,
1204 NULL, _objc_internal_zone());
1207 oldCls = NXHashInsert(unconnected_class_hash, newCls);
1209 // Duplicate classes loaded.
1210 // newCls has been inserted over oldCls,
1211 // same as really_connect_class
1212 inform_duplicate(oldCls, newCls);
1215 OBJC_UNLOCK(&classLock);
1217 // Fix up pended class refs to this class, if any
1218 resolve_references_to_class(newCls);
1220 // Attach pended categories for this class, if any
1221 resolve_categories_for_class(newCls);
1227 /***********************************************************************
1228 * _objc_connect_classes_from_image.
1229 * Connect the classes in the given image to their superclasses,
1230 * or register them for later connection if any superclasses are missing.
1231 **********************************************************************/
1232 static void _objc_connect_classes_from_image(header_info *hi)
1237 BOOL replacement = _objcHeaderIsReplacement(hi);
1239 // Major loop - process all modules in the image
1241 for (midx = 0; midx < hi->mod_count; midx += 1)
1243 // Skip module containing no classes
1244 if (mods[midx].symtab == NULL)
1247 // Minor loop - process all the classes in given module
1248 for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
1250 struct old_class *cls = mods[midx].symtab->defs[index];
1251 if (! replacement) {
1253 struct old_class *futureCls = getFutureClassForOriginalClass(cls);
1255 // objc_getFutureClass() requested a different class
1256 // struct. Fix up the original struct's super_class
1257 // field for [super ...] use, but otherwise perform
1258 // fixups on the new class struct only.
1259 const char *super_name = (const char *) cls->super_class;
1260 if (super_name) cls->super_class = _class_asOld(objc_getClass(super_name));
1263 connected = connect_class(cls);
1264 if (connected && callbackFunction) {
1265 (*callbackFunction)((Class)cls, 0);
1268 // Replacement image - fix up super_class only (#3704817)
1269 // And metaclass's super_class (#5351107)
1270 const char *super_name = (const char *) cls->super_class;
1272 cls->super_class = _class_asOld(objc_getClass(super_name));
1273 // metaclass's superclass is superclass's metaclass
1274 cls->isa->super_class = cls->super_class->isa;
1276 // Replacement for a root class
1277 // cls->super_class already NULL
1278 // root metaclass's superclass is root class
1279 cls->isa->super_class = cls;
1287 /***********************************************************************
1288 * _objc_map_class_refs_for_image. Convert the class ref entries from
1289 * a class name string pointer to a class pointer. If the class does
1290 * not yet exist, the reference is added to a list of pending references
1291 * to be fixed up at a later date.
1292 **********************************************************************/
1293 static void fix_class_ref(struct old_class **ref, const char *name, BOOL isMeta)
1295 struct old_class *cls;
1297 // Get pointer to class of this name
1298 // YES unconnected, YES class loader
1299 cls = _class_asOld(look_up_class(name, YES, YES));
1301 // Referenced class exists. Fix up the reference.
1302 *ref = isMeta ? cls->isa : cls;
1304 // Referenced class does not exist yet. Insert a placeholder
1305 // class and fix up the reference later.
1306 pendClassReference (ref, name, isMeta);
1307 *ref = (struct old_class *)_class_getNonexistentObjectClass();
1311 static void _objc_map_class_refs_for_image (header_info * hi)
1313 struct old_class **cls_refs;
1317 // Locate class refs in image
1318 cls_refs = _getObjcClassRefs (hi, &count);
1320 // Process each class ref
1321 for (index = 0; index < count; index += 1) {
1322 // Ref is initially class name char*
1323 const char *name = (const char *) cls_refs[index];
1325 // rdar://5453039 is the entire page zero, or just this pointer
1326 uintptr_t *p = (uintptr_t *)(((uintptr_t)&cls_refs[index]) & ~0xfff);
1327 uintptr_t *end = (uintptr_t *)(((uintptr_t)p)+0x1000);
1329 for ( ; p < end; p++) {
1335 _objc_inform_on_crash("rdar://5453039 page around %p IS%s clear",
1336 &cls_refs[index], clear ? "" : " NOT");
1337 // crash in the usual spot so CrashTracer coalesces it
1339 fix_class_ref(&cls_refs[index], name, NO /*never meta*/);
1345 /***********************************************************************
1346 * _objc_remove_pending_class_refs_in_image
1347 * Delete any pending class ref fixups for class refs in the given image,
1348 * because the image is about to be unloaded.
1349 **********************************************************************/
1350 static void removePendingReferences(struct old_class **refs, size_t count)
1352 struct old_class **end = refs + count;
1355 if (!pendingClassRefsMap) return;
1357 // Search the pending class ref table for class refs in this range.
1358 // The class refs may have already been stomped with nonexistentClass,
1359 // so there's no way to recover the original class name.
1362 PendingClassRef *pending;
1363 NXMapState state = NXInitMapState(pendingClassRefsMap);
1364 while(NXNextMapState(pendingClassRefsMap, &state,
1365 (const void **)&key, (const void **)&pending))
1367 for ( ; pending != NULL; pending = pending->next) {
1368 if (pending->ref >= refs && pending->ref < end) {
1369 pending->ref = NULL;
1375 static void _objc_remove_pending_class_refs_in_image(header_info *hi)
1377 struct old_class **cls_refs;
1380 // Locate class refs in this image
1381 cls_refs = _getObjcClassRefs(hi, &count);
1382 removePendingReferences(cls_refs, count);
1386 /***********************************************************************
1387 * map_selrefs. For each selector in the specified array,
1388 * replace the name pointer with a uniqued selector.
1389 * If copy is TRUE, all selector data is always copied. This is used
1390 * for registering selectors from unloadable bundles, so the selector
1391 * can still be used after the bundle's data segment is unmapped.
1392 * Returns YES if dst was written to, NO if it was unchanged.
1393 **********************************************************************/
1394 static inline BOOL map_selrefs(SEL *src, SEL *dst, size_t size, BOOL copy)
1397 size_t cnt = size / sizeof(SEL);
1402 // Process each selector
1403 for (index = 0; index < cnt; index += 1)
1407 // Lookup pointer to uniqued string
1408 sel = sel_registerNameNoLock((const char *) src[index], copy);
1410 // Replace this selector with uniqued one (avoid
1411 // modifying the VM page if this would be a NOP)
1412 if (dst[index] != sel) {
1424 /***********************************************************************
1425 * map_message_refs. For each message ref in the specified array,
1426 * replace the name pointer with a uniqued selector.
1427 * If copy is TRUE, all selector data is always copied. This is used
1428 * for registering selectors from unloadable bundles, so the selector
1429 * can still be used after the bundle's data segment is unmapped.
1430 * Returns YES if dst was written to, NO if it was unchanged.
1431 **********************************************************************/
1432 static inline BOOL map_message_refs(message_ref *src, message_ref *dst, size_t size, BOOL copy)
1435 size_t cnt = size / sizeof(message_ref);
1440 // Process each selector
1441 for (index = 0; index < cnt; index += 1)
1445 // Lookup pointer to uniqued string
1446 sel = sel_registerNameNoLock((const char *) src[index].sel, copy);
1448 // Replace this selector with uniqued one (avoid
1449 // modifying the VM page if this would be a NOP)
1450 if (dst[index].sel != sel) {
1451 dst[index].sel = sel;
1462 /***********************************************************************
1463 * map_method_descs. For each method in the specified method list,
1464 * replace the name pointer with a uniqued selector.
1465 * If copy is TRUE, all selector data is always copied. This is used
1466 * for registering selectors from unloadable bundles, so the selector
1467 * can still be used after the bundle's data segment is unmapped.
1468 **********************************************************************/
1469 static void map_method_descs (struct objc_method_description_list * methods, BOOL copy)
1473 if (!methods) return;
1477 // Process each method
1478 for (index = 0; index < methods->count; index += 1)
1480 struct objc_method_description * method;
1483 // Get method entry to fix up
1484 method = &methods->list[index];
1486 // Lookup pointer to uniqued string
1487 sel = sel_registerNameNoLock((const char *) method->name, copy);
1489 // Replace this selector with uniqued one (avoid
1490 // modifying the VM page if this would be a NOP)
1491 if (method->name != sel)
1499 /***********************************************************************
1501 * Returns the protocol extension for the given protocol.
1502 * Returns NULL if the protocol has no extension.
1503 **********************************************************************/
1504 static struct old_protocol_ext *ext_for_protocol(struct old_protocol *proto)
1506 if (!proto) return NULL;
1507 if (!protocol_ext_map) return NULL;
1508 else return (struct old_protocol_ext *)NXMapGet(protocol_ext_map, proto);
1512 /***********************************************************************
1514 * Search a protocol method list for a selector.
1515 **********************************************************************/
1516 static struct objc_method_description *
1517 lookup_method(struct objc_method_description_list *mlist, SEL aSel)
1521 for (i = 0; i < mlist->count; i++) {
1522 if (mlist->list[i].name == aSel) {
1523 return mlist->list+i;
1531 /***********************************************************************
1532 * lookup_protocol_method
1533 * Recursively search for a selector in a protocol
1534 * (and all incorporated protocols)
1535 **********************************************************************/
1536 __private_extern__ struct objc_method_description *
1537 lookup_protocol_method(struct old_protocol *proto, SEL aSel,
1538 BOOL isRequiredMethod, BOOL isInstanceMethod)
1540 struct objc_method_description *m = NULL;
1541 struct old_protocol_ext *ext;
1543 if (isRequiredMethod) {
1544 if (isInstanceMethod) {
1545 m = lookup_method(proto->instance_methods, aSel);
1547 m = lookup_method(proto->class_methods, aSel);
1549 } else if ((ext = ext_for_protocol(proto))) {
1550 if (isInstanceMethod) {
1551 m = lookup_method(ext->optional_instance_methods, aSel);
1553 m = lookup_method(ext->optional_class_methods, aSel);
1557 if (!m && proto->protocol_list) {
1559 for (i = 0; !m && i < proto->protocol_list->count; i++) {
1560 m = lookup_protocol_method(proto->protocol_list->list[i], aSel,
1561 isRequiredMethod, isInstanceMethod);
1569 /***********************************************************************
1571 * Returns the name of the given protocol.
1572 **********************************************************************/
1573 const char *protocol_getName(Protocol *p)
1575 struct old_protocol *proto = oldprotocol(p);
1576 if (!proto) return "nil";
1577 return proto->protocol_name;
1581 /***********************************************************************
1582 * protocol_getMethodDescription
1583 * Returns the description of a named method.
1584 * Searches either required or optional methods.
1585 * Searches either instance or class methods.
1586 **********************************************************************/
1587 struct objc_method_description
1588 protocol_getMethodDescription(Protocol *p, SEL aSel,
1589 BOOL isRequiredMethod, BOOL isInstanceMethod)
1591 struct old_protocol *proto = oldprotocol(p);
1592 if (!proto) return (struct objc_method_description){NULL, NULL};
1594 struct objc_method_description *desc =
1595 lookup_protocol_method(proto, aSel,
1596 isRequiredMethod, isInstanceMethod);
1597 if (desc) return *desc;
1598 else return (struct objc_method_description){NULL, NULL};
1602 /***********************************************************************
1603 * protocol_copyMethodDescriptionList
1604 * Returns an array of method descriptions from a protocol.
1605 * Copies either required or optional methods.
1606 * Copies either instance or class methods.
1607 **********************************************************************/
1608 struct objc_method_description *
1609 protocol_copyMethodDescriptionList(Protocol *p,
1610 BOOL isRequiredMethod,
1611 BOOL isInstanceMethod,
1612 unsigned int *outCount)
1614 struct objc_method_description_list *mlist = NULL;
1615 struct old_protocol *proto = oldprotocol(p);
1616 struct old_protocol_ext *ext;
1619 if (outCount) *outCount = 0;
1623 if (isRequiredMethod) {
1624 if (isInstanceMethod) {
1625 mlist = proto->instance_methods;
1627 mlist = proto->class_methods;
1629 } else if ((ext = ext_for_protocol(proto))) {
1630 if (isInstanceMethod) {
1631 mlist = ext->optional_instance_methods;
1633 mlist = ext->optional_class_methods;
1638 if (outCount) *outCount = 0;
1643 unsigned int count = mlist->count;
1644 struct objc_method_description *result =
1645 calloc(count + 1, sizeof(struct objc_method_description));
1646 for (i = 0; i < count; i++) {
1647 result[i] = mlist->list[i];
1650 if (outCount) *outCount = count;
1655 Property protocol_getProperty(Protocol *p, const char *name,
1656 BOOL isRequiredProperty, BOOL isInstanceProperty)
1658 struct old_protocol *proto = oldprotocol(p);
1660 if (!proto || !name) return NULL;
1662 if (!isRequiredProperty || !isInstanceProperty) {
1663 // Only required instance properties are currently supported
1667 struct old_protocol_ext *ext;
1668 if ((ext = ext_for_protocol(proto))) {
1669 struct objc_property_list *plist;
1670 if ((plist = ext->instance_properties)) {
1672 for (i = 0; i < plist->count; i++) {
1673 Property prop = property_list_nth(plist, i);
1674 if (0 == strcmp(name, prop->name)) {
1681 struct old_protocol_list *plist;
1682 if ((plist = proto->protocol_list)) {
1684 for (i = 0; i < plist->count; i++) {
1686 protocol_getProperty((Protocol *)plist->list[i], name,
1687 isRequiredProperty, isInstanceProperty);
1688 if (prop) return prop;
1696 Property *protocol_copyPropertyList(Protocol *p, unsigned int *outCount)
1698 Property *result = NULL;
1699 struct old_protocol_ext *ext;
1701 struct old_protocol *proto = oldprotocol(p);
1702 if (! (ext = ext_for_protocol(proto))) {
1703 if (outCount) *outCount = 0;
1707 struct objc_property_list *plist = ext->instance_properties;
1708 result = copyPropertyList(plist, outCount);
1714 /***********************************************************************
1715 * protocol_copyProtocolList
1716 * Copies this protocol's incorporated protocols.
1717 * Does not copy those protocol's incorporated protocols in turn.
1718 **********************************************************************/
1719 Protocol **protocol_copyProtocolList(Protocol *p, unsigned int *outCount)
1721 unsigned int count = 0;
1722 Protocol **result = NULL;
1723 struct old_protocol *proto = oldprotocol(p);
1726 if (outCount) *outCount = 0;
1730 if (proto->protocol_list) {
1731 count = (unsigned int)proto->protocol_list->count;
1734 result = malloc((count+1) * sizeof(Protocol *));
1737 for (i = 0; i < count; i++) {
1738 result[i] = (Protocol *)proto->protocol_list->list[i];
1743 if (outCount) *outCount = count;
1748 BOOL protocol_conformsToProtocol(Protocol *self_gen, Protocol *other_gen)
1750 struct old_protocol *self = oldprotocol(self_gen);
1751 struct old_protocol *other = oldprotocol(other_gen);
1753 if (!self || !other) {
1757 if (0 == strcmp(self->protocol_name, other->protocol_name)) {
1761 if (self->protocol_list) {
1763 for (i = 0; i < self->protocol_list->count; i++) {
1764 struct old_protocol *proto = self->protocol_list->list[i];
1765 if (0 == strcmp(other->protocol_name, proto->protocol_name)) {
1768 if (protocol_conformsToProtocol((Protocol *)proto, other_gen)) {
1778 BOOL protocol_isEqual(Protocol *self, Protocol *other)
1780 if (self == other) return YES;
1781 if (!self || !other) return NO;
1783 if (!protocol_conformsToProtocol(self, other)) return NO;
1784 if (!protocol_conformsToProtocol(other, self)) return NO;
1790 /***********************************************************************
1791 * _objc_fixup_protocol_objects_for_image. For each protocol in the
1792 * specified image, selectorize the method names and add to the protocol hash.
1793 **********************************************************************/
1795 static BOOL versionIsExt(uintptr_t version, const char *names, size_t size)
1797 // CodeWarrior used isa field for string "Protocol"
1798 // from section __OBJC,__class_names. rdar://4951638
1799 // gcc (10.4 and earlier) used isa field for version number;
1800 // the only version number used on Mac OS X was 2.
1801 // gcc (10.5 and later) uses isa field for ext pointer
1803 if (version < 4096) {
1807 if (version >= (uintptr_t)names && version < (uintptr_t)(names + size)) {
1814 static void fix_protocol(struct old_protocol *proto, Class protocolClass,
1815 BOOL isBundle, const char *names, size_t names_size)
1817 #warning GrP fixme hack
1820 uintptr_t version = (uintptr_t)proto->isa;
1822 // Set the protocol's isa
1823 proto->isa = protocolClass;
1825 // Fix up method lists
1826 // fixme share across duplicates
1827 map_method_descs (proto->instance_methods, isBundle);
1828 map_method_descs (proto->class_methods, isBundle);
1830 // Fix up ext, if any
1831 if (versionIsExt(version, names, names_size)) {
1832 struct old_protocol_ext *ext = (struct old_protocol_ext *)version;
1833 NXMapInsert(protocol_ext_map, proto, ext);
1834 map_method_descs (ext->optional_instance_methods, isBundle);
1835 map_method_descs (ext->optional_class_methods, isBundle);
1838 // Record the protocol it if we don't have one with this name yet
1839 // fixme bundles - copy protocol
1841 if (!NXMapGet(protocol_map, proto->protocol_name)) {
1842 NXMapKeyCopyingInsert(protocol_map, proto->protocol_name, proto);
1843 if (PrintProtocols) {
1844 _objc_inform("PROTOCOLS: protocol at %p is %s",
1845 proto, proto->protocol_name);
1848 // duplicate - do nothing
1849 if (PrintProtocols) {
1850 _objc_inform("PROTOCOLS: protocol at %p is %s (duplicate)",
1851 proto, proto->protocol_name);
1856 static void _objc_fixup_protocol_objects_for_image (header_info * hi)
1858 Class protocolClass = objc_getClass("Protocol");
1860 struct old_protocol *protos;
1861 int isBundle = hi->mhdr->filetype == MH_BUNDLE;
1865 OBJC_LOCK(&classLock);
1867 // Allocate the protocol registry if necessary.
1868 if (!protocol_map) {
1870 NXCreateMapTableFromZone(NXStrValueMapPrototype, 32,
1871 _objc_internal_zone());
1873 if (!protocol_ext_map) {
1875 NXCreateMapTableFromZone(NXPtrValueMapPrototype, 32,
1876 _objc_internal_zone());
1879 protos = _getObjcProtocols(hi, &count);
1880 names = _getObjcClassNames(hi, &names_size);
1881 for (i = 0; i < count; i++) {
1882 fix_protocol(&protos[i], protocolClass, isBundle, names, names_size);
1885 OBJC_UNLOCK(&classLock);
1889 /***********************************************************************
1890 * _objc_fixup_selector_refs. Register all of the selectors in each
1891 * image, and fix them all up.
1892 **********************************************************************/
1893 static void _objc_fixup_selector_refs (const header_info *hi)
1898 // Fix up selector refs
1899 sels = _getObjcSelectorRefs (hi, &count);
1901 map_selrefs(sels, sels, count * sizeof(SEL),
1902 hi->mhdr->filetype == MH_BUNDLE);
1907 /***********************************************************************
1909 * Perform metadata processing for hCount images starting with firstNewHeader
1910 **********************************************************************/
1911 __private_extern__ void _read_images(header_info **hList, uint32_t hCount)
1915 if (!class_hash) _objc_init_class_hash();
1917 // Parts of this order are important for correctness or performance.
1919 // Read classes from all images.
1920 for (i = 0; i < hCount; i++) {
1921 _objc_read_classes_from_image(hList[i]);
1924 // Read categories from all images.
1925 BOOL needFlush = NO;
1926 for (i = 0; i < hCount; i++) {
1927 needFlush |= _objc_read_categories_from_image(hList[i]);
1929 if (needFlush) flush_marked_caches();
1931 // Connect classes from all images.
1932 for (i = 0; i < hCount; i++) {
1933 _objc_connect_classes_from_image(hList[i]);
1936 // Fix up class refs, selector refs, and protocol objects from all images.
1937 for (i = 0; i < hCount; i++) {
1938 _objc_map_class_refs_for_image(hList[i]);
1939 _objc_fixup_selector_refs(hList[i]);
1940 _objc_fixup_protocol_objects_for_image(hList[i]);
1945 /***********************************************************************
1946 * prepare_load_methods
1947 * Schedule +load for classes in this image, any un-+load-ed
1948 * superclasses in other images, and any categories in this image.
1949 **********************************************************************/
1950 // Recursively schedule +load for cls and any un-+load-ed superclasses.
1951 // cls must already be connected.
1952 static void schedule_class_load(struct old_class *cls)
1954 if (cls->info & CLS_LOADED) return;
1955 if (cls->super_class) schedule_class_load(cls->super_class);
1956 add_class_to_loadable_list((Class)cls);
1957 cls->info |= CLS_LOADED;
1960 __private_extern__ void prepare_load_methods(header_info *hi)
1966 if (_objcHeaderIsReplacement(hi)) {
1967 // Ignore any classes in this image
1971 // Major loop - process all modules in the image
1973 for (midx = 0; midx < hi->mod_count; midx += 1)
1977 // Skip module containing no classes
1978 if (mods[midx].symtab == NULL)
1981 // Minor loop - process all the classes in given module
1982 for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
1984 // Locate the class description pointer
1985 struct old_class *cls = mods[midx].symtab->defs[index];
1986 if (cls->info & CLS_CONNECTED) {
1987 schedule_class_load(cls);
1993 // Major loop - process all modules in the header
1996 // NOTE: The module and category lists are traversed backwards
1997 // to preserve the pre-10.4 processing order. Changing the order
1998 // would have a small chance of introducing binary compatibility bugs.
1999 midx = hi->mod_count;
2000 while (midx-- > 0) {
2003 Symtab symtab = mods[midx].symtab;
2005 // Nothing to do for a module without a symbol table
2006 if (mods[midx].symtab == NULL)
2008 // Total entries in symbol table (class entries followed
2009 // by category entries)
2010 total = mods[midx].symtab->cls_def_cnt +
2011 mods[midx].symtab->cat_def_cnt;
2013 // Minor loop - register all categories from given module
2015 while (index-- > mods[midx].symtab->cls_def_cnt) {
2016 struct old_category *cat = symtab->defs[index];
2017 add_category_to_loadable_list((Category)cat);
2023 /***********************************************************************
2024 * _objc_remove_classes_in_image
2025 * Remove all classes in the given image from the runtime, because
2026 * the image is about to be unloaded.
2027 * Things to clean up:
2029 * unconnected_class_hash
2030 * pending subclasses list (only if class is still unconnected)
2031 * loadable class list
2032 * class's method caches
2033 * class refs in all other images
2034 **********************************************************************/
2035 // Re-pend any class references in refs that point into [start..end)
2036 static void rependClassReferences(struct old_class **refs, size_t count,
2037 uintptr_t start, uintptr_t end)
2043 // Process each class ref
2044 for (i = 0; i < count; i++) {
2045 if ((uintptr_t)(refs[i]) >= start && (uintptr_t)(refs[i]) < end) {
2046 pendClassReference(&refs[i], refs[i]->name,
2047 (refs[i]->info & CLS_META) ? YES : NO);
2048 refs[i] = (struct old_class *)_class_getNonexistentObjectClass();
2054 static void try_free(const void *p)
2056 if (p && malloc_size(p)) free((void *)p);
2059 // Deallocate all memory in a method list
2060 static void unload_mlist(struct old_method_list *mlist)
2063 if (mlist->obsolete == _OBJC_FIXED_UP) {
2064 for (i = 0; i < mlist->method_count; i++) {
2065 try_free(mlist->method_list[i].method_types);
2072 // Deallocate all memory in a class.
2073 __private_extern__ void unload_class(struct old_class *cls)
2078 for (i = 0; i < cls->ivars->ivar_count; i++) {
2079 try_free(cls->ivars->ivar_list[i].ivar_name);
2080 try_free(cls->ivars->ivar_list[i].ivar_type);
2082 try_free(cls->ivars);
2085 // Free fixed-up method lists and method list array
2086 if (cls->methodLists) {
2087 // more than zero method lists
2088 if (cls->info & CLS_NO_METHOD_ARRAY) {
2090 unload_mlist((struct old_method_list *)cls->methodLists);
2093 // more than one method list
2094 struct old_method_list **mlistp;
2095 for (mlistp = cls->methodLists;
2096 *mlistp != NULL && *mlistp != END_OF_METHODS_LIST;
2099 unload_mlist(*mlistp);
2101 free(cls->methodLists);
2105 // Free protocol list
2106 struct old_protocol_list *protos = cls->protocols;
2108 struct old_protocol_list *dead = protos;
2109 protos = protos->next;
2113 // Free method cache
2114 if (cls->cache && cls->cache != &_objc_empty_cache) {
2115 _cache_free(cls->cache);
2118 if ((cls->info & CLS_EXT)) {
2120 // Free property lists and property list array
2121 if (cls->ext->propertyLists) {
2122 // more than zero property lists
2123 if (cls->info & CLS_NO_PROPERTY_ARRAY) {
2124 // one property list
2125 try_free(cls->ext->propertyLists);
2127 // more than one property list
2128 struct objc_property_list **plistp;
2129 for (plistp = cls->ext->propertyLists;
2135 try_free(cls->ext->propertyLists);
2139 // Free weak ivar layout
2140 try_free(cls->ext->weak_ivar_layout);
2146 // Free non-weak ivar layout
2147 try_free(cls->ivar_layout);
2151 try_free(cls->name);
2158 static void _objc_remove_classes_in_image(header_info *hi)
2164 OBJC_LOCK(&classLock);
2166 // Major loop - process all modules in the image
2168 for (midx = 0; midx < hi->mod_count; midx += 1)
2170 // Skip module containing no classes
2171 if (mods[midx].symtab == NULL)
2174 // Minor loop - process all the classes in given module
2175 for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
2177 struct old_class *cls;
2179 // Locate the class description pointer
2180 cls = mods[midx].symtab->defs[index];
2182 // Remove from loadable class list, if present
2183 remove_class_from_loadable_list((Class)cls);
2185 // Remove from unconnected_class_hash and pending subclasses
2186 if (unconnected_class_hash && NXHashMember(unconnected_class_hash, cls)) {
2187 NXHashRemove(unconnected_class_hash, cls);
2188 if (pendingSubclassesMap) {
2189 // Find this class in its superclass's pending list
2190 char *supercls_name = (char *)cls->super_class;
2191 PendingSubclass *pending =
2192 NXMapGet(pendingSubclassesMap, supercls_name);
2193 for ( ; pending != NULL; pending = pending->next) {
2194 if (pending->subclass == cls) {
2195 pending->subclass = Nil;
2202 // Remove from class_hash
2203 NXHashRemove(class_hash, cls);
2205 // Free heap memory pointed to by the class
2206 unload_class(cls->isa);
2212 // Search all other images for class refs that point back to this range.
2213 // Un-fix and re-pend any such class refs.
2215 // Get the location of the dying image's __OBJC segment
2216 uintptr_t seg = hi->objcSegmentHeader->vmaddr + hi->image_slide;
2217 size_t seg_size = hi->objcSegmentHeader->filesize;
2219 header_info *other_hi;
2220 for (other_hi = _objc_headerStart();
2222 other_hi = other_hi->next)
2224 struct old_class **other_refs;
2226 if (other_hi == hi) continue; // skip the image being unloaded
2228 // Fix class refs in the other image
2229 other_refs = _getObjcClassRefs(other_hi, &count);
2230 rependClassReferences(other_refs, count, seg, seg+seg_size);
2233 OBJC_UNLOCK(&classLock);
2237 /***********************************************************************
2238 * _objc_remove_categories_in_image
2239 * Remove all categories in the given image from the runtime, because
2240 * the image is about to be unloaded.
2241 * Things to clean up:
2242 * unresolved category list
2243 * loadable category list
2244 **********************************************************************/
2245 static void _objc_remove_categories_in_image(header_info *hi)
2250 // Major loop - process all modules in the header
2253 for (midx = 0; midx < hi->mod_count; midx++) {
2256 Symtab symtab = mods[midx].symtab;
2258 // Nothing to do for a module without a symbol table
2259 if (symtab == NULL) continue;
2261 // Total entries in symbol table (class entries followed
2262 // by category entries)
2263 total = symtab->cls_def_cnt + symtab->cat_def_cnt;
2265 // Minor loop - check all categories from given module
2266 for (index = symtab->cls_def_cnt; index < total; index++) {
2267 struct old_category *cat = symtab->defs[index];
2269 // Clean up loadable category list
2270 remove_category_from_loadable_list((Category)cat);
2272 // Clean up category_hash
2273 if (category_hash) {
2274 _objc_unresolved_category *cat_entry =
2275 NXMapGet(category_hash, cat->class_name);
2276 for ( ; cat_entry != NULL; cat_entry = cat_entry->next) {
2277 if (cat_entry->cat == cat) {
2278 cat_entry->cat = NULL;
2288 /***********************************************************************
2290 * Various paranoid debugging checks that look for poorly-behaving
2291 * unloadable bundles.
2292 * Called by _objc_unmap_image when OBJC_UNLOAD_DEBUG is set.
2293 **********************************************************************/
2294 static void unload_paranoia(header_info *hi)
2296 // Get the location of the dying image's __OBJC segment
2297 uintptr_t seg = hi->objcSegmentHeader->vmaddr + hi->image_slide;
2298 size_t seg_size = hi->objcSegmentHeader->filesize;
2300 _objc_inform("UNLOAD DEBUG: unloading image '%s' [%p..%p]",
2301 _nameForHeader(hi->mhdr), (void *)seg, (void*)(seg+seg_size));
2303 OBJC_LOCK(&classLock);
2305 // Make sure the image contains no categories on surviving classes.
2310 // Major loop - process all modules in the header
2313 for (midx = 0; midx < hi->mod_count; midx++) {
2316 Symtab symtab = mods[midx].symtab;
2318 // Nothing to do for a module without a symbol table
2319 if (symtab == NULL) continue;
2321 // Total entries in symbol table (class entries followed
2322 // by category entries)
2323 total = symtab->cls_def_cnt + symtab->cat_def_cnt;
2325 // Minor loop - check all categories from given module
2326 for (index = symtab->cls_def_cnt; index < total; index++) {
2327 struct old_category *cat = symtab->defs[index];
2328 struct old_class query;
2330 query.name = cat->class_name;
2331 if (NXHashMember(class_hash, &query)) {
2332 _objc_inform("UNLOAD DEBUG: dying image contains category '%s(%s)' on surviving class '%s'!", cat->class_name, cat->category_name, cat->class_name);
2338 // Make sure no surviving class is in the dying image.
2339 // Make sure no surviving class has a superclass in the dying image.
2340 // fixme check method implementations too
2342 struct old_class *cls;
2345 state = NXInitHashState(class_hash);
2346 while (NXNextHashState(class_hash, &state, (void **)&cls)) {
2347 if ((vm_address_t)cls >= seg &&
2348 (vm_address_t)cls < seg+seg_size)
2350 _objc_inform("UNLOAD DEBUG: dying image contains surviving class '%s'!", cls->name);
2353 if ((vm_address_t)cls->super_class >= seg &&
2354 (vm_address_t)cls->super_class < seg+seg_size)
2356 _objc_inform("UNLOAD DEBUG: dying image contains superclass '%s' of surviving class '%s'!", cls->super_class->name, cls->name);
2361 OBJC_UNLOCK(&classLock);
2365 /***********************************************************************
2367 * Only handles MH_BUNDLE for now.
2368 **********************************************************************/
2369 __private_extern__ void _unload_image(header_info *hi)
2372 // Remove image's classes from the class list and free auxiliary data.
2373 // Remove image's unresolved or loadable categories and free auxiliary data
2374 // Remove image's unresolved class refs.
2375 _objc_remove_classes_in_image(hi);
2376 _objc_remove_categories_in_image(hi);
2377 _objc_remove_pending_class_refs_in_image(hi);
2379 // Perform various debugging checks if requested.
2380 if (DebugUnload) unload_paranoia(hi);
2384 /***********************************************************************
2385 * objc_addClass. Add the specified class to the table of known classes,
2386 * after doing a little verification and fixup.
2387 **********************************************************************/
2388 void objc_addClass (Class cls_gen)
2390 struct old_class *cls = _class_asOld(cls_gen);
2392 OBJC_WARN_DEPRECATED;
2394 // Synchronize access to hash table
2395 OBJC_LOCK (&classLock);
2397 // Make sure both the class and the metaclass have caches!
2398 // Clear all bits of the info fields except CLS_CLASS and CLS_META.
2399 // Normally these bits are already clear but if someone tries to cons
2400 // up their own class on the fly they might need to be cleared.
2401 if (cls->cache == NULL) {
2402 cls->cache = (Cache) &_objc_empty_cache;
2403 cls->info = CLS_CLASS;
2406 if (cls->isa->cache == NULL) {
2407 cls->isa->cache = (Cache) &_objc_empty_cache;
2408 cls->isa->info = CLS_META;
2411 // methodLists should be:
2412 // 1. NULL (Tiger and later only)
2413 // 2. A -1 terminated method list array
2414 // In either case, CLS_NO_METHOD_ARRAY remains clear.
2415 // If the user manipulates the method list directly,
2416 // they must use the magic private format.
2418 // Add the class to the table
2419 (void) NXHashInsert (class_hash, cls);
2421 // Superclass is no longer a leaf for cache flushing
2422 if (cls->super_class && (cls->super_class->info & CLS_LEAF)) {
2423 _class_clearInfo((Class)cls->super_class, CLS_LEAF);
2424 _class_clearInfo((Class)cls->super_class->isa, CLS_LEAF);
2428 OBJC_UNLOCK (&classLock);
2431 /***********************************************************************
2432 * _objcTweakMethodListPointerForClass.
2433 * Change the class's method list pointer to a method list array.
2434 * Does nothing if the method list pointer is already a method list array.
2435 * If the class is currently in use, methodListLock must be held by the caller.
2436 **********************************************************************/
2437 static void _objcTweakMethodListPointerForClass(struct old_class *cls)
2439 struct old_method_list * originalList;
2440 const int initialEntries = 4;
2442 struct old_method_list ** ptr;
2444 // Do nothing if methodLists is already an array.
2445 if (cls->methodLists && !(cls->info & CLS_NO_METHOD_ARRAY)) return;
2447 // Remember existing list
2448 originalList = (struct old_method_list *) cls->methodLists;
2450 // Allocate and zero a method list array
2451 mallocSize = sizeof(struct old_method_list *) * initialEntries;
2452 ptr = (struct old_method_list **) _calloc_internal(1, mallocSize);
2454 // Insert the existing list into the array
2455 ptr[initialEntries - 1] = END_OF_METHODS_LIST;
2456 ptr[0] = originalList;
2458 // Replace existing list with array
2459 cls->methodLists = ptr;
2460 _class_clearInfo((Class)cls, CLS_NO_METHOD_ARRAY);
2464 /***********************************************************************
2465 * _objc_insertMethods.
2466 * Adds methods to a class.
2467 * Does not flush any method caches.
2468 * Does not take any locks.
2469 * If the class is already in use, use class_addMethods() instead.
2470 **********************************************************************/
2471 __private_extern__ void _objc_insertMethods(struct old_class *cls,
2472 struct old_method_list *mlist,
2473 struct old_category *cat)
2475 struct old_method_list ***list;
2476 struct old_method_list **ptr;
2481 if (!cls->methodLists) {
2482 // cls has no methods - simply use this method list
2483 cls->methodLists = (struct old_method_list **)mlist;
2484 _class_setInfo((Class)cls, CLS_NO_METHOD_ARRAY);
2488 // Log any existing methods being replaced
2489 if (PrintReplacedMethods) {
2491 for (i = 0; i < mlist->method_count; i++) {
2492 extern IMP findIMPInClass(struct old_class *cls, SEL sel);
2493 SEL sel = sel_registerName((char *)mlist->method_list[i].method_name);
2494 IMP newImp = mlist->method_list[i].method_imp;
2497 if ((oldImp = findIMPInClass(cls, sel))) {
2498 _objc_inform("REPLACED: %c[%s %s] %s%s (IMP was %p, now %p)",
2499 ISMETA(cls) ? '+' : '-',
2500 cls->name, sel_getName(sel),
2501 cat ? "by category " : "",
2502 cat ? cat->category_name : "",
2508 // Create method list array if necessary
2509 _objcTweakMethodListPointerForClass(cls);
2511 list = &cls->methodLists;
2513 // Locate unused entry for insertion point
2515 while ((*ptr != 0) && (*ptr != END_OF_METHODS_LIST))
2518 // If array is full, add to it
2519 if (*ptr == END_OF_METHODS_LIST)
2521 // Calculate old and new dimensions
2522 endIndex = ptr - *list;
2523 oldSize = (endIndex + 1) * sizeof(void *);
2524 newSize = oldSize + sizeof(struct old_method_list *); // only increase by 1
2526 // Grow the method list array by one.
2527 // This block may be from user code; don't use _realloc_internal
2528 *list = (struct old_method_list **)realloc(*list, newSize);
2530 // Zero out addition part of new array
2531 bzero (&((*list)[endIndex]), newSize - oldSize);
2533 // Place new end marker
2534 (*list)[(newSize/sizeof(void *)) - 1] = END_OF_METHODS_LIST;
2536 // Insertion point corresponds to old array end
2537 ptr = &((*list)[endIndex]);
2540 // Right shift existing entries by one
2541 bcopy (*list, (*list) + 1, ((void *) ptr) - ((void *) *list));
2543 // Insert at method list at beginning of array
2547 /***********************************************************************
2548 * _objc_removeMethods.
2549 * Remove methods from a class.
2550 * Does not take any locks.
2551 * Does not flush any method caches.
2552 * If the class is currently in use, use class_removeMethods() instead.
2553 **********************************************************************/
2554 __private_extern__ void _objc_removeMethods(struct old_class *cls,
2555 struct old_method_list *mlist)
2557 struct old_method_list ***list;
2558 struct old_method_list **ptr;
2560 if (cls->methodLists == NULL) {
2561 // cls has no methods
2564 if (cls->methodLists == (struct old_method_list **)mlist) {
2565 // mlist is the class's only method list - erase it
2566 cls->methodLists = NULL;
2569 if (cls->info & CLS_NO_METHOD_ARRAY) {
2570 // cls has only one method list, and this isn't it - do nothing
2574 // cls has a method list array - search it
2576 list = &cls->methodLists;
2578 // Locate list in the array
2580 while (*ptr != mlist) {
2581 // fix for radar # 2538790
2582 if ( *ptr == END_OF_METHODS_LIST ) return;
2586 // Remove this entry
2589 // Left shift the following entries
2590 while (*(++ptr) != END_OF_METHODS_LIST)
2595 /***********************************************************************
2596 * _objc_add_category. Install the specified category's methods and
2597 * protocols into the class it augments.
2598 * The class is assumed not to be in use yet: no locks are taken and
2599 * no method caches are flushed.
2600 **********************************************************************/
2601 static inline void _objc_add_category(struct old_class *cls, struct old_category *category, int version)
2603 if (PrintConnecting) {
2604 _objc_inform("CONNECT: attaching category '%s (%s)'", cls->name, category->category_name);
2607 // Augment instance methods
2608 if (category->instance_methods)
2609 _objc_insertMethods (cls, category->instance_methods, category);
2611 // Augment class methods
2612 if (category->class_methods)
2613 _objc_insertMethods (cls->isa, category->class_methods, category);
2615 // Augment protocols
2616 if ((version >= 5) && category->protocols)
2618 if (cls->isa->version >= 5)
2620 category->protocols->next = cls->protocols;
2621 cls->protocols = category->protocols;
2622 cls->isa->protocols = category->protocols;
2626 _objc_inform ("unable to add protocols from category %s...\n", category->category_name);
2627 _objc_inform ("class `%s' must be recompiled\n", category->class_name);
2631 // Augment properties
2632 if (version >= 7 && category->instance_properties) {
2633 if (cls->isa->version >= 6) {
2634 _class_addProperties(cls, category->instance_properties);
2636 _objc_inform ("unable to add properties from category %s...\n", category->category_name);
2637 _objc_inform ("class `%s' must be recompiled\n", category->class_name);
2642 /***********************************************************************
2643 * _objc_add_category_flush_caches. Install the specified category's
2644 * methods into the class it augments, and flush the class' method cache.
2645 * Return YES if some method caches now need to be flushed.
2646 **********************************************************************/
2647 static BOOL _objc_add_category_flush_caches(struct old_class *cls, struct old_category *category, int version)
2649 BOOL needFlush = NO;
2651 // Install the category's methods into its intended class
2652 OBJC_LOCK(&methodListLock);
2653 _objc_add_category (cls, category, version);
2654 OBJC_UNLOCK(&methodListLock);
2656 // Queue for cache flushing so category's methods can get called
2657 if (category->instance_methods) {
2658 _class_setInfo((Class)cls, CLS_FLUSH_CACHE);
2661 if (category->class_methods) {
2662 _class_setInfo((Class)cls->isa, CLS_FLUSH_CACHE);
2670 /***********************************************************************
2672 * Reverse the given linked list of pending categories.
2673 * The pending category list is built backwards, and needs to be
2674 * reversed before actually attaching the categories to a class.
2675 * Returns the head of the new linked list.
2676 **********************************************************************/
2677 static _objc_unresolved_category *reverse_cat(_objc_unresolved_category *cat)
2679 if (!cat) return NULL;
2681 _objc_unresolved_category *prev = NULL;
2682 _objc_unresolved_category *cur = cat;
2683 _objc_unresolved_category *ahead = cat->next;
2696 /***********************************************************************
2697 * resolve_categories_for_class.
2698 * Install all existing categories intended for the specified class.
2699 * cls must be a true class and not a metaclass.
2700 **********************************************************************/
2701 static void resolve_categories_for_class(struct old_class *cls)
2703 _objc_unresolved_category * pending;
2704 _objc_unresolved_category * next;
2706 // Nothing to do if there are no categories at all
2707 if (!category_hash) return;
2709 // Locate and remove first element in category list
2710 // associated with this class
2711 pending = NXMapKeyFreeingRemove (category_hash, cls->name);
2713 // Traverse the list of categories, if any, registered for this class
2715 // The pending list is built backwards. Reverse it and walk forwards.
2716 pending = reverse_cat(pending);
2720 // Install the category
2721 // use the non-flush-cache version since we are only
2722 // called from the class intialization code
2723 _objc_add_category(cls, pending->cat, (int)pending->version);
2726 // Delink and reclaim this registration
2727 next = pending->next;
2728 _free_internal(pending);
2734 /***********************************************************************
2735 * _objc_resolve_categories_for_class.
2736 * Public version of resolve_categories_for_class. This was
2737 * exported pre-10.4 for Omni et al. to workaround a problem
2738 * with too-lazy category attachment.
2739 * cls should be a class, but this function can also cope with metaclasses.
2740 **********************************************************************/
2741 void _objc_resolve_categories_for_class(Class cls_gen)
2743 struct old_class *cls = _class_asOld(cls_gen);
2745 // If cls is a metaclass, get the class.
2746 // resolve_categories_for_class() requires a real class to work correctly.
2748 if (strncmp(cls->name, "_%", 2) == 0) {
2749 // Posee's meta's name is smashed and isn't in the class_hash,
2750 // so objc_getClass doesn't work.
2751 char *baseName = strchr(cls->name, '%'); // get posee's real name
2752 cls = _class_asOld(objc_getClass(baseName));
2754 cls = _class_asOld(objc_getClass(cls->name));
2758 resolve_categories_for_class(cls);
2762 /***********************************************************************
2763 * _objc_register_category.
2764 * Process a category read from an image.
2765 * If the category's class exists, attach the category immediately.
2766 * Classes that need cache flushing are marked but not flushed.
2767 * If the category's class does not exist yet, pend the category for
2768 * later attachment. Pending categories are attached in the order
2769 * they were discovered.
2770 * Returns YES if some method caches now need to be flushed.
2771 **********************************************************************/
2772 static BOOL _objc_register_category(struct old_category *cat, int version)
2774 _objc_unresolved_category * new_cat;
2775 _objc_unresolved_category * old;
2776 struct old_class *theClass;
2778 // If the category's class exists, attach the category.
2779 if ((theClass = _class_asOld(objc_lookUpClass(cat->class_name)))) {
2780 return _objc_add_category_flush_caches(theClass, cat, version);
2783 // If the category's class exists but is unconnected,
2784 // then attach the category to the class but don't bother
2785 // flushing any method caches (because they must be empty).
2786 // YES unconnected, NO class_handler
2787 if ((theClass = _class_asOld(look_up_class(cat->class_name, YES, NO)))) {
2788 _objc_add_category(theClass, cat, version);
2793 // Category's class does not exist yet.
2794 // Save the category for later attachment.
2796 if (PrintConnecting) {
2797 _objc_inform("CONNECT: pending category '%s (%s)'", cat->class_name, cat->category_name);
2800 // Create category lookup table if needed
2802 category_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype,
2804 _objc_internal_zone ());
2806 // Locate an existing list of categories, if any, for the class.
2807 old = NXMapGet (category_hash, cat->class_name);
2809 // Register the category to be fixed up later.
2810 // The category list is built backwards, and is reversed again
2811 // by resolve_categories_for_class().
2812 new_cat = _malloc_internal(sizeof(_objc_unresolved_category));
2813 new_cat->next = old;
2815 new_cat->version = version;
2816 (void) NXMapKeyCopyingInsert (category_hash, cat->class_name, new_cat);
2822 __private_extern__ const char **
2823 _objc_copyClassNamesForImage(header_info *hi, unsigned int *outCount)
2836 for (m = 0; m < hi->mod_count; m++) {
2839 if (!mods[m].symtab) continue;
2841 for (d = 0; d < mods[m].symtab->cls_def_cnt; d++) {
2842 struct old_class *cls = mods[m].symtab->defs[d];
2843 // fixme what about future-ified classes?
2844 if (class_is_connected(cls)) {
2845 if (count == allocated) {
2846 allocated = allocated*2 + 16;
2847 list = realloc(list, allocated * sizeof(char *));
2849 list[count++] = cls->name;
2855 // NULL-terminate non-empty list
2856 if (count == allocated) {
2857 allocated = allocated+1;
2858 list = realloc(list, allocated * sizeof(char *));
2863 if (outCount) *outCount = count;