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