]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-runtime-old.m
objc4-437.1.tar.gz
[apple/objc4.git] / runtime / objc-runtime-old.m
1 /*
2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /***********************************************************************
25 * objc-runtime-old.m
26 * Support for old-ABI classes and images.
27 **********************************************************************/
28
29 /***********************************************************************
30 * Class loading and connecting (GrP 2004-2-11)
31 *
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
35 * +load methods.
36 *
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.
41 *
42 * (Historical note)
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)
53 *
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.
60 *
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.
67 *
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.
74 *
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.
79 *
80 * Image mapping sequence:
81 *
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),
89 * and pend the rest.
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:
96 * connect the class
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.
109 *
110 * Performance: all classes are read before any categories are read.
111 * Fewer categories need be pended for lack of a parent class.
112 *
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.)
117 *
118 * Performance: all classes are read before any classes are connected.
119 * Fewer classes need be pended for lack of a superclass.
120 *
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.
124 *
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.
129 *
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.
134 *
135 **********************************************************************/
136
137 #if !__OBJC2__
138
139 #define OLD 1
140 #include "objc-private.h"
141 #include "objc-loadmethod.h"
142
143 /* NXHashTable SPI */
144 extern unsigned _NXHashCapacity(NXHashTable *table);
145 extern void _NXHashRehashToCapacity(NXHashTable *table, unsigned newCapacity);
146
147
148 typedef struct _objc_unresolved_category
149 {
150 struct _objc_unresolved_category *next;
151 struct old_category *cat; // may be NULL
152 long version;
153 } _objc_unresolved_category;
154
155 typedef struct _PendingSubclass
156 {
157 struct old_class *subclass; // subclass to finish connecting; may be NULL
158 struct _PendingSubclass *next;
159 } PendingSubclass;
160
161 typedef struct _PendingClassRef
162 {
163 struct old_class **ref; // class reference to fix up; may be NULL
164 // (ref & 1) is a metaclass reference
165 struct _PendingClassRef *next;
166 } PendingClassRef;
167
168
169 static uintptr_t classHash(void *info, Class data);
170 static int classIsEqual(void *info, Class name, Class cls);
171 static int _objc_defaultClassHandler(const char *clsName);
172 static BOOL class_is_connected(struct old_class *cls);
173 static inline NXMapTable *pendingClassRefsMapTable(void);
174 static inline NXMapTable *pendingSubclassesMapTable(void);
175 static void pendClassInstallation(struct old_class *cls, const char *superName);
176 static void pendClassReference(struct old_class **ref, const char *className, BOOL isMeta);
177 static void resolve_references_to_class(struct old_class *cls);
178 static void resolve_subclasses_of_class(struct old_class *cls);
179 static void really_connect_class(struct old_class *cls, struct old_class *supercls);
180 static BOOL connect_class(struct old_class *cls);
181 static void map_method_descs (struct objc_method_description_list * methods, BOOL copy);
182 static void _objcTweakMethodListPointerForClass(struct old_class *cls);
183 static inline void _objc_add_category(struct old_class *cls, struct old_category *category, int version);
184 static BOOL _objc_add_category_flush_caches(struct old_class *cls, struct old_category *category, int version);
185 static _objc_unresolved_category *reverse_cat(_objc_unresolved_category *cat);
186 static void resolve_categories_for_class(struct old_class *cls);
187 static BOOL _objc_register_category(struct old_category *cat, int version);
188
189
190 // Function called when a class is loaded from an image
191 __private_extern__ void (*callbackFunction)(Class, const char *) = 0;
192
193 // Hash table of classes
194 __private_extern__ NXHashTable * class_hash NOBSS = 0;
195 static NXHashTablePrototype classHashPrototype =
196 {
197 (uintptr_t (*) (const void *, const void *)) classHash,
198 (int (*)(const void *, const void *, const void *)) classIsEqual,
199 NXNoEffectFree, 0
200 };
201
202 // Hash table of unconnected classes
203 static NXHashTable *unconnected_class_hash NOBSS = NULL;
204
205 // Exported copy of class_hash variable (hook for debugging tools)
206 NXHashTable *_objc_debug_class_hash = NULL;
207
208 // Category and class registries
209 // Keys are COPIES of strings, to prevent stale pointers with unloaded bundles
210 // Use NXMapKeyCopyingInsert and NXMapKeyFreeingRemove
211 static NXMapTable * category_hash = NULL;
212
213 // Keys are COPIES of strings, to prevent stale pointers with unloaded bundles
214 // Use NXMapKeyCopyingInsert and NXMapKeyFreeingRemove
215 static NXMapTable * pendingClassRefsMap = NULL;
216 static NXMapTable * pendingSubclassesMap = NULL;
217
218 // Protocols
219 static NXMapTable *protocol_map = NULL; // name -> protocol
220 static NXMapTable *protocol_ext_map = NULL; // protocol -> protocol ext
221
222 // Function pointer objc_getClass calls through when class is not found
223 static int (*objc_classHandler) (const char *) = _objc_defaultClassHandler;
224
225 // Function pointer called by objc_getClass and objc_lookupClass when
226 // class is not found. _objc_classLoader is called before objc_classHandler.
227 static BOOL (*_objc_classLoader)(const char *) = NULL;
228
229
230 /***********************************************************************
231 * objc_dump_class_hash. Log names of all known classes.
232 **********************************************************************/
233 __private_extern__ void objc_dump_class_hash(void)
234 {
235 NXHashTable *table;
236 unsigned count;
237 Class data;
238 NXHashState state;
239
240 table = class_hash;
241 count = 0;
242 state = NXInitHashState (table);
243 while (NXNextHashState (table, &state, (void **) &data))
244 printf ("class %d: %s\n", ++count, _class_getName(data));
245 }
246
247
248 /***********************************************************************
249 * _objc_init_class_hash. Return the class lookup table, create it if
250 * necessary.
251 **********************************************************************/
252 __private_extern__ void _objc_init_class_hash(void)
253 {
254 // Do nothing if class hash table already exists
255 if (class_hash)
256 return;
257
258 // class_hash starts small, with only enough capacity for libobjc itself.
259 // If a second library is found by map_images(), class_hash is immediately
260 // resized to capacity 1024 to cut down on rehashes.
261 // Old numbers: A smallish Foundation+AppKit program will have
262 // about 520 classes. Larger apps (like IB or WOB) have more like
263 // 800 classes. Some customers have massive quantities of classes.
264 // Foundation-only programs aren't likely to notice the ~6K loss.
265 class_hash = NXCreateHashTableFromZone (classHashPrototype,
266 16,
267 nil,
268 _objc_internal_zone ());
269 _objc_debug_class_hash = class_hash;
270 }
271
272
273 /***********************************************************************
274 * objc_getClassList. Return the known classes.
275 **********************************************************************/
276 int objc_getClassList(Class *buffer, int bufferLen)
277 {
278 NXHashState state;
279 Class cls;
280 int cnt, num;
281
282 mutex_lock(&classLock);
283 if (!class_hash) {
284 mutex_unlock(&classLock);
285 return 0;
286 }
287 num = NXCountHashTable(class_hash);
288 if (NULL == buffer) {
289 mutex_unlock(&classLock);
290 return num;
291 }
292 cnt = 0;
293 state = NXInitHashState(class_hash);
294 while (cnt < bufferLen &&
295 NXNextHashState(class_hash, &state, (void **)&cls))
296 {
297 buffer[cnt++] = cls;
298 }
299 mutex_unlock(&classLock);
300 return num;
301 }
302
303
304 /***********************************************************************
305 * objc_copyProtocolList
306 * Returns pointers to all protocols.
307 * Locking: acquires classLock
308 **********************************************************************/
309 Protocol **
310 objc_copyProtocolList(unsigned int *outCount)
311 {
312 int count, i;
313 Protocol *proto;
314 const char *name;
315 NXMapState state;
316 Protocol **result;
317
318 mutex_lock(&classLock);
319
320 count = NXCountMapTable(protocol_map);
321 if (count == 0) {
322 mutex_unlock(&classLock);
323 if (outCount) *outCount = 0;
324 return NULL;
325 }
326
327 result = calloc(1 + count, sizeof(Protocol *));
328
329 i = 0;
330 state = NXInitMapState(protocol_map);
331 while (NXNextMapState(protocol_map, &state,
332 (const void **)&name, (const void **)&proto))
333 {
334 result[i++] = proto;
335 }
336
337 result[i++] = NULL;
338 assert(i == count+1);
339
340 mutex_unlock(&classLock);
341
342 if (outCount) *outCount = count;
343 return result;
344 }
345
346
347 /***********************************************************************
348 * objc_getClasses. Return class lookup table.
349 *
350 * NOTE: This function is very dangerous, since you cannot safely use
351 * the hashtable without locking it, and the lock is private!
352 **********************************************************************/
353 void *objc_getClasses(void)
354 {
355 OBJC_WARN_DEPRECATED;
356
357 // Return the class lookup hash table
358 return class_hash;
359 }
360
361
362 /***********************************************************************
363 * classHash.
364 **********************************************************************/
365 static uintptr_t classHash(void *info, Class data)
366 {
367 // Nil classes hash to zero
368 if (!data)
369 return 0;
370
371 // Call through to real hash function
372 return _objc_strhash (_class_getName(data));
373 }
374
375 /***********************************************************************
376 * classIsEqual. Returns whether the class names match. If we ever
377 * check more than the name, routines like objc_lookUpClass have to
378 * change as well.
379 **********************************************************************/
380 static int classIsEqual(void *info, Class name, Class cls)
381 {
382 // Standard string comparison
383 // Our local inlined version is significantly shorter on PPC and avoids the
384 // mflr/mtlr and dyld_stub overhead when calling strcmp.
385 return _objc_strcmp(_class_getName(name), _class_getName(cls)) == 0;
386 }
387
388
389 // Unresolved future classes
390 static NXHashTable *future_class_hash = NULL;
391
392 // Resolved future<->original classes
393 static NXMapTable *future_class_to_original_class_map = NULL;
394 static NXMapTable *original_class_to_future_class_map = NULL;
395
396 // CF requests about 20 future classes; HIToolbox requests one.
397 #define FUTURE_COUNT 32
398
399
400 /***********************************************************************
401 * setOriginalClassForFutureClass
402 * Record resolution of a future class.
403 **********************************************************************/
404 static void setOriginalClassForFutureClass(struct old_class *futureClass,
405 struct old_class *originalClass)
406 {
407 if (!future_class_to_original_class_map) {
408 future_class_to_original_class_map =
409 NXCreateMapTableFromZone (NXPtrValueMapPrototype, FUTURE_COUNT,
410 _objc_internal_zone ());
411 original_class_to_future_class_map =
412 NXCreateMapTableFromZone (NXPtrValueMapPrototype, FUTURE_COUNT,
413 _objc_internal_zone ());
414 }
415
416 NXMapInsert (future_class_to_original_class_map,
417 futureClass, originalClass);
418 NXMapInsert (original_class_to_future_class_map,
419 originalClass, futureClass);
420
421 if (PrintFuture) {
422 _objc_inform("FUTURE: using %p instead of %p for %s", futureClass, originalClass, originalClass->name);
423 }
424 }
425
426 /***********************************************************************
427 * getOriginalClassForFutureClass
428 * getFutureClassForOriginalClass
429 * Switch between a future class and its corresponding original class.
430 * The future class is the one actually in use.
431 * The original class is the one from disk.
432 **********************************************************************/
433 /*
434 static struct old_class *
435 getOriginalClassForFutureClass(struct old_class *futureClass)
436 {
437 if (!future_class_to_original_class_map) return Nil;
438 return NXMapGet (future_class_to_original_class_map, futureClass);
439 }
440 */
441 static struct old_class *
442 getFutureClassForOriginalClass(struct old_class *originalClass)
443 {
444 if (!original_class_to_future_class_map) return Nil;
445 return NXMapGet (original_class_to_future_class_map, originalClass);
446 }
447
448
449 /***********************************************************************
450 * makeFutureClass
451 * Initialize the memory in *cls with an unresolved future class with the
452 * given name. The memory is recorded in future_class_hash.
453 **********************************************************************/
454 static void makeFutureClass(struct old_class *cls, const char *name)
455 {
456 // CF requests about 20 future classes, plus HIToolbox has one.
457 if (!future_class_hash) {
458 future_class_hash =
459 NXCreateHashTableFromZone(classHashPrototype, FUTURE_COUNT,
460 NULL, _objc_internal_zone());
461 }
462
463 cls->name = _strdup_internal(name);
464 NXHashInsert(future_class_hash, cls);
465
466 if (PrintFuture) {
467 _objc_inform("FUTURE: reserving %p for %s", cls, name);
468 }
469 }
470
471
472 /***********************************************************************
473 * _objc_allocateFutureClass
474 * Allocate an unresolved future class for the given class name.
475 * Returns any existing allocation if one was already made.
476 * Assumes the named class doesn't exist yet.
477 * Not thread safe.
478 **********************************************************************/
479 __private_extern__ Class _objc_allocateFutureClass(const char *name)
480 {
481 struct old_class *cls;
482
483 if (future_class_hash) {
484 struct old_class query;
485 query.name = name;
486 if ((cls = NXHashGet(future_class_hash, &query))) {
487 // Already have a future class for this name.
488 return (Class)cls;
489 }
490 }
491
492 cls = (struct old_class *)_calloc_class(sizeof(*cls));
493 makeFutureClass(cls, name);
494 return (Class)cls;
495 }
496
497
498 /***********************************************************************
499 * objc_setFutureClass.
500 * Like objc_getFutureClass, but uses the provided memory block.
501 * If the class already exists, a posing-like substitution is performed.
502 * Not thread safe.
503 **********************************************************************/
504 void objc_setFutureClass(Class cls, const char *name)
505 {
506 struct old_class *oldcls;
507 struct old_class *newcls = (struct old_class *)cls; // Not a real class!
508
509 if ((oldcls = _class_asOld((Class)look_up_class(name, NO/*unconnected*/, NO/*classhandler*/)))) {
510 setOriginalClassForFutureClass(newcls, oldcls);
511 // fixme hack
512 memcpy(newcls, oldcls, sizeof(struct objc_class));
513 newcls->info &= ~CLS_EXT;
514
515 mutex_lock(&classLock);
516 NXHashRemove(class_hash, oldcls);
517 objc_removeRegisteredClass((Class)oldcls);
518 change_class_references(newcls, oldcls, nil, YES);
519 NXHashInsert(class_hash, newcls);
520 objc_addRegisteredClass((Class)newcls);
521 mutex_unlock(&classLock);
522 } else {
523 makeFutureClass(newcls, name);
524 }
525 }
526
527
528 /***********************************************************************
529 * _objc_defaultClassHandler. Default objc_classHandler. Does nothing.
530 **********************************************************************/
531 static int _objc_defaultClassHandler(const char *clsName)
532 {
533 // Return zero so objc_getClass doesn't bother re-searching
534 return 0;
535 }
536
537 /***********************************************************************
538 * objc_setClassHandler. Set objc_classHandler to the specified value.
539 *
540 * NOTE: This should probably deal with userSuppliedHandler being NULL,
541 * because the objc_classHandler caller does not check... it would bus
542 * error. It would make sense to handle NULL by restoring the default
543 * handler. Is anyone hacking with this, though?
544 **********************************************************************/
545 void objc_setClassHandler(int (*userSuppliedHandler)(const char *))
546 {
547 OBJC_WARN_DEPRECATED;
548
549 objc_classHandler = userSuppliedHandler;
550 }
551
552
553 /***********************************************************************
554 * _objc_setClassLoader
555 * Similar to objc_setClassHandler, but objc_classLoader is used for
556 * both objc_getClass() and objc_lookupClass(), and objc_classLoader
557 * pre-empts objc_classHandler.
558 **********************************************************************/
559 void _objc_setClassLoader(BOOL (*newClassLoader)(const char *))
560 {
561 _objc_classLoader = newClassLoader;
562 }
563
564
565 /***********************************************************************
566 * objc_getProtocol
567 * Get a protocol by name, or NULL.
568 **********************************************************************/
569 Protocol *objc_getProtocol(const char *name)
570 {
571 Protocol *result;
572 if (!protocol_map) return NULL;
573 mutex_lock(&classLock);
574 result = (Protocol *)NXMapGet(protocol_map, name);
575 mutex_unlock(&classLock);
576 return result;
577 }
578
579
580 /***********************************************************************
581 * look_up_class
582 * Map a class name to a class using various methods.
583 * This is the common implementation of objc_lookUpClass and objc_getClass,
584 * and is also used internally to get additional search options.
585 * Sequence:
586 * 1. class_hash
587 * 2. unconnected_class_hash (optional)
588 * 3. classLoader callback
589 * 4. classHandler callback (optional)
590 **********************************************************************/
591 __private_extern__ id look_up_class(const char *aClassName, BOOL includeUnconnected, BOOL includeClassHandler)
592 {
593 BOOL includeClassLoader = YES; // class loader cannot be skipped
594 id result = nil;
595 struct old_class query;
596
597 query.name = aClassName;
598
599 retry:
600
601 if (!result && class_hash) {
602 // Check ordinary classes
603 mutex_lock (&classLock);
604 result = (id)NXHashGet(class_hash, &query);
605 mutex_unlock (&classLock);
606 }
607
608 if (!result && includeUnconnected && unconnected_class_hash) {
609 // Check not-yet-connected classes
610 mutex_lock(&classLock);
611 result = (id)NXHashGet(unconnected_class_hash, &query);
612 mutex_unlock(&classLock);
613 }
614
615 if (!result && includeClassLoader && _objc_classLoader) {
616 // Try class loader callback
617 if ((*_objc_classLoader)(aClassName)) {
618 // Re-try lookup without class loader
619 includeClassLoader = NO;
620 goto retry;
621 }
622 }
623
624 if (!result && includeClassHandler && objc_classHandler) {
625 // Try class handler callback
626 if ((*objc_classHandler)(aClassName)) {
627 // Re-try lookup without class handler or class loader
628 includeClassLoader = NO;
629 includeClassHandler = NO;
630 goto retry;
631 }
632 }
633
634 return result;
635 }
636
637
638 /***********************************************************************
639 * class_is_connected.
640 * Returns TRUE if class cls is connected.
641 * A connected class has either a connected superclass or a NULL superclass,
642 * and is present in class_hash.
643 **********************************************************************/
644 static BOOL class_is_connected(struct old_class *cls)
645 {
646 BOOL result;
647 mutex_lock(&classLock);
648 result = NXHashMember(class_hash, cls);
649 mutex_unlock(&classLock);
650 return result;
651 }
652
653
654 /***********************************************************************
655 * _class_isLoadable.
656 * Returns TRUE if class cls is ready for its +load method to be called.
657 * A class is ready for +load if it is connected.
658 **********************************************************************/
659 __private_extern__ BOOL _class_isLoadable(Class cls)
660 {
661 return class_is_connected(_class_asOld(cls));
662 }
663
664
665 /***********************************************************************
666 * pendingClassRefsMapTable. Return a pointer to the lookup table for
667 * pending class refs.
668 **********************************************************************/
669 static inline NXMapTable *pendingClassRefsMapTable(void)
670 {
671 // Allocate table if needed
672 if (!pendingClassRefsMap) {
673 pendingClassRefsMap =
674 NXCreateMapTableFromZone(NXStrValueMapPrototype,
675 10, _objc_internal_zone ());
676 }
677
678 // Return table pointer
679 return pendingClassRefsMap;
680 }
681
682
683 /***********************************************************************
684 * pendingSubclassesMapTable. Return a pointer to the lookup table for
685 * pending subclasses.
686 **********************************************************************/
687 static inline NXMapTable *pendingSubclassesMapTable(void)
688 {
689 // Allocate table if needed
690 if (!pendingSubclassesMap) {
691 pendingSubclassesMap =
692 NXCreateMapTableFromZone(NXStrValueMapPrototype,
693 10, _objc_internal_zone ());
694 }
695
696 // Return table pointer
697 return pendingSubclassesMap;
698 }
699
700
701 /***********************************************************************
702 * pendClassInstallation
703 * Finish connecting class cls when its superclass becomes connected.
704 * Check for multiple pends of the same class because connect_class does not.
705 **********************************************************************/
706 static void pendClassInstallation(struct old_class *cls, const char *superName)
707 {
708 NXMapTable *table;
709 PendingSubclass *pending;
710 PendingSubclass *oldList;
711 PendingSubclass *l;
712
713 // Create and/or locate pending class lookup table
714 table = pendingSubclassesMapTable ();
715
716 // Make sure this class isn't already in the pending list.
717 oldList = NXMapGet (table, superName);
718 for (l = oldList; l != NULL; l = l->next) {
719 if (l->subclass == cls) return; // already here, nothing to do
720 }
721
722 // Create entry referring to this class
723 pending = _malloc_internal(sizeof(PendingSubclass));
724 pending->subclass = cls;
725
726 // Link new entry into head of list of entries for this class
727 pending->next = oldList;
728
729 // (Re)place entry list in the table
730 NXMapKeyCopyingInsert (table, superName, pending);
731 }
732
733
734 /***********************************************************************
735 * pendClassReference
736 * Fix up a class ref when the class with the given name becomes connected.
737 **********************************************************************/
738 static void pendClassReference(struct old_class **ref, const char *className, BOOL isMeta)
739 {
740 NXMapTable *table;
741 PendingClassRef *pending;
742
743 // Create and/or locate pending class lookup table
744 table = pendingClassRefsMapTable ();
745
746 // Create entry containing the class reference
747 pending = _malloc_internal(sizeof(PendingClassRef));
748 pending->ref = ref;
749 if (isMeta) {
750 pending->ref = (struct old_class **)((uintptr_t)pending->ref | 1);
751 }
752
753 // Link new entry into head of list of entries for this class
754 pending->next = NXMapGet (table, className);
755
756 // (Re)place entry list in the table
757 NXMapKeyCopyingInsert (table, className, pending);
758
759 if (PrintConnecting) {
760 _objc_inform("CONNECT: pended reference to class '%s%s' at %p",
761 className, isMeta ? " (meta)" : "", (void *)ref);
762 }
763 }
764
765
766 /***********************************************************************
767 * resolve_references_to_class
768 * Fix up any pending class refs to this class.
769 **********************************************************************/
770 static void resolve_references_to_class(struct old_class *cls)
771 {
772 PendingClassRef *pending;
773
774 if (!pendingClassRefsMap) return; // no unresolved refs for any class
775
776 pending = NXMapGet(pendingClassRefsMap, cls->name);
777 if (!pending) return; // no unresolved refs for this class
778
779 NXMapKeyFreeingRemove(pendingClassRefsMap, cls->name);
780
781 if (PrintConnecting) {
782 _objc_inform("CONNECT: resolving references to class '%s'", cls->name);
783 }
784
785 while (pending) {
786 PendingClassRef *next = pending->next;
787 if (pending->ref) {
788 BOOL isMeta = ((uintptr_t)pending->ref & 1) ? YES : NO;
789 struct old_class **ref =
790 (struct old_class **)((uintptr_t)pending->ref & ~(uintptr_t)1);
791 *ref = isMeta ? cls->isa : cls;
792 }
793 _free_internal(pending);
794 pending = next;
795 }
796
797 if (NXCountMapTable(pendingClassRefsMap) == 0) {
798 NXFreeMapTable(pendingClassRefsMap);
799 pendingClassRefsMap = NULL;
800 }
801 }
802
803
804 /***********************************************************************
805 * resolve_subclasses_of_class
806 * Fix up any pending subclasses of this class.
807 **********************************************************************/
808 static void resolve_subclasses_of_class(struct old_class *cls)
809 {
810 PendingSubclass *pending;
811
812 if (!pendingSubclassesMap) return; // no unresolved subclasses
813
814 pending = NXMapGet(pendingSubclassesMap, cls->name);
815 if (!pending) return; // no unresolved subclasses for this class
816
817 NXMapKeyFreeingRemove(pendingSubclassesMap, cls->name);
818
819 // Destroy the pending table if it's now empty, to save memory.
820 if (NXCountMapTable(pendingSubclassesMap) == 0) {
821 NXFreeMapTable(pendingSubclassesMap);
822 pendingSubclassesMap = NULL;
823 }
824
825 if (PrintConnecting) {
826 _objc_inform("CONNECT: resolving subclasses of class '%s'", cls->name);
827 }
828
829 while (pending) {
830 PendingSubclass *next = pending->next;
831 if (pending->subclass) connect_class(pending->subclass);
832 _free_internal(pending);
833 pending = next;
834 }
835 }
836
837
838 /***********************************************************************
839 * really_connect_class
840 * Connect cls to superclass supercls unconditionally.
841 * Also adjust the class hash tables and handle pended subclasses.
842 *
843 * This should be called from connect_class() ONLY.
844 **********************************************************************/
845 static void really_connect_class(struct old_class *cls,
846 struct old_class *supercls)
847 {
848 struct old_class *oldCls;
849
850 // Connect superclass pointers.
851 set_superclass(cls, supercls);
852
853 // Update GC layouts
854 // For paranoia, this is a conservative update:
855 // only non-strong -> strong and weak -> strong are corrected.
856 if (UseGC && supercls &&
857 (cls->info & CLS_EXT) && (supercls->info & CLS_EXT))
858 {
859 BOOL layoutChanged;
860 layout_bitmap ivarBitmap =
861 layout_bitmap_create(cls->ivar_layout,
862 cls->instance_size,
863 cls->instance_size, NO);
864
865 layout_bitmap superBitmap =
866 layout_bitmap_create(supercls->ivar_layout,
867 supercls->instance_size,
868 supercls->instance_size, NO);
869
870 // non-strong -> strong: bits set in super should be set in sub
871 layoutChanged = layout_bitmap_or(ivarBitmap, superBitmap, cls->name);
872 layout_bitmap_free(superBitmap);
873
874 if (layoutChanged) {
875 layout_bitmap weakBitmap = {0};
876 BOOL weakLayoutChanged = NO;
877
878 if (cls->ext && cls->ext->weak_ivar_layout) {
879 // weak -> strong: strong bits should be cleared in weak layout
880 // This is a subset of non-strong -> strong
881 weakBitmap =
882 layout_bitmap_create(cls->ext->weak_ivar_layout,
883 cls->instance_size,
884 cls->instance_size, YES);
885
886 weakLayoutChanged =
887 layout_bitmap_clear(weakBitmap, ivarBitmap, cls->name);
888 } else {
889 // no existing weak ivars, so no weak -> strong changes
890 }
891
892 // Rebuild layout strings.
893 if (PrintIvars) {
894 _objc_inform("IVARS: gc layout changed "
895 "for class %s (super %s)",
896 cls->name, supercls->name);
897 if (weakLayoutChanged) {
898 _objc_inform("IVARS: gc weak layout changed "
899 "for class %s (super %s)",
900 cls->name, supercls->name);
901 }
902 }
903 cls->ivar_layout = layout_string_create(ivarBitmap);
904 if (weakLayoutChanged) {
905 cls->ext->weak_ivar_layout = layout_string_create(weakBitmap);
906 }
907
908 layout_bitmap_free(weakBitmap);
909 }
910
911 layout_bitmap_free(ivarBitmap);
912 }
913
914 // Done!
915 cls->info |= CLS_CONNECTED;
916
917 mutex_lock(&classLock);
918
919 // Update hash tables.
920 NXHashRemove(unconnected_class_hash, cls);
921 oldCls = NXHashInsert(class_hash, cls);
922 objc_addRegisteredClass((Class)cls);
923
924 // Delete unconnected_class_hash if it is now empty.
925 if (NXCountHashTable(unconnected_class_hash) == 0) {
926 NXFreeHashTable(unconnected_class_hash);
927 unconnected_class_hash = NULL;
928 }
929
930 // No duplicate classes allowed.
931 // Duplicates should have been rejected by _objc_read_classes_from_image.
932 assert(!oldCls);
933
934 mutex_unlock(&classLock);
935
936 // Connect newly-connectable subclasses
937 resolve_subclasses_of_class(cls);
938
939 // GC debugging: make sure all classes with -dealloc also have -finalize
940 if (DebugFinalizers) {
941 extern IMP findIMPInClass(struct old_class *cls, SEL sel);
942 if (findIMPInClass(cls, sel_getUid("dealloc")) &&
943 ! findIMPInClass(cls, sel_getUid("finalize")))
944 {
945 _objc_inform("GC: class '%s' implements -dealloc but not -finalize", cls->name);
946 }
947 }
948
949 // Debugging: if this class has ivars, make sure this class's ivars don't
950 // overlap with its super's. This catches some broken fragile base classes.
951 // Do not use super->instance_size vs. self->ivar[0] to check this.
952 // Ivars may be packed across instance_size boundaries.
953 if (DebugFragileSuperclasses && cls->ivars && cls->ivars->ivar_count) {
954 struct old_class *ivar_cls = supercls;
955
956 // Find closest superclass that has some ivars, if one exists.
957 while (ivar_cls &&
958 (!ivar_cls->ivars || ivar_cls->ivars->ivar_count == 0))
959 {
960 ivar_cls = ivar_cls->super_class;
961 }
962
963 if (ivar_cls) {
964 // Compare superclass's last ivar to this class's first ivar
965 struct old_ivar *super_ivar =
966 &ivar_cls->ivars->ivar_list[ivar_cls->ivars->ivar_count - 1];
967 struct old_ivar *self_ivar =
968 &cls->ivars->ivar_list[0];
969
970 // fixme could be smarter about super's ivar size
971 if (self_ivar->ivar_offset <= super_ivar->ivar_offset) {
972 _objc_inform("WARNING: ivars of superclass '%s' and "
973 "subclass '%s' overlap; superclass may have "
974 "changed since subclass was compiled",
975 ivar_cls->name, cls->name);
976 }
977 }
978 }
979 }
980
981
982 /***********************************************************************
983 * connect_class
984 * Connect class cls to its superclasses, if possible.
985 * If cls becomes connected, move it from unconnected_class_hash
986 * to connected_class_hash.
987 * Returns TRUE if cls is connected.
988 * Returns FALSE if cls could not be connected for some reason
989 * (missing superclass or still-unconnected superclass)
990 **********************************************************************/
991 static BOOL connect_class(struct old_class *cls)
992 {
993 if (class_is_connected(cls)) {
994 // This class is already connected to its superclass.
995 // Do nothing.
996 return TRUE;
997 }
998 else if (cls->super_class == NULL) {
999 // This class is a root class.
1000 // Connect it to itself.
1001
1002 if (PrintConnecting) {
1003 _objc_inform("CONNECT: class '%s' now connected (root class)",
1004 cls->name);
1005 }
1006
1007 really_connect_class(cls, NULL);
1008 return TRUE;
1009 }
1010 else {
1011 // This class is not a root class and is not yet connected.
1012 // Connect it if its superclass and root class are already connected.
1013 // Otherwise, add this class to the to-be-connected list,
1014 // pending the completion of its superclass and root class.
1015
1016 // At this point, cls->super_class and cls->isa->isa are still STRINGS
1017 char *supercls_name = (char *)cls->super_class;
1018 struct old_class *supercls;
1019
1020 // YES unconnected, YES class handler
1021 if (NULL == (supercls = _class_asOld((Class)look_up_class(supercls_name, YES, YES)))) {
1022 // Superclass does not exist yet.
1023 // pendClassInstallation will handle duplicate pends of this class
1024 pendClassInstallation(cls, supercls_name);
1025
1026 if (PrintConnecting) {
1027 _objc_inform("CONNECT: class '%s' NOT connected (missing super)", cls->name);
1028 }
1029 return FALSE;
1030 }
1031
1032 if (! connect_class(supercls)) {
1033 // Superclass exists but is not yet connected.
1034 // pendClassInstallation will handle duplicate pends of this class
1035 pendClassInstallation(cls, supercls_name);
1036
1037 if (PrintConnecting) {
1038 _objc_inform("CONNECT: class '%s' NOT connected (unconnected super)", cls->name);
1039 }
1040 return FALSE;
1041 }
1042
1043 // Superclass exists and is connected.
1044 // Connect this class to the superclass.
1045
1046 if (PrintConnecting) {
1047 _objc_inform("CONNECT: class '%s' now connected", cls->name);
1048 }
1049
1050 really_connect_class(cls, supercls);
1051 return TRUE;
1052 }
1053 }
1054
1055
1056 /***********************************************************************
1057 * _objc_read_categories_from_image.
1058 * Read all categories from the given image.
1059 * Install them on their parent classes, or register them for later
1060 * installation.
1061 * Returns YES if some method caches now need to be flushed.
1062 **********************************************************************/
1063 static BOOL _objc_read_categories_from_image (header_info * hi)
1064 {
1065 Module mods;
1066 size_t midx;
1067 BOOL needFlush = NO;
1068
1069 if (_objcHeaderIsReplacement(hi)) {
1070 // Ignore any categories in this image
1071 return NO;
1072 }
1073
1074
1075 // Major loop - process all modules in the header
1076 mods = hi->mod_ptr;
1077
1078 // NOTE: The module and category lists are traversed backwards
1079 // to preserve the pre-10.4 processing order. Changing the order
1080 // would have a small chance of introducing binary compatibility bugs.
1081 midx = hi->mod_count;
1082 while (midx-- > 0) {
1083 unsigned int index;
1084 unsigned int total;
1085
1086 // Nothing to do for a module without a symbol table
1087 if (mods[midx].symtab == NULL)
1088 continue;
1089
1090 // Total entries in symbol table (class entries followed
1091 // by category entries)
1092 total = mods[midx].symtab->cls_def_cnt +
1093 mods[midx].symtab->cat_def_cnt;
1094
1095 // Minor loop - register all categories from given module
1096 index = total;
1097 while (index-- > mods[midx].symtab->cls_def_cnt) {
1098 struct old_category *cat = mods[midx].symtab->defs[index];
1099 needFlush |= _objc_register_category(cat, (int)mods[midx].version);
1100 }
1101 }
1102
1103 return needFlush;
1104 }
1105
1106
1107 /***********************************************************************
1108 * _objc_read_classes_from_image.
1109 * Read classes from the given image, perform assorted minor fixups,
1110 * scan for +load implementation.
1111 * Does not connect classes to superclasses.
1112 * Does attach pended categories to the classes.
1113 * Adds all classes to unconnected_class_hash. class_hash is unchanged.
1114 **********************************************************************/
1115 static void _objc_read_classes_from_image(header_info *hi)
1116 {
1117 unsigned int index;
1118 unsigned int midx;
1119 Module mods;
1120 int isBundle = headerIsBundle(hi);
1121
1122 if (_objcHeaderIsReplacement(hi)) {
1123 // Ignore any classes in this image
1124 return;
1125 }
1126
1127 // class_hash starts small, enough only for libobjc itself.
1128 // If other Objective-C libraries are found, immediately resize
1129 // class_hash, assuming that Foundation and AppKit are about
1130 // to add lots of classes.
1131 mutex_lock(&classLock);
1132 if (hi->mhdr != libobjc_header && _NXHashCapacity(class_hash) < 1024) {
1133 _NXHashRehashToCapacity(class_hash, 1024);
1134 }
1135 mutex_unlock(&classLock);
1136
1137 // Major loop - process all modules in the image
1138 mods = hi->mod_ptr;
1139 for (midx = 0; midx < hi->mod_count; midx += 1)
1140 {
1141 // Skip module containing no classes
1142 if (mods[midx].symtab == NULL)
1143 continue;
1144
1145 // Minor loop - process all the classes in given module
1146 for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
1147 {
1148 struct old_class *newCls, *oldCls;
1149 BOOL rejected;
1150
1151 // Locate the class description pointer
1152 newCls = mods[midx].symtab->defs[index];
1153
1154 // Classes loaded from Mach-O bundles can be unloaded later.
1155 // Nothing uses this class yet, so _class_setInfo is not needed.
1156 if (isBundle) newCls->info |= CLS_FROM_BUNDLE;
1157 if (isBundle) newCls->isa->info |= CLS_FROM_BUNDLE;
1158
1159 // Use common static empty cache instead of NULL
1160 if (newCls->cache == NULL)
1161 newCls->cache = (Cache) &_objc_empty_cache;
1162 if (newCls->isa->cache == NULL)
1163 newCls->isa->cache = (Cache) &_objc_empty_cache;
1164
1165 // Set metaclass version
1166 newCls->isa->version = mods[midx].version;
1167
1168 // methodLists is NULL or a single list, not an array
1169 newCls->info |= CLS_NO_METHOD_ARRAY|CLS_NO_PROPERTY_ARRAY;
1170 newCls->isa->info |= CLS_NO_METHOD_ARRAY|CLS_NO_PROPERTY_ARRAY;
1171
1172 // class has no subclasses for cache flushing
1173 newCls->info |= CLS_LEAF;
1174 newCls->isa->info |= CLS_LEAF;
1175
1176 if (mods[midx].version >= 6) {
1177 // class structure has ivar_layout and ext fields
1178 newCls->info |= CLS_EXT;
1179 newCls->isa->info |= CLS_EXT;
1180 }
1181
1182 // Check for +load implementation before categories are attached
1183 if (_class_hasLoadMethod((Class)newCls)) {
1184 newCls->isa->info |= CLS_HAS_LOAD_METHOD;
1185 }
1186
1187 // Install into unconnected_class_hash.
1188 mutex_lock(&classLock);
1189
1190 if (future_class_hash) {
1191 struct old_class *futureCls =
1192 NXHashRemove(future_class_hash, newCls);
1193 if (futureCls) {
1194 // Another class structure for this class was already
1195 // prepared by objc_getFutureClass(). Use it instead.
1196 _free_internal((char *)futureCls->name);
1197 memcpy(futureCls, newCls, sizeof(*newCls));
1198 setOriginalClassForFutureClass(futureCls, newCls);
1199 newCls = futureCls;
1200
1201 if (NXCountHashTable(future_class_hash) == 0) {
1202 NXFreeHashTable(future_class_hash);
1203 future_class_hash = NULL;
1204 }
1205 }
1206 }
1207
1208 if (!unconnected_class_hash) {
1209 unconnected_class_hash =
1210 NXCreateHashTableFromZone(classHashPrototype, 128,
1211 NULL, _objc_internal_zone());
1212 }
1213
1214 if ((oldCls = NXHashGet(class_hash, newCls)) ||
1215 (oldCls = NXHashGet(unconnected_class_hash, newCls)))
1216 {
1217 // Another class with this name exists. Complain and reject.
1218 inform_duplicate(newCls->name, (Class)oldCls, (Class)newCls);
1219 rejected = YES;
1220 }
1221 else {
1222 NXHashInsert(unconnected_class_hash, newCls);
1223 rejected = NO;
1224 }
1225
1226 mutex_unlock(&classLock);
1227
1228 if (!rejected) {
1229 // Fix up pended class refs to this class, if any
1230 resolve_references_to_class(newCls);
1231
1232 // Attach pended categories for this class, if any
1233 resolve_categories_for_class(newCls);
1234 }
1235 }
1236 }
1237 }
1238
1239
1240 /***********************************************************************
1241 * _objc_connect_classes_from_image.
1242 * Connect the classes in the given image to their superclasses,
1243 * or register them for later connection if any superclasses are missing.
1244 **********************************************************************/
1245 static void _objc_connect_classes_from_image(header_info *hi)
1246 {
1247 unsigned int index;
1248 unsigned int midx;
1249 Module mods;
1250 BOOL replacement = _objcHeaderIsReplacement(hi);
1251
1252 // Major loop - process all modules in the image
1253 mods = hi->mod_ptr;
1254 for (midx = 0; midx < hi->mod_count; midx += 1)
1255 {
1256 // Skip module containing no classes
1257 if (mods[midx].symtab == NULL)
1258 continue;
1259
1260 // Minor loop - process all the classes in given module
1261 for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
1262 {
1263 struct old_class *cls = mods[midx].symtab->defs[index];
1264 if (! replacement) {
1265 BOOL connected;
1266 struct old_class *futureCls = getFutureClassForOriginalClass(cls);
1267 if (futureCls) {
1268 // objc_getFutureClass() requested a different class
1269 // struct. Fix up the original struct's super_class
1270 // field for [super ...] use, but otherwise perform
1271 // fixups on the new class struct only.
1272 const char *super_name = (const char *) cls->super_class;
1273 if (super_name) cls->super_class = _class_asOld((Class)objc_getClass(super_name));
1274 cls = futureCls;
1275 }
1276 connected = connect_class(cls);
1277 if (connected && callbackFunction) {
1278 (*callbackFunction)((Class)cls, 0);
1279 }
1280 } else {
1281 // Replacement image - fix up super_class only (#3704817)
1282 // And metaclass's super_class (#5351107)
1283 const char *super_name = (const char *) cls->super_class;
1284 if (super_name) {
1285 cls->super_class = _class_asOld((Class)objc_getClass(super_name));
1286 // metaclass's superclass is superclass's metaclass
1287 cls->isa->super_class = cls->super_class->isa;
1288 } else {
1289 // Replacement for a root class
1290 // cls->super_class already NULL
1291 // root metaclass's superclass is root class
1292 cls->isa->super_class = cls;
1293 }
1294 }
1295 }
1296 }
1297 }
1298
1299
1300 /***********************************************************************
1301 * _objc_map_class_refs_for_image. Convert the class ref entries from
1302 * a class name string pointer to a class pointer. If the class does
1303 * not yet exist, the reference is added to a list of pending references
1304 * to be fixed up at a later date.
1305 **********************************************************************/
1306 static void fix_class_ref(struct old_class **ref, const char *name, BOOL isMeta)
1307 {
1308 struct old_class *cls;
1309
1310 // Get pointer to class of this name
1311 // YES unconnected, YES class loader
1312 cls = _class_asOld((Class)look_up_class(name, YES, YES));
1313 if (cls) {
1314 // Referenced class exists. Fix up the reference.
1315 *ref = isMeta ? cls->isa : cls;
1316 } else {
1317 // Referenced class does not exist yet. Insert a placeholder
1318 // class and fix up the reference later.
1319 pendClassReference (ref, name, isMeta);
1320 *ref = (struct old_class *)_class_getNonexistentObjectClass();
1321 }
1322 }
1323
1324 static void _objc_map_class_refs_for_image (header_info * hi)
1325 {
1326 struct old_class **cls_refs;
1327 size_t count;
1328 unsigned int index;
1329
1330 // Locate class refs in image
1331 cls_refs = _getObjcClassRefs (hi, &count);
1332 if (cls_refs) {
1333 // Process each class ref
1334 for (index = 0; index < count; index += 1) {
1335 // Ref is initially class name char*
1336 const char *name = (const char *) cls_refs[index];
1337 if (!name) continue;
1338 fix_class_ref(&cls_refs[index], name, NO /*never meta*/);
1339 }
1340 }
1341 }
1342
1343
1344 /***********************************************************************
1345 * _objc_remove_pending_class_refs_in_image
1346 * Delete any pending class ref fixups for class refs in the given image,
1347 * because the image is about to be unloaded.
1348 **********************************************************************/
1349 static void removePendingReferences(struct old_class **refs, size_t count)
1350 {
1351 struct old_class **end = refs + count;
1352
1353 if (!refs) return;
1354 if (!pendingClassRefsMap) return;
1355
1356 // Search the pending class ref table for class refs in this range.
1357 // The class refs may have already been stomped with nonexistentClass,
1358 // so there's no way to recover the original class name.
1359
1360 {
1361 const char *key;
1362 PendingClassRef *pending;
1363 NXMapState state = NXInitMapState(pendingClassRefsMap);
1364 while(NXNextMapState(pendingClassRefsMap, &state,
1365 (const void **)&key, (const void **)&pending))
1366 {
1367 for ( ; pending != NULL; pending = pending->next) {
1368 if (pending->ref >= refs && pending->ref < end) {
1369 pending->ref = NULL;
1370 }
1371 }
1372 }
1373 }
1374 }
1375
1376 static void _objc_remove_pending_class_refs_in_image(header_info *hi)
1377 {
1378 struct old_class **cls_refs;
1379 size_t count;
1380
1381 // Locate class refs in this image
1382 cls_refs = _getObjcClassRefs(hi, &count);
1383 removePendingReferences(cls_refs, count);
1384 }
1385
1386
1387 /***********************************************************************
1388 * map_selrefs. For each selector in the specified array,
1389 * replace the name pointer with a uniqued selector.
1390 * If copy is TRUE, all selector data is always copied. This is used
1391 * for registering selectors from unloadable bundles, so the selector
1392 * can still be used after the bundle's data segment is unmapped.
1393 * Returns YES if dst was written to, NO if it was unchanged.
1394 **********************************************************************/
1395 static inline void map_selrefs(SEL *sels, size_t count, BOOL copy)
1396 {
1397 size_t index;
1398
1399 if (!sels) return;
1400
1401 sel_lock();
1402
1403 // Process each selector
1404 for (index = 0; index < count; index += 1)
1405 {
1406 SEL sel;
1407
1408 // Lookup pointer to uniqued string
1409 sel = sel_registerNameNoLock((const char *) sels[index], copy);
1410
1411 // Replace this selector with uniqued one (avoid
1412 // modifying the VM page if this would be a NOP)
1413 if (sels[index] != sel) {
1414 sels[index] = sel;
1415 }
1416 }
1417
1418 sel_unlock();
1419 }
1420
1421
1422 /***********************************************************************
1423 * map_method_descs. For each method in the specified method list,
1424 * replace the name pointer with a uniqued selector.
1425 * If copy is TRUE, all selector data is always copied. This is used
1426 * for registering selectors from unloadable bundles, so the selector
1427 * can still be used after the bundle's data segment is unmapped.
1428 **********************************************************************/
1429 static void map_method_descs (struct objc_method_description_list * methods, BOOL copy)
1430 {
1431 int index;
1432
1433 if (!methods) return;
1434
1435 sel_lock();
1436
1437 // Process each method
1438 for (index = 0; index < methods->count; index += 1)
1439 {
1440 struct objc_method_description * method;
1441 SEL sel;
1442
1443 // Get method entry to fix up
1444 method = &methods->list[index];
1445
1446 // Lookup pointer to uniqued string
1447 sel = sel_registerNameNoLock((const char *) method->name, copy);
1448
1449 // Replace this selector with uniqued one (avoid
1450 // modifying the VM page if this would be a NOP)
1451 if (method->name != sel)
1452 method->name = sel;
1453 }
1454
1455 sel_unlock();
1456 }
1457
1458
1459 /***********************************************************************
1460 * ext_for_protocol
1461 * Returns the protocol extension for the given protocol.
1462 * Returns NULL if the protocol has no extension.
1463 **********************************************************************/
1464 static struct old_protocol_ext *ext_for_protocol(struct old_protocol *proto)
1465 {
1466 if (!proto) return NULL;
1467 if (!protocol_ext_map) return NULL;
1468 else return (struct old_protocol_ext *)NXMapGet(protocol_ext_map, proto);
1469 }
1470
1471
1472 /***********************************************************************
1473 * lookup_method
1474 * Search a protocol method list for a selector.
1475 **********************************************************************/
1476 static struct objc_method_description *
1477 lookup_method(struct objc_method_description_list *mlist, SEL aSel)
1478 {
1479 if (mlist) {
1480 int i;
1481 for (i = 0; i < mlist->count; i++) {
1482 if (mlist->list[i].name == aSel) {
1483 return mlist->list+i;
1484 }
1485 }
1486 }
1487 return NULL;
1488 }
1489
1490
1491 /***********************************************************************
1492 * lookup_protocol_method
1493 * Recursively search for a selector in a protocol
1494 * (and all incorporated protocols)
1495 **********************************************************************/
1496 __private_extern__ struct objc_method_description *
1497 lookup_protocol_method(struct old_protocol *proto, SEL aSel,
1498 BOOL isRequiredMethod, BOOL isInstanceMethod)
1499 {
1500 struct objc_method_description *m = NULL;
1501 struct old_protocol_ext *ext;
1502
1503 if (isRequiredMethod) {
1504 if (isInstanceMethod) {
1505 m = lookup_method(proto->instance_methods, aSel);
1506 } else {
1507 m = lookup_method(proto->class_methods, aSel);
1508 }
1509 } else if ((ext = ext_for_protocol(proto))) {
1510 if (isInstanceMethod) {
1511 m = lookup_method(ext->optional_instance_methods, aSel);
1512 } else {
1513 m = lookup_method(ext->optional_class_methods, aSel);
1514 }
1515 }
1516
1517 if (!m && proto->protocol_list) {
1518 int i;
1519 for (i = 0; !m && i < proto->protocol_list->count; i++) {
1520 m = lookup_protocol_method(proto->protocol_list->list[i], aSel,
1521 isRequiredMethod, isInstanceMethod);
1522 }
1523 }
1524
1525 return m;
1526 }
1527
1528
1529 /***********************************************************************
1530 * protocol_getName
1531 * Returns the name of the given protocol.
1532 **********************************************************************/
1533 const char *protocol_getName(Protocol *p)
1534 {
1535 struct old_protocol *proto = oldprotocol(p);
1536 if (!proto) return "nil";
1537 return proto->protocol_name;
1538 }
1539
1540
1541 /***********************************************************************
1542 * protocol_getMethodDescription
1543 * Returns the description of a named method.
1544 * Searches either required or optional methods.
1545 * Searches either instance or class methods.
1546 **********************************************************************/
1547 struct objc_method_description
1548 protocol_getMethodDescription(Protocol *p, SEL aSel,
1549 BOOL isRequiredMethod, BOOL isInstanceMethod)
1550 {
1551 struct objc_method_description empty = {NULL, NULL};
1552 struct old_protocol *proto = oldprotocol(p);
1553 struct objc_method_description *desc;
1554 if (!proto) return empty;
1555
1556 desc = lookup_protocol_method(proto, aSel,
1557 isRequiredMethod, isInstanceMethod);
1558 if (desc) return *desc;
1559 else return empty;
1560 }
1561
1562
1563 /***********************************************************************
1564 * protocol_copyMethodDescriptionList
1565 * Returns an array of method descriptions from a protocol.
1566 * Copies either required or optional methods.
1567 * Copies either instance or class methods.
1568 **********************************************************************/
1569 struct objc_method_description *
1570 protocol_copyMethodDescriptionList(Protocol *p,
1571 BOOL isRequiredMethod,
1572 BOOL isInstanceMethod,
1573 unsigned int *outCount)
1574 {
1575 struct objc_method_description_list *mlist = NULL;
1576 struct old_protocol *proto = oldprotocol(p);
1577 struct old_protocol_ext *ext;
1578 unsigned int i, count;
1579 struct objc_method_description *result;
1580
1581 if (!proto) {
1582 if (outCount) *outCount = 0;
1583 return NULL;
1584 }
1585
1586 if (isRequiredMethod) {
1587 if (isInstanceMethod) {
1588 mlist = proto->instance_methods;
1589 } else {
1590 mlist = proto->class_methods;
1591 }
1592 } else if ((ext = ext_for_protocol(proto))) {
1593 if (isInstanceMethod) {
1594 mlist = ext->optional_instance_methods;
1595 } else {
1596 mlist = ext->optional_class_methods;
1597 }
1598 }
1599
1600 if (!mlist) {
1601 if (outCount) *outCount = 0;
1602 return NULL;
1603 }
1604
1605 count = mlist->count;
1606 result =
1607 calloc(count + 1, sizeof(struct objc_method_description));
1608 for (i = 0; i < count; i++) {
1609 result[i] = mlist->list[i];
1610 }
1611
1612 if (outCount) *outCount = count;
1613 return result;
1614 }
1615
1616
1617 Property protocol_getProperty(Protocol *p, const char *name,
1618 BOOL isRequiredProperty, BOOL isInstanceProperty)
1619 {
1620 struct old_protocol *proto = oldprotocol(p);
1621 struct old_protocol_ext *ext;
1622 struct old_protocol_list *plist;
1623
1624 if (!proto || !name) return NULL;
1625
1626 if (!isRequiredProperty || !isInstanceProperty) {
1627 // Only required instance properties are currently supported
1628 return NULL;
1629 }
1630
1631 if ((ext = ext_for_protocol(proto))) {
1632 struct objc_property_list *plist;
1633 if ((plist = ext->instance_properties)) {
1634 uint32_t i;
1635 for (i = 0; i < plist->count; i++) {
1636 Property prop = property_list_nth(plist, i);
1637 if (0 == strcmp(name, prop->name)) {
1638 return prop;
1639 }
1640 }
1641 }
1642 }
1643
1644 if ((plist = proto->protocol_list)) {
1645 int i;
1646 for (i = 0; i < plist->count; i++) {
1647 Property prop =
1648 protocol_getProperty((Protocol *)plist->list[i], name,
1649 isRequiredProperty, isInstanceProperty);
1650 if (prop) return prop;
1651 }
1652 }
1653
1654 return NULL;
1655 }
1656
1657
1658 Property *protocol_copyPropertyList(Protocol *p, unsigned int *outCount)
1659 {
1660 Property *result = NULL;
1661 struct old_protocol_ext *ext;
1662 struct objc_property_list *plist;
1663
1664 struct old_protocol *proto = oldprotocol(p);
1665 if (! (ext = ext_for_protocol(proto))) {
1666 if (outCount) *outCount = 0;
1667 return NULL;
1668 }
1669
1670 plist = ext->instance_properties;
1671 result = copyPropertyList(plist, outCount);
1672
1673 return result;
1674 }
1675
1676
1677 /***********************************************************************
1678 * protocol_copyProtocolList
1679 * Copies this protocol's incorporated protocols.
1680 * Does not copy those protocol's incorporated protocols in turn.
1681 **********************************************************************/
1682 Protocol **protocol_copyProtocolList(Protocol *p, unsigned int *outCount)
1683 {
1684 unsigned int count = 0;
1685 Protocol **result = NULL;
1686 struct old_protocol *proto = oldprotocol(p);
1687
1688 if (!proto) {
1689 if (outCount) *outCount = 0;
1690 return NULL;
1691 }
1692
1693 if (proto->protocol_list) {
1694 count = (unsigned int)proto->protocol_list->count;
1695 }
1696 if (count > 0) {
1697 unsigned int i;
1698 result = malloc((count+1) * sizeof(Protocol *));
1699
1700 for (i = 0; i < count; i++) {
1701 result[i] = (Protocol *)proto->protocol_list->list[i];
1702 }
1703 result[i] = NULL;
1704 }
1705
1706 if (outCount) *outCount = count;
1707 return result;
1708 }
1709
1710
1711 BOOL protocol_conformsToProtocol(Protocol *self_gen, Protocol *other_gen)
1712 {
1713 struct old_protocol *self = oldprotocol(self_gen);
1714 struct old_protocol *other = oldprotocol(other_gen);
1715
1716 if (!self || !other) {
1717 return NO;
1718 }
1719
1720 if (0 == strcmp(self->protocol_name, other->protocol_name)) {
1721 return YES;
1722 }
1723
1724 if (self->protocol_list) {
1725 int i;
1726 for (i = 0; i < self->protocol_list->count; i++) {
1727 struct old_protocol *proto = self->protocol_list->list[i];
1728 if (0 == strcmp(other->protocol_name, proto->protocol_name)) {
1729 return YES;
1730 }
1731 if (protocol_conformsToProtocol((Protocol *)proto, other_gen)) {
1732 return YES;
1733 }
1734 }
1735 }
1736
1737 return NO;
1738 }
1739
1740
1741 BOOL protocol_isEqual(Protocol *self, Protocol *other)
1742 {
1743 if (self == other) return YES;
1744 if (!self || !other) return NO;
1745
1746 if (!protocol_conformsToProtocol(self, other)) return NO;
1747 if (!protocol_conformsToProtocol(other, self)) return NO;
1748
1749 return YES;
1750 }
1751
1752
1753 /***********************************************************************
1754 * _objc_fixup_protocol_objects_for_image. For each protocol in the
1755 * specified image, selectorize the method names and add to the protocol hash.
1756 **********************************************************************/
1757
1758 static BOOL versionIsExt(uintptr_t version, const char *names, size_t size)
1759 {
1760 // CodeWarrior used isa field for string "Protocol"
1761 // from section __OBJC,__class_names. rdar://4951638
1762 // gcc (10.4 and earlier) used isa field for version number;
1763 // the only version number used on Mac OS X was 2.
1764 // gcc (10.5 and later) uses isa field for ext pointer
1765
1766 if (version < 4096) {
1767 return NO;
1768 }
1769
1770 if (version >= (uintptr_t)names && version < (uintptr_t)(names + size)) {
1771 return NO;
1772 }
1773
1774 return YES;
1775 }
1776
1777 static void fix_protocol(struct old_protocol *proto, Class protocolClass,
1778 BOOL isBundle, const char *names, size_t names_size)
1779 {
1780 uintptr_t version;
1781 if (!proto) return;
1782
1783 version = (uintptr_t)proto->isa;
1784
1785 // Set the protocol's isa
1786 proto->isa = protocolClass;
1787
1788 // Fix up method lists
1789 // fixme share across duplicates
1790 map_method_descs (proto->instance_methods, isBundle);
1791 map_method_descs (proto->class_methods, isBundle);
1792
1793 // Fix up ext, if any
1794 if (versionIsExt(version, names, names_size)) {
1795 struct old_protocol_ext *ext = (struct old_protocol_ext *)version;
1796 NXMapInsert(protocol_ext_map, proto, ext);
1797 map_method_descs (ext->optional_instance_methods, isBundle);
1798 map_method_descs (ext->optional_class_methods, isBundle);
1799 }
1800
1801 // Record the protocol it if we don't have one with this name yet
1802 // fixme bundles - copy protocol
1803 // fixme unloading
1804 if (!NXMapGet(protocol_map, proto->protocol_name)) {
1805 NXMapKeyCopyingInsert(protocol_map, proto->protocol_name, proto);
1806 if (PrintProtocols) {
1807 _objc_inform("PROTOCOLS: protocol at %p is %s",
1808 proto, proto->protocol_name);
1809 }
1810 } else {
1811 // duplicate - do nothing
1812 if (PrintProtocols) {
1813 _objc_inform("PROTOCOLS: protocol at %p is %s (duplicate)",
1814 proto, proto->protocol_name);
1815 }
1816 }
1817 }
1818
1819 static void _objc_fixup_protocol_objects_for_image (header_info * hi)
1820 {
1821 Class protocolClass = (Class)objc_getClass("Protocol");
1822 size_t count, i;
1823 struct old_protocol **protos;
1824 int isBundle = headerIsBundle(hi);
1825 const char *names;
1826 size_t names_size;
1827
1828 mutex_lock(&classLock);
1829
1830 // Allocate the protocol registry if necessary.
1831 if (!protocol_map) {
1832 protocol_map =
1833 NXCreateMapTableFromZone(NXStrValueMapPrototype, 32,
1834 _objc_internal_zone());
1835 }
1836 if (!protocol_ext_map) {
1837 protocol_ext_map =
1838 NXCreateMapTableFromZone(NXPtrValueMapPrototype, 32,
1839 _objc_internal_zone());
1840 }
1841
1842 protos = _getObjcProtocols(hi, &count);
1843 names = _getObjcClassNames(hi, &names_size);
1844 for (i = 0; i < count; i++) {
1845 fix_protocol(protos[i], protocolClass, isBundle, names, names_size);
1846 }
1847
1848 mutex_unlock(&classLock);
1849 }
1850
1851
1852 /***********************************************************************
1853 * _objc_fixup_selector_refs. Register all of the selectors in each
1854 * image, and fix them all up.
1855 **********************************************************************/
1856 static void _objc_fixup_selector_refs (const header_info *hi)
1857 {
1858 size_t count;
1859 SEL *sels;
1860
1861 if (PrintPreopt) {
1862 if (sel_preoptimizationValid(hi)) {
1863 _objc_inform("PREOPTIMIZATION: honoring preoptimized selectors in %s",
1864 _nameForHeader(hi->mhdr));
1865 }
1866 else if (_objcHeaderOptimizedByDyld(hi)) {
1867 _objc_inform("PREOPTIMIZATION: IGNORING preoptimized selectors in %s",
1868 _nameForHeader(hi->mhdr));
1869 }
1870 }
1871
1872 if (sel_preoptimizationValid(hi)) return;
1873
1874 sels = _getObjcSelectorRefs (hi, &count);
1875
1876 map_selrefs(sels, count, headerIsBundle(hi));
1877 }
1878
1879 static inline BOOL _is_threaded() {
1880 #if TARGET_OS_WIN32
1881 return YES;
1882 #else
1883 return pthread_is_threaded_np() != 0;
1884 #endif
1885 }
1886
1887 /***********************************************************************
1888 * unmap_image
1889 * Process the given image which is about to be unmapped by dyld.
1890 * mh is mach_header instead of headerType because that's what
1891 * dyld_priv.h says even for 64-bit.
1892 **********************************************************************/
1893 __private_extern__ void
1894 unmap_image(const struct mach_header *mh, intptr_t vmaddr_slide)
1895 {
1896 recursive_mutex_lock(&loadMethodLock);
1897 unmap_image_nolock(mh, vmaddr_slide);
1898 recursive_mutex_unlock(&loadMethodLock);
1899 }
1900
1901
1902 /***********************************************************************
1903 * map_images
1904 * Process the given images which are being mapped in by dyld.
1905 * Calls ABI-agnostic code after taking ABI-specific locks.
1906 **********************************************************************/
1907 __private_extern__ const char *
1908 map_images(enum dyld_image_states state, uint32_t infoCount,
1909 const struct dyld_image_info infoList[])
1910 {
1911 const char *err;
1912
1913 recursive_mutex_lock(&loadMethodLock);
1914 err = map_images_nolock(state, infoCount, infoList);
1915 recursive_mutex_unlock(&loadMethodLock);
1916
1917 return err;
1918 }
1919
1920
1921 /***********************************************************************
1922 * load_images
1923 * Process +load in the given images which are being mapped in by dyld.
1924 * Calls ABI-agnostic code after taking ABI-specific locks.
1925 *
1926 * Locking: acquires classLock and loadMethodLock
1927 **********************************************************************/
1928 __private_extern__ const char *
1929 load_images(enum dyld_image_states state, uint32_t infoCount,
1930 const struct dyld_image_info infoList[])
1931 {
1932 BOOL found;
1933
1934 recursive_mutex_lock(&loadMethodLock);
1935
1936 // Discover +load methods
1937 found = load_images_nolock(state, infoCount, infoList);
1938
1939 // Call +load methods (without classLock - re-entrant)
1940 if (found) {
1941 call_load_methods();
1942 }
1943
1944 recursive_mutex_unlock(&loadMethodLock);
1945
1946 return NULL;
1947 }
1948
1949
1950 /***********************************************************************
1951 * _read_images
1952 * Perform metadata processing for hCount images starting with firstNewHeader
1953 **********************************************************************/
1954 __private_extern__ void _read_images(header_info **hList, uint32_t hCount)
1955 {
1956 uint32_t i;
1957 BOOL categoriesLoaded = NO;
1958
1959 if (!class_hash) _objc_init_class_hash();
1960
1961 // Parts of this order are important for correctness or performance.
1962
1963 // Read classes from all images.
1964 for (i = 0; i < hCount; i++) {
1965 _objc_read_classes_from_image(hList[i]);
1966 }
1967
1968 // Read categories from all images.
1969 // But not if any other threads are running - they might
1970 // call a category method before the fixups below are complete.
1971 if (!_is_threaded()) {
1972 BOOL needFlush = NO;
1973 for (i = 0; i < hCount; i++) {
1974 needFlush |= _objc_read_categories_from_image(hList[i]);
1975 }
1976 if (needFlush) flush_marked_caches();
1977 categoriesLoaded = YES;
1978 }
1979
1980 // Connect classes from all images.
1981 for (i = 0; i < hCount; i++) {
1982 _objc_connect_classes_from_image(hList[i]);
1983 }
1984
1985 // Fix up class refs, selector refs, and protocol objects from all images.
1986 for (i = 0; i < hCount; i++) {
1987 _objc_map_class_refs_for_image(hList[i]);
1988 _objc_fixup_selector_refs(hList[i]);
1989 _objc_fixup_protocol_objects_for_image(hList[i]);
1990 }
1991
1992 // Read categories from all images.
1993 // But not if this is the only thread - it's more
1994 // efficient to attach categories earlier if safe.
1995 if (!categoriesLoaded) {
1996 BOOL needFlush = NO;
1997 for (i = 0; i < hCount; i++) {
1998 needFlush |= _objc_read_categories_from_image(hList[i]);
1999 }
2000 if (needFlush) flush_marked_caches();
2001 }
2002
2003 // Multi-threaded category load MUST BE LAST to avoid a race.
2004 }
2005
2006
2007 /***********************************************************************
2008 * prepare_load_methods
2009 * Schedule +load for classes in this image, any un-+load-ed
2010 * superclasses in other images, and any categories in this image.
2011 **********************************************************************/
2012 // Recursively schedule +load for cls and any un-+load-ed superclasses.
2013 // cls must already be connected.
2014 static void schedule_class_load(struct old_class *cls)
2015 {
2016 if (cls->info & CLS_LOADED) return;
2017 if (cls->super_class) schedule_class_load(cls->super_class);
2018 add_class_to_loadable_list((Class)cls);
2019 cls->info |= CLS_LOADED;
2020 }
2021
2022 __private_extern__ void prepare_load_methods(header_info *hi)
2023 {
2024 Module mods;
2025 unsigned int midx;
2026
2027
2028 if (_objcHeaderIsReplacement(hi)) {
2029 // Ignore any classes in this image
2030 return;
2031 }
2032
2033 // Major loop - process all modules in the image
2034 mods = hi->mod_ptr;
2035 for (midx = 0; midx < hi->mod_count; midx += 1)
2036 {
2037 unsigned int index;
2038
2039 // Skip module containing no classes
2040 if (mods[midx].symtab == NULL)
2041 continue;
2042
2043 // Minor loop - process all the classes in given module
2044 for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
2045 {
2046 // Locate the class description pointer
2047 struct old_class *cls = mods[midx].symtab->defs[index];
2048 if (cls->info & CLS_CONNECTED) {
2049 schedule_class_load(cls);
2050 }
2051 }
2052 }
2053
2054
2055 // Major loop - process all modules in the header
2056 mods = hi->mod_ptr;
2057
2058 // NOTE: The module and category lists are traversed backwards
2059 // to preserve the pre-10.4 processing order. Changing the order
2060 // would have a small chance of introducing binary compatibility bugs.
2061 midx = (unsigned int)hi->mod_count;
2062 while (midx-- > 0) {
2063 unsigned int index;
2064 unsigned int total;
2065 Symtab symtab = mods[midx].symtab;
2066
2067 // Nothing to do for a module without a symbol table
2068 if (mods[midx].symtab == NULL)
2069 continue;
2070 // Total entries in symbol table (class entries followed
2071 // by category entries)
2072 total = mods[midx].symtab->cls_def_cnt +
2073 mods[midx].symtab->cat_def_cnt;
2074
2075 // Minor loop - register all categories from given module
2076 index = total;
2077 while (index-- > mods[midx].symtab->cls_def_cnt) {
2078 struct old_category *cat = symtab->defs[index];
2079 add_category_to_loadable_list((Category)cat);
2080 }
2081 }
2082 }
2083
2084
2085 #if TARGET_OS_WIN32
2086
2087 __private_extern__ void unload_class(struct old_class *cls)
2088 {
2089 }
2090
2091 #else
2092
2093 /***********************************************************************
2094 * _objc_remove_classes_in_image
2095 * Remove all classes in the given image from the runtime, because
2096 * the image is about to be unloaded.
2097 * Things to clean up:
2098 * class_hash
2099 * unconnected_class_hash
2100 * pending subclasses list (only if class is still unconnected)
2101 * loadable class list
2102 * class's method caches
2103 * class refs in all other images
2104 **********************************************************************/
2105 // Re-pend any class references in refs that point into [start..end)
2106 static void rependClassReferences(struct old_class **refs, size_t count,
2107 uintptr_t start, uintptr_t end)
2108 {
2109 size_t i;
2110
2111 if (!refs) return;
2112
2113 // Process each class ref
2114 for (i = 0; i < count; i++) {
2115 if ((uintptr_t)(refs[i]) >= start && (uintptr_t)(refs[i]) < end) {
2116 pendClassReference(&refs[i], refs[i]->name,
2117 (refs[i]->info & CLS_META) ? YES : NO);
2118 refs[i] = (struct old_class *)_class_getNonexistentObjectClass();
2119 }
2120 }
2121 }
2122
2123
2124 static void try_free(const void *p)
2125 {
2126 if (p && malloc_size(p)) free((void *)p);
2127 }
2128
2129 // Deallocate all memory in a method list
2130 static void unload_mlist(struct old_method_list *mlist)
2131 {
2132 int i;
2133 for (i = 0; i < mlist->method_count; i++) {
2134 try_free(mlist->method_list[i].method_types);
2135 }
2136 try_free(mlist);
2137 }
2138
2139 // Deallocate all memory in a class.
2140 __private_extern__ void unload_class(struct old_class *cls)
2141 {
2142 // Free method cache
2143 // This dereferences the cache contents; do this before freeing methods
2144 if (cls->cache && cls->cache != &_objc_empty_cache) {
2145 _cache_free(cls->cache);
2146 }
2147
2148 // Free ivar lists
2149 if (cls->ivars) {
2150 int i;
2151 for (i = 0; i < cls->ivars->ivar_count; i++) {
2152 try_free(cls->ivars->ivar_list[i].ivar_name);
2153 try_free(cls->ivars->ivar_list[i].ivar_type);
2154 }
2155 try_free(cls->ivars);
2156 }
2157
2158 // Free fixed-up method lists and method list array
2159 if (cls->methodLists) {
2160 // more than zero method lists
2161 if (cls->info & CLS_NO_METHOD_ARRAY) {
2162 // one method list
2163 unload_mlist((struct old_method_list *)cls->methodLists);
2164 }
2165 else {
2166 // more than one method list
2167 struct old_method_list **mlistp;
2168 for (mlistp = cls->methodLists;
2169 *mlistp != NULL && *mlistp != END_OF_METHODS_LIST;
2170 mlistp++)
2171 {
2172 unload_mlist(*mlistp);
2173 }
2174 free(cls->methodLists);
2175 }
2176 }
2177
2178 // Free protocol list
2179 struct old_protocol_list *protos = cls->protocols;
2180 while (protos) {
2181 struct old_protocol_list *dead = protos;
2182 protos = protos->next;
2183 try_free(dead);
2184 }
2185
2186 if ((cls->info & CLS_EXT)) {
2187 if (cls->ext) {
2188 // Free property lists and property list array
2189 if (cls->ext->propertyLists) {
2190 // more than zero property lists
2191 if (cls->info & CLS_NO_PROPERTY_ARRAY) {
2192 // one property list
2193 try_free(cls->ext->propertyLists);
2194 } else {
2195 // more than one property list
2196 struct objc_property_list **plistp;
2197 for (plistp = cls->ext->propertyLists;
2198 *plistp != NULL;
2199 plistp++)
2200 {
2201 try_free(*plistp);
2202 }
2203 try_free(cls->ext->propertyLists);
2204 }
2205 }
2206
2207 // Free weak ivar layout
2208 try_free(cls->ext->weak_ivar_layout);
2209
2210 // Free ext
2211 try_free(cls->ext);
2212 }
2213
2214 // Free non-weak ivar layout
2215 try_free(cls->ivar_layout);
2216 }
2217
2218 // Free class name
2219 try_free(cls->name);
2220
2221 // Free cls
2222 try_free(cls);
2223 }
2224
2225
2226 static void _objc_remove_classes_in_image(header_info *hi)
2227 {
2228 unsigned int index;
2229 unsigned int midx;
2230 Module mods;
2231
2232 mutex_lock(&classLock);
2233
2234 // Major loop - process all modules in the image
2235 mods = hi->mod_ptr;
2236 for (midx = 0; midx < hi->mod_count; midx += 1)
2237 {
2238 // Skip module containing no classes
2239 if (mods[midx].symtab == NULL)
2240 continue;
2241
2242 // Minor loop - process all the classes in given module
2243 for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
2244 {
2245 struct old_class *cls;
2246
2247 // Locate the class description pointer
2248 cls = mods[midx].symtab->defs[index];
2249
2250 // Remove from loadable class list, if present
2251 remove_class_from_loadable_list((Class)cls);
2252
2253 // Remove from unconnected_class_hash and pending subclasses
2254 if (unconnected_class_hash && NXHashMember(unconnected_class_hash, cls)) {
2255 NXHashRemove(unconnected_class_hash, cls);
2256 if (pendingSubclassesMap) {
2257 // Find this class in its superclass's pending list
2258 char *supercls_name = (char *)cls->super_class;
2259 PendingSubclass *pending =
2260 NXMapGet(pendingSubclassesMap, supercls_name);
2261 for ( ; pending != NULL; pending = pending->next) {
2262 if (pending->subclass == cls) {
2263 pending->subclass = Nil;
2264 break;
2265 }
2266 }
2267 }
2268 }
2269
2270 // Remove from class_hash
2271 NXHashRemove(class_hash, cls);
2272 objc_removeRegisteredClass((Class)cls);
2273
2274 // Free heap memory pointed to by the class
2275 unload_class(cls->isa);
2276 unload_class(cls);
2277 }
2278 }
2279
2280
2281 // Search all other images for class refs that point back to this range.
2282 // Un-fix and re-pend any such class refs.
2283
2284 // Get the location of the dying image's __OBJC segment
2285 uintptr_t seg = hi->os.objcSegmentHeader->vmaddr + hi->os.image_slide;
2286 size_t seg_size = hi->os.objcSegmentHeader->filesize;
2287
2288 header_info *other_hi;
2289 for (other_hi = FirstHeader; other_hi != NULL; other_hi = other_hi->next) {
2290 struct old_class **other_refs;
2291 size_t count;
2292 if (other_hi == hi) continue; // skip the image being unloaded
2293
2294 // Fix class refs in the other image
2295 other_refs = _getObjcClassRefs(other_hi, &count);
2296 rependClassReferences(other_refs, count, seg, seg+seg_size);
2297 }
2298
2299 mutex_unlock(&classLock);
2300 }
2301
2302
2303 /***********************************************************************
2304 * _objc_remove_categories_in_image
2305 * Remove all categories in the given image from the runtime, because
2306 * the image is about to be unloaded.
2307 * Things to clean up:
2308 * unresolved category list
2309 * loadable category list
2310 **********************************************************************/
2311 static void _objc_remove_categories_in_image(header_info *hi)
2312 {
2313 Module mods;
2314 unsigned int midx;
2315
2316 // Major loop - process all modules in the header
2317 mods = hi->mod_ptr;
2318
2319 for (midx = 0; midx < hi->mod_count; midx++) {
2320 unsigned int index;
2321 unsigned int total;
2322 Symtab symtab = mods[midx].symtab;
2323
2324 // Nothing to do for a module without a symbol table
2325 if (symtab == NULL) continue;
2326
2327 // Total entries in symbol table (class entries followed
2328 // by category entries)
2329 total = symtab->cls_def_cnt + symtab->cat_def_cnt;
2330
2331 // Minor loop - check all categories from given module
2332 for (index = symtab->cls_def_cnt; index < total; index++) {
2333 struct old_category *cat = symtab->defs[index];
2334
2335 // Clean up loadable category list
2336 remove_category_from_loadable_list((Category)cat);
2337
2338 // Clean up category_hash
2339 if (category_hash) {
2340 _objc_unresolved_category *cat_entry =
2341 NXMapGet(category_hash, cat->class_name);
2342 for ( ; cat_entry != NULL; cat_entry = cat_entry->next) {
2343 if (cat_entry->cat == cat) {
2344 cat_entry->cat = NULL;
2345 break;
2346 }
2347 }
2348 }
2349 }
2350 }
2351 }
2352
2353
2354 /***********************************************************************
2355 * unload_paranoia
2356 * Various paranoid debugging checks that look for poorly-behaving
2357 * unloadable bundles.
2358 * Called by _objc_unmap_image when OBJC_UNLOAD_DEBUG is set.
2359 **********************************************************************/
2360 static void unload_paranoia(header_info *hi)
2361 {
2362 // Get the location of the dying image's __OBJC segment
2363 uintptr_t seg = hi->os.objcSegmentHeader->vmaddr + hi->os.image_slide;
2364 size_t seg_size = hi->os.objcSegmentHeader->filesize;
2365
2366 _objc_inform("UNLOAD DEBUG: unloading image '%s' [%p..%p]",
2367 _nameForHeader(hi->mhdr), (void *)seg, (void*)(seg+seg_size));
2368
2369 mutex_lock(&classLock);
2370
2371 // Make sure the image contains no categories on surviving classes.
2372 {
2373 Module mods;
2374 unsigned int midx;
2375
2376 // Major loop - process all modules in the header
2377 mods = hi->mod_ptr;
2378
2379 for (midx = 0; midx < hi->mod_count; midx++) {
2380 unsigned int index;
2381 unsigned int total;
2382 Symtab symtab = mods[midx].symtab;
2383
2384 // Nothing to do for a module without a symbol table
2385 if (symtab == NULL) continue;
2386
2387 // Total entries in symbol table (class entries followed
2388 // by category entries)
2389 total = symtab->cls_def_cnt + symtab->cat_def_cnt;
2390
2391 // Minor loop - check all categories from given module
2392 for (index = symtab->cls_def_cnt; index < total; index++) {
2393 struct old_category *cat = symtab->defs[index];
2394 struct old_class query;
2395
2396 query.name = cat->class_name;
2397 if (NXHashMember(class_hash, &query)) {
2398 _objc_inform("UNLOAD DEBUG: dying image contains category '%s(%s)' on surviving class '%s'!", cat->class_name, cat->category_name, cat->class_name);
2399 }
2400 }
2401 }
2402 }
2403
2404 // Make sure no surviving class is in the dying image.
2405 // Make sure no surviving class has a superclass in the dying image.
2406 // fixme check method implementations too
2407 {
2408 struct old_class *cls;
2409 NXHashState state;
2410
2411 state = NXInitHashState(class_hash);
2412 while (NXNextHashState(class_hash, &state, (void **)&cls)) {
2413 if ((vm_address_t)cls >= seg &&
2414 (vm_address_t)cls < seg+seg_size)
2415 {
2416 _objc_inform("UNLOAD DEBUG: dying image contains surviving class '%s'!", cls->name);
2417 }
2418
2419 if ((vm_address_t)cls->super_class >= seg &&
2420 (vm_address_t)cls->super_class < seg+seg_size)
2421 {
2422 _objc_inform("UNLOAD DEBUG: dying image contains superclass '%s' of surviving class '%s'!", cls->super_class->name, cls->name);
2423 }
2424 }
2425 }
2426
2427 mutex_unlock(&classLock);
2428 }
2429
2430
2431 /***********************************************************************
2432 * _unload_image
2433 * Only handles MH_BUNDLE for now.
2434 * Locking: loadMethodLock acquired by unmap_image
2435 **********************************************************************/
2436 __private_extern__ void _unload_image(header_info *hi)
2437 {
2438 recursive_mutex_assert_locked(&loadMethodLock);
2439
2440 // Cleanup:
2441 // Remove image's classes from the class list and free auxiliary data.
2442 // Remove image's unresolved or loadable categories and free auxiliary data
2443 // Remove image's unresolved class refs.
2444 _objc_remove_classes_in_image(hi);
2445 _objc_remove_categories_in_image(hi);
2446 _objc_remove_pending_class_refs_in_image(hi);
2447
2448 // Perform various debugging checks if requested.
2449 if (DebugUnload) unload_paranoia(hi);
2450 }
2451
2452 #endif
2453
2454
2455 /***********************************************************************
2456 * objc_addClass. Add the specified class to the table of known classes,
2457 * after doing a little verification and fixup.
2458 **********************************************************************/
2459 void objc_addClass (Class cls_gen)
2460 {
2461 struct old_class *cls = _class_asOld(cls_gen);
2462
2463 OBJC_WARN_DEPRECATED;
2464
2465 // Synchronize access to hash table
2466 mutex_lock (&classLock);
2467
2468 // Make sure both the class and the metaclass have caches!
2469 // Clear all bits of the info fields except CLS_CLASS and CLS_META.
2470 // Normally these bits are already clear but if someone tries to cons
2471 // up their own class on the fly they might need to be cleared.
2472 if (cls->cache == NULL) {
2473 cls->cache = (Cache) &_objc_empty_cache;
2474 cls->info = CLS_CLASS;
2475 }
2476
2477 if (cls->isa->cache == NULL) {
2478 cls->isa->cache = (Cache) &_objc_empty_cache;
2479 cls->isa->info = CLS_META;
2480 }
2481
2482 // methodLists should be:
2483 // 1. NULL (Tiger and later only)
2484 // 2. A -1 terminated method list array
2485 // In either case, CLS_NO_METHOD_ARRAY remains clear.
2486 // If the user manipulates the method list directly,
2487 // they must use the magic private format.
2488
2489 // Add the class to the table
2490 (void) NXHashInsert (class_hash, cls);
2491 objc_addRegisteredClass((Class)cls);
2492
2493 // Superclass is no longer a leaf for cache flushing
2494 if (cls->super_class && (cls->super_class->info & CLS_LEAF)) {
2495 _class_clearInfo((Class)cls->super_class, CLS_LEAF);
2496 _class_clearInfo((Class)cls->super_class->isa, CLS_LEAF);
2497 }
2498
2499 // Desynchronize
2500 mutex_unlock (&classLock);
2501 }
2502
2503 /***********************************************************************
2504 * _objcTweakMethodListPointerForClass.
2505 * Change the class's method list pointer to a method list array.
2506 * Does nothing if the method list pointer is already a method list array.
2507 * If the class is currently in use, methodListLock must be held by the caller.
2508 **********************************************************************/
2509 static void _objcTweakMethodListPointerForClass(struct old_class *cls)
2510 {
2511 struct old_method_list * originalList;
2512 const int initialEntries = 4;
2513 size_t mallocSize;
2514 struct old_method_list ** ptr;
2515
2516 // Do nothing if methodLists is already an array.
2517 if (cls->methodLists && !(cls->info & CLS_NO_METHOD_ARRAY)) return;
2518
2519 // Remember existing list
2520 originalList = (struct old_method_list *) cls->methodLists;
2521
2522 // Allocate and zero a method list array
2523 mallocSize = sizeof(struct old_method_list *) * initialEntries;
2524 ptr = (struct old_method_list **) _calloc_internal(1, mallocSize);
2525
2526 // Insert the existing list into the array
2527 ptr[initialEntries - 1] = END_OF_METHODS_LIST;
2528 ptr[0] = originalList;
2529
2530 // Replace existing list with array
2531 cls->methodLists = ptr;
2532 _class_clearInfo((Class)cls, CLS_NO_METHOD_ARRAY);
2533 }
2534
2535
2536 /***********************************************************************
2537 * _objc_insertMethods.
2538 * Adds methods to a class.
2539 * Does not flush any method caches.
2540 * Does not take any locks.
2541 * If the class is already in use, use class_addMethods() instead.
2542 **********************************************************************/
2543 __private_extern__ void _objc_insertMethods(struct old_class *cls,
2544 struct old_method_list *mlist,
2545 struct old_category *cat)
2546 {
2547 struct old_method_list ***list;
2548 struct old_method_list **ptr;
2549 ptrdiff_t endIndex;
2550 size_t oldSize;
2551 size_t newSize;
2552
2553 if (!cls->methodLists) {
2554 // cls has no methods - simply use this method list
2555 cls->methodLists = (struct old_method_list **)mlist;
2556 _class_setInfo((Class)cls, CLS_NO_METHOD_ARRAY);
2557 return;
2558 }
2559
2560 // Log any existing methods being replaced
2561 if (PrintReplacedMethods) {
2562 int i;
2563 for (i = 0; i < mlist->method_count; i++) {
2564 extern IMP findIMPInClass(struct old_class *cls, SEL sel);
2565 SEL sel = sel_registerName((char *)mlist->method_list[i].method_name);
2566 IMP newImp = mlist->method_list[i].method_imp;
2567 IMP oldImp;
2568
2569 if ((oldImp = findIMPInClass(cls, sel))) {
2570 logReplacedMethod(cls->name, sel, ISMETA(cls),
2571 cat ? cat->category_name : NULL,
2572 oldImp, newImp);
2573 }
2574 }
2575 }
2576
2577 // Create method list array if necessary
2578 _objcTweakMethodListPointerForClass(cls);
2579
2580 list = &cls->methodLists;
2581
2582 // Locate unused entry for insertion point
2583 ptr = *list;
2584 while ((*ptr != 0) && (*ptr != END_OF_METHODS_LIST))
2585 ptr += 1;
2586
2587 // If array is full, add to it
2588 if (*ptr == END_OF_METHODS_LIST)
2589 {
2590 // Calculate old and new dimensions
2591 endIndex = ptr - *list;
2592 oldSize = (endIndex + 1) * sizeof(void *);
2593 newSize = oldSize + sizeof(struct old_method_list *); // only increase by 1
2594
2595 // Grow the method list array by one.
2596 // This block may be from user code; don't use _realloc_internal
2597 *list = (struct old_method_list **)realloc(*list, newSize);
2598
2599 // Zero out addition part of new array
2600 bzero (&((*list)[endIndex]), newSize - oldSize);
2601
2602 // Place new end marker
2603 (*list)[(newSize/sizeof(void *)) - 1] = END_OF_METHODS_LIST;
2604
2605 // Insertion point corresponds to old array end
2606 ptr = &((*list)[endIndex]);
2607 }
2608
2609 // Right shift existing entries by one
2610 bcopy (*list, (*list) + 1, (uint8_t *)ptr - (uint8_t *)*list);
2611
2612 // Insert at method list at beginning of array
2613 **list = mlist;
2614 }
2615
2616 /***********************************************************************
2617 * _objc_removeMethods.
2618 * Remove methods from a class.
2619 * Does not take any locks.
2620 * Does not flush any method caches.
2621 * If the class is currently in use, use class_removeMethods() instead.
2622 **********************************************************************/
2623 __private_extern__ void _objc_removeMethods(struct old_class *cls,
2624 struct old_method_list *mlist)
2625 {
2626 struct old_method_list ***list;
2627 struct old_method_list **ptr;
2628
2629 if (cls->methodLists == NULL) {
2630 // cls has no methods
2631 return;
2632 }
2633 if (cls->methodLists == (struct old_method_list **)mlist) {
2634 // mlist is the class's only method list - erase it
2635 cls->methodLists = NULL;
2636 return;
2637 }
2638 if (cls->info & CLS_NO_METHOD_ARRAY) {
2639 // cls has only one method list, and this isn't it - do nothing
2640 return;
2641 }
2642
2643 // cls has a method list array - search it
2644
2645 list = &cls->methodLists;
2646
2647 // Locate list in the array
2648 ptr = *list;
2649 while (*ptr != mlist) {
2650 // fix for radar # 2538790
2651 if ( *ptr == END_OF_METHODS_LIST ) return;
2652 ptr += 1;
2653 }
2654
2655 // Remove this entry
2656 *ptr = 0;
2657
2658 // Left shift the following entries
2659 while (*(++ptr) != END_OF_METHODS_LIST)
2660 *(ptr-1) = *ptr;
2661 *(ptr-1) = 0;
2662 }
2663
2664 /***********************************************************************
2665 * _objc_add_category. Install the specified category's methods and
2666 * protocols into the class it augments.
2667 * The class is assumed not to be in use yet: no locks are taken and
2668 * no method caches are flushed.
2669 **********************************************************************/
2670 static inline void _objc_add_category(struct old_class *cls, struct old_category *category, int version)
2671 {
2672 if (PrintConnecting) {
2673 _objc_inform("CONNECT: attaching category '%s (%s)'", cls->name, category->category_name);
2674 }
2675
2676 // Augment instance methods
2677 if (category->instance_methods)
2678 _objc_insertMethods (cls, category->instance_methods, category);
2679
2680 // Augment class methods
2681 if (category->class_methods)
2682 _objc_insertMethods (cls->isa, category->class_methods, category);
2683
2684 // Augment protocols
2685 if ((version >= 5) && category->protocols)
2686 {
2687 if (cls->isa->version >= 5)
2688 {
2689 category->protocols->next = cls->protocols;
2690 cls->protocols = category->protocols;
2691 cls->isa->protocols = category->protocols;
2692 }
2693 else
2694 {
2695 _objc_inform ("unable to add protocols from category %s...\n", category->category_name);
2696 _objc_inform ("class `%s' must be recompiled\n", category->class_name);
2697 }
2698 }
2699
2700 // Augment properties
2701 if (version >= 7 && category->instance_properties) {
2702 if (cls->isa->version >= 6) {
2703 _class_addProperties(cls, category->instance_properties);
2704 } else {
2705 _objc_inform ("unable to add properties from category %s...\n", category->category_name);
2706 _objc_inform ("class `%s' must be recompiled\n", category->class_name);
2707 }
2708 }
2709 }
2710
2711 /***********************************************************************
2712 * _objc_add_category_flush_caches. Install the specified category's
2713 * methods into the class it augments, and flush the class' method cache.
2714 * Return YES if some method caches now need to be flushed.
2715 **********************************************************************/
2716 static BOOL _objc_add_category_flush_caches(struct old_class *cls, struct old_category *category, int version)
2717 {
2718 BOOL needFlush = NO;
2719
2720 // Install the category's methods into its intended class
2721 mutex_lock(&methodListLock);
2722 _objc_add_category (cls, category, version);
2723 mutex_unlock(&methodListLock);
2724
2725 // Queue for cache flushing so category's methods can get called
2726 if (category->instance_methods) {
2727 _class_setInfo((Class)cls, CLS_FLUSH_CACHE);
2728 needFlush = YES;
2729 }
2730 if (category->class_methods) {
2731 _class_setInfo((Class)cls->isa, CLS_FLUSH_CACHE);
2732 needFlush = YES;
2733 }
2734
2735 return needFlush;
2736 }
2737
2738
2739 /***********************************************************************
2740 * reverse_cat
2741 * Reverse the given linked list of pending categories.
2742 * The pending category list is built backwards, and needs to be
2743 * reversed before actually attaching the categories to a class.
2744 * Returns the head of the new linked list.
2745 **********************************************************************/
2746 static _objc_unresolved_category *reverse_cat(_objc_unresolved_category *cat)
2747 {
2748 _objc_unresolved_category *prev;
2749 _objc_unresolved_category *cur;
2750 _objc_unresolved_category *ahead;
2751
2752 if (!cat) return NULL;
2753
2754 prev = NULL;
2755 cur = cat;
2756 ahead = cat->next;
2757
2758 while (cur) {
2759 ahead = cur->next;
2760 cur->next = prev;
2761 prev = cur;
2762 cur = ahead;
2763 }
2764
2765 return prev;
2766 }
2767
2768
2769 /***********************************************************************
2770 * resolve_categories_for_class.
2771 * Install all existing categories intended for the specified class.
2772 * cls must be a true class and not a metaclass.
2773 **********************************************************************/
2774 static void resolve_categories_for_class(struct old_class *cls)
2775 {
2776 _objc_unresolved_category * pending;
2777 _objc_unresolved_category * next;
2778
2779 // Nothing to do if there are no categories at all
2780 if (!category_hash) return;
2781
2782 // Locate and remove first element in category list
2783 // associated with this class
2784 pending = NXMapKeyFreeingRemove (category_hash, cls->name);
2785
2786 // Traverse the list of categories, if any, registered for this class
2787
2788 // The pending list is built backwards. Reverse it and walk forwards.
2789 pending = reverse_cat(pending);
2790
2791 while (pending) {
2792 if (pending->cat) {
2793 // Install the category
2794 // use the non-flush-cache version since we are only
2795 // called from the class intialization code
2796 _objc_add_category(cls, pending->cat, (int)pending->version);
2797 }
2798
2799 // Delink and reclaim this registration
2800 next = pending->next;
2801 _free_internal(pending);
2802 pending = next;
2803 }
2804 }
2805
2806
2807 /***********************************************************************
2808 * _objc_resolve_categories_for_class.
2809 * Public version of resolve_categories_for_class. This was
2810 * exported pre-10.4 for Omni et al. to workaround a problem
2811 * with too-lazy category attachment.
2812 * cls should be a class, but this function can also cope with metaclasses.
2813 **********************************************************************/
2814 void _objc_resolve_categories_for_class(Class cls_gen)
2815 {
2816 struct old_class *cls = _class_asOld(cls_gen);
2817
2818 // If cls is a metaclass, get the class.
2819 // resolve_categories_for_class() requires a real class to work correctly.
2820 if (ISMETA(cls)) {
2821 if (strncmp(cls->name, "_%", 2) == 0) {
2822 // Posee's meta's name is smashed and isn't in the class_hash,
2823 // so objc_getClass doesn't work.
2824 const char *baseName = strchr(cls->name, '%'); // get posee's real name
2825 cls = _class_asOld((Class)objc_getClass(baseName));
2826 } else {
2827 cls = _class_asOld((Class)objc_getClass(cls->name));
2828 }
2829 }
2830
2831 resolve_categories_for_class(cls);
2832 }
2833
2834
2835 /***********************************************************************
2836 * _objc_register_category.
2837 * Process a category read from an image.
2838 * If the category's class exists, attach the category immediately.
2839 * Classes that need cache flushing are marked but not flushed.
2840 * If the category's class does not exist yet, pend the category for
2841 * later attachment. Pending categories are attached in the order
2842 * they were discovered.
2843 * Returns YES if some method caches now need to be flushed.
2844 **********************************************************************/
2845 static BOOL _objc_register_category(struct old_category *cat, int version)
2846 {
2847 _objc_unresolved_category * new_cat;
2848 _objc_unresolved_category * old;
2849 struct old_class *theClass;
2850
2851 // If the category's class exists, attach the category.
2852 if ((theClass = _class_asOld((Class)objc_lookUpClass(cat->class_name)))) {
2853 return _objc_add_category_flush_caches(theClass, cat, version);
2854 }
2855
2856 // If the category's class exists but is unconnected,
2857 // then attach the category to the class but don't bother
2858 // flushing any method caches (because they must be empty).
2859 // YES unconnected, NO class_handler
2860 if ((theClass = _class_asOld((Class)look_up_class(cat->class_name, YES, NO)))) {
2861 _objc_add_category(theClass, cat, version);
2862 return NO;
2863 }
2864
2865
2866 // Category's class does not exist yet.
2867 // Save the category for later attachment.
2868
2869 if (PrintConnecting) {
2870 _objc_inform("CONNECT: pending category '%s (%s)'", cat->class_name, cat->category_name);
2871 }
2872
2873 // Create category lookup table if needed
2874 if (!category_hash)
2875 category_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype,
2876 128,
2877 _objc_internal_zone ());
2878
2879 // Locate an existing list of categories, if any, for the class.
2880 old = NXMapGet (category_hash, cat->class_name);
2881
2882 // Register the category to be fixed up later.
2883 // The category list is built backwards, and is reversed again
2884 // by resolve_categories_for_class().
2885 new_cat = _malloc_internal(sizeof(_objc_unresolved_category));
2886 new_cat->next = old;
2887 new_cat->cat = cat;
2888 new_cat->version = version;
2889 (void) NXMapKeyCopyingInsert (category_hash, cat->class_name, new_cat);
2890
2891 return NO;
2892 }
2893
2894
2895 __private_extern__ const char **
2896 _objc_copyClassNamesForImage(header_info *hi, unsigned int *outCount)
2897 {
2898 Module mods;
2899 unsigned int m;
2900 const char **list;
2901 int count;
2902 int allocated;
2903
2904 list = NULL;
2905 count = 0;
2906 allocated = 0;
2907
2908 mods = hi->mod_ptr;
2909 for (m = 0; m < hi->mod_count; m++) {
2910 int d;
2911
2912 if (!mods[m].symtab) continue;
2913
2914 for (d = 0; d < mods[m].symtab->cls_def_cnt; d++) {
2915 struct old_class *cls = mods[m].symtab->defs[d];
2916 // fixme what about future-ified classes?
2917 if (class_is_connected(cls)) {
2918 if (count == allocated) {
2919 allocated = allocated*2 + 16;
2920 list = (const char **)
2921 realloc((void *)list, allocated * sizeof(char *));
2922 }
2923 list[count++] = cls->name;
2924 }
2925 }
2926 }
2927
2928 if (count > 0) {
2929 // NULL-terminate non-empty list
2930 if (count == allocated) {
2931 allocated = allocated+1;
2932 list = (const char **)
2933 realloc((void *)list, allocated * sizeof(char *));
2934 }
2935 list[count] = NULL;
2936 }
2937
2938 if (outCount) *outCount = count;
2939 return list;
2940 }
2941
2942 BOOL gdb_objc_isRuntimeLocked()
2943 {
2944 if (mutex_try_lock(&methodListLock)) {
2945 mutex_unlock(&methodListLock);
2946 } else
2947 return YES;
2948
2949 if (mutex_try_lock(&classLock)) {
2950 mutex_unlock(&classLock);
2951 } else
2952 return YES;
2953
2954 if (mutex_try_lock(&cacheUpdateLock)) {
2955 mutex_unlock(&cacheUpdateLock);
2956 } else
2957 return YES;
2958
2959 return NO;
2960 }
2961
2962
2963 /***********************************************************************
2964 * Lock management
2965 * Every lock used anywhere must be managed here.
2966 * Locks not managed here may cause gdb deadlocks.
2967 **********************************************************************/
2968 __private_extern__ rwlock_t selLock = {0};
2969 __private_extern__ mutex_t classLock = MUTEX_INITIALIZER;
2970 __private_extern__ mutex_t methodListLock = MUTEX_INITIALIZER;
2971 __private_extern__ mutex_t cacheUpdateLock = MUTEX_INITIALIZER;
2972 __private_extern__ recursive_mutex_t loadMethodLock = RECURSIVE_MUTEX_INITIALIZER;
2973 static int debugger_selLock;
2974 static int debugger_loadMethodLock;
2975 #define RDONLY 1
2976 #define RDWR 2
2977
2978 __private_extern__ void lock_init(void)
2979 {
2980 rwlock_init(&selLock);
2981 recursive_mutex_init(&loadMethodLock);
2982 }
2983
2984
2985 #ifndef NO_DEBUGGER_MODE
2986
2987 /***********************************************************************
2988 * startDebuggerMode
2989 * Attempt to acquire some locks for debugger mode.
2990 * Returns 0 if debugger mode failed because too many locks are unavailable.
2991 *
2992 * Locks successfully acquired are held until endDebuggerMode().
2993 * Locks not acquired are off-limits until endDebuggerMode(); any
2994 * attempt to manipulate them will cause a trap.
2995 * Locks not handled here may cause deadlocks in gdb.
2996 **********************************************************************/
2997 __private_extern__ int startDebuggerMode(void)
2998 {
2999 int result = DEBUGGER_FULL;
3000
3001 // classLock is required
3002 // methodListLock is required
3003 // cacheUpdateLock is required
3004 // fixme might be able to allow all-or-none
3005 if (! mutex_try_lock(&classLock)) {
3006 return DEBUGGER_OFF;
3007 }
3008 if (! mutex_try_lock(&methodListLock)) {
3009 mutex_unlock(&classLock);
3010 return DEBUGGER_OFF;
3011 }
3012 if (! mutex_try_lock(&cacheUpdateLock)) {
3013 mutex_unlock(&methodListLock);
3014 mutex_unlock(&classLock);
3015 return DEBUGGER_OFF;
3016 }
3017
3018 // selLock is optional
3019 if (rwlock_try_write(&selLock)) {
3020 debugger_selLock = RDWR;
3021 } else if (rwlock_try_read(&selLock)) {
3022 debugger_selLock = RDONLY;
3023 result = DEBUGGER_PARTIAL;
3024 } else {
3025 debugger_selLock = 0;
3026 result = DEBUGGER_PARTIAL;
3027 }
3028
3029 // loadMethodLock is optional
3030 if (recursive_mutex_try_lock(&loadMethodLock)) {
3031 debugger_loadMethodLock = RDWR;
3032 } else {
3033 debugger_loadMethodLock = 0;
3034 result = DEBUGGER_PARTIAL;
3035 }
3036
3037 return result;
3038 }
3039
3040 /***********************************************************************
3041 * endDebuggerMode
3042 * Relinquish locks acquired in startDebuggerMode().
3043 **********************************************************************/
3044 __private_extern__ void endDebuggerMode(void)
3045 {
3046 if (debugger_loadMethodLock) {
3047 recursive_mutex_unlock(&loadMethodLock);
3048 debugger_loadMethodLock = 0;
3049 }
3050 rwlock_unlock(&selLock, debugger_selLock);
3051 debugger_selLock = 0;
3052 mutex_unlock(&classLock);
3053 mutex_unlock(&methodListLock);
3054 mutex_unlock(&cacheUpdateLock);
3055 }
3056
3057 /***********************************************************************
3058 * isManagedDuringDebugger
3059 * Returns YES if the given lock is handled specially during debugger
3060 * mode (i.e. debugger mode tries to acquire it).
3061 **********************************************************************/
3062 __private_extern__ BOOL isManagedDuringDebugger(void *lock)
3063 {
3064 if (lock == &selLock) return YES;
3065 if (lock == &classLock) return YES;
3066 if (lock == &methodListLock) return YES;
3067 if (lock == &cacheUpdateLock) return YES;
3068 if (lock == &loadMethodLock) return YES;
3069 return NO;
3070 }
3071
3072 /***********************************************************************
3073 * isLockedDuringDebugger
3074 * Returns YES if the given mutex was acquired by debugger mode.
3075 * Locking a managed mutex during debugger mode causes a trap unless
3076 * this returns YES.
3077 **********************************************************************/
3078 __private_extern__ BOOL isLockedDuringDebugger(mutex_t *lock)
3079 {
3080 assert(DebuggerMode);
3081
3082 if (lock == &classLock) return YES;
3083 if (lock == &methodListLock) return YES;
3084 if (lock == &cacheUpdateLock) return YES;
3085 if (lock == (mutex_t *)&loadMethodLock) return YES;
3086
3087 return NO;
3088 }
3089
3090 /***********************************************************************
3091 * isReadingDuringDebugger
3092 * Returns YES if the given rwlock was read-locked by debugger mode.
3093 * Read-locking a managed rwlock during debugger mode causes a trap unless
3094 * this returns YES.
3095 **********************************************************************/
3096 __private_extern__ BOOL isReadingDuringDebugger(rwlock_t *lock)
3097 {
3098 assert(DebuggerMode);
3099
3100 // read-lock is allowed even if debugger mode actually write-locked it
3101 if (debugger_selLock && lock == &selLock) return YES;
3102
3103 return NO;
3104 }
3105
3106 /***********************************************************************
3107 * isWritingDuringDebugger
3108 * Returns YES if the given rwlock was write-locked by debugger mode.
3109 * Write-locking a managed rwlock during debugger mode causes a trap unless
3110 * this returns YES.
3111 **********************************************************************/
3112 __private_extern__ BOOL isWritingDuringDebugger(rwlock_t *lock)
3113 {
3114 assert(DebuggerMode);
3115
3116 if (debugger_selLock == RDWR && lock == &selLock) return YES;
3117
3118 return NO;
3119 }
3120
3121 // !defined(NO_DEBUGGER_MODE)
3122 #endif
3123
3124 #endif