2 * Copyright (c) 1999-2009 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 /***********************************************************************
26 * Support for old-ABI classes, methods, and categories.
27 **********************************************************************/
31 #include "objc-private.h"
32 #include "objc-runtime-old.h"
33 #include "objc-file-old.h"
34 #include "objc-cache-old.h"
36 static Method _class_getMethod(Class cls, SEL sel);
37 static Method _class_getMethodNoSuper(Class cls, SEL sel);
38 static Method _class_getMethodNoSuper_nolock(Class cls, SEL sel);
39 static Class _class_getNonMetaClass(Class cls, id obj);
40 static void flush_caches(Class cls, bool flush_meta);
43 // Freed objects have their isa set to point to this dummy class.
44 // This avoids the need to check for Nil classes in the messenger.
45 static const void* freedObjectClass[12] =
55 (Cache) &_objc_empty_cache, // cache
62 /***********************************************************************
63 * _class_getFreedObjectClass. Return a pointer to the dummy freed
64 * object class. Freed objects get their isa pointers replaced with
65 * a pointer to the freedObjectClass, so that we can catch usages of
67 **********************************************************************/
68 static Class _class_getFreedObjectClass(void)
70 return (Class)freedObjectClass;
74 /***********************************************************************
75 * _objc_getFreedObjectClass. Return a pointer to the dummy freed
76 * object class. Freed objects get their isa pointers replaced with
77 * a pointer to the freedObjectClass, so that we can catch usages of
79 **********************************************************************/
80 Class _objc_getFreedObjectClass(void)
82 return _class_getFreedObjectClass();
86 static void allocateExt(Class cls)
88 if (! (cls->info & CLS_EXT)) {
89 _objc_inform("class '%s' needs to be recompiled", cls->name);
93 uint32_t size = (uint32_t)sizeof(old_class_ext);
94 cls->ext = (old_class_ext *)calloc(size, 1);
95 cls->ext->size = size;
100 static inline old_method *_findNamedMethodInList(old_method_list * mlist, const char *meth_name) {
102 if (!mlist) return nil;
103 for (i = 0; i < mlist->method_count; i++) {
104 old_method *m = &mlist->method_list[i];
105 if (0 == strcmp((const char *)(m->method_name), meth_name)) {
113 /***********************************************************************
114 * Method list fixup markers.
115 * mlist->obsolete == fixed_up_method_list marks method lists with real SELs
116 * versus method lists with un-uniqued char*.
117 * PREOPTIMIZED VERSION:
118 * Fixed-up method lists get mlist->obsolete == OBJC_FIXED_UP
119 * dyld shared cache sets this for method lists it preoptimizes.
120 * UN-PREOPTIMIZED VERSION
121 * Fixed-up method lists get mlist->obsolete == OBJC_FIXED_UP_outside_dyld
122 * dyld shared cache uses OBJC_FIXED_UP, but those aren't trusted.
123 **********************************************************************/
124 #define OBJC_FIXED_UP ((void *)1771)
125 #define OBJC_FIXED_UP_outside_dyld ((void *)1773)
126 static void *fixed_up_method_list = OBJC_FIXED_UP;
128 // sel_init() decided that selectors in the dyld shared cache are untrustworthy
129 void disableSharedCacheOptimizations(void)
131 fixed_up_method_list = OBJC_FIXED_UP_outside_dyld;
134 /***********************************************************************
135 * fixupSelectorsInMethodList
136 * Uniques selectors in the given method list.
137 * The given method list must be non-nil and not already fixed-up.
138 * If the class was loaded from a bundle:
139 * fixes up the given list in place with heap-allocated selector strings
140 * If the class was not from a bundle:
141 * allocates a copy of the method list, fixes up the copy, and returns
142 * the copy. The given list is unmodified.
144 * If cls is already in use, methodListLock must be held by the caller.
145 **********************************************************************/
146 static old_method_list *fixupSelectorsInMethodList(Class cls, old_method_list *mlist)
151 old_method_list *old_mlist;
153 if ( ! mlist ) return nil;
154 if ( mlist->obsolete == fixed_up_method_list ) {
157 bool isBundle = cls->info & CLS_FROM_BUNDLE;
160 size = sizeof(old_method_list) - sizeof(old_method) + old_mlist->method_count * sizeof(old_method);
161 mlist = (old_method_list *)malloc(size);
162 memmove(mlist, old_mlist, size);
164 // Mach-O bundles are fixed up in place.
165 // This prevents leaks when a bundle is unloaded.
167 mutex_locker_t lock(selLock);
168 for ( i = 0; i < mlist->method_count; i += 1 ) {
169 method = &mlist->method_list[i];
170 method->method_name =
171 sel_registerNameNoLock((const char *)method->method_name, isBundle); // Always copy selector data from bundles.
173 mlist->obsolete = fixed_up_method_list;
179 /***********************************************************************
181 * Returns successive method lists from the given class.
182 * Method lists are returned in method search order (i.e. highest-priority
183 * implementations first).
184 * All necessary method list fixups are performed, so the
185 * returned method list is fully-constructed.
187 * If cls is already in use, methodListLock must be held by the caller.
188 * For full thread-safety, methodListLock must be continuously held by the
189 * caller across all calls to nextMethodList(). If the lock is released,
190 * the bad results listed in class_nextMethodList() may occur.
192 * void *iterator = nil;
193 * old_method_list *mlist;
194 * mutex_locker_t lock(methodListLock);
195 * while ((mlist = nextMethodList(cls, &iterator))) {
196 * // do something with mlist
198 **********************************************************************/
199 static old_method_list *nextMethodList(Class cls,
202 uintptr_t index = *(uintptr_t *)it;
203 old_method_list **resultp;
206 // First call to nextMethodList.
207 if (!cls->methodLists) {
209 } else if (cls->info & CLS_NO_METHOD_ARRAY) {
210 resultp = (old_method_list **)&cls->methodLists;
212 resultp = &cls->methodLists[0];
213 if (!*resultp || *resultp == END_OF_METHODS_LIST) {
218 // Subsequent call to nextMethodList.
219 if (!cls->methodLists) {
221 } else if (cls->info & CLS_NO_METHOD_ARRAY) {
224 resultp = &cls->methodLists[index];
225 if (!*resultp || *resultp == END_OF_METHODS_LIST) {
231 // resultp now is nil, meaning there are no more method lists,
232 // OR the address of the method list pointer to fix up and return.
236 *resultp = fixupSelectorsInMethodList(cls, *resultp);
238 *it = (void *)(index + 1);
247 /* These next three functions are the heart of ObjC method lookup.
248 * If the class is currently in use, methodListLock must be held by the caller.
250 static inline old_method *_findMethodInList(old_method_list * mlist, SEL sel) {
252 if (!mlist) return nil;
253 for (i = 0; i < mlist->method_count; i++) {
254 old_method *m = &mlist->method_list[i];
255 if (m->method_name == sel) {
262 static inline old_method * _findMethodInClass(Class cls, SEL sel) __attribute__((always_inline));
263 static inline old_method * _findMethodInClass(Class cls, SEL sel) {
264 // Flattened version of nextMethodList(). The optimizer doesn't
265 // do a good job with hoisting the conditionals out of the loop.
266 // Conceptually, this looks like:
267 // while ((mlist = nextMethodList(cls, &iterator))) {
268 // old_method *m = _findMethodInList(mlist, sel);
272 if (!cls->methodLists) {
276 else if (cls->info & CLS_NO_METHOD_ARRAY) {
278 old_method_list **mlistp;
279 mlistp = (old_method_list **)&cls->methodLists;
280 *mlistp = fixupSelectorsInMethodList(cls, *mlistp);
281 return _findMethodInList(*mlistp, sel);
284 // Multiple method lists.
285 old_method_list **mlistp;
286 for (mlistp = cls->methodLists;
287 *mlistp != nil && *mlistp != END_OF_METHODS_LIST;
291 *mlistp = fixupSelectorsInMethodList(cls, *mlistp);
292 m = _findMethodInList(*mlistp, sel);
299 static inline old_method * _getMethod(Class cls, SEL sel) {
300 for (; cls; cls = cls->superclass) {
302 m = _findMethodInClass(cls, sel);
309 // called by a debugging check in _objc_insertMethods
310 IMP findIMPInClass(Class cls, SEL sel)
312 old_method *m = _findMethodInClass(cls, sel);
313 if (m) return m->method_imp;
318 /***********************************************************************
320 **********************************************************************/
321 static void _freedHandler(id obj, SEL sel)
323 __objc_error (obj, "message %s sent to freed object=%p",
324 sel_getName(sel), (void*)obj);
328 /***********************************************************************
329 * _class_resolveClassMethod
330 * Call +resolveClassMethod, looking for a method to be added to class cls.
331 * cls should be a metaclass.
332 * Does not check if the method already exists.
333 **********************************************************************/
334 static void _class_resolveClassMethod(id inst, SEL sel, Class cls)
336 ASSERT(cls->isMetaClass());
337 SEL resolve_sel = @selector(resolveClassMethod:);
339 if (!lookUpImpOrNil(inst, resolve_sel, cls)) {
340 // Resolver not implemented.
344 BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
345 bool resolved = msg(_class_getNonMetaClass(cls, inst), resolve_sel, sel);
347 // Cache the result (good or bad) so the resolver doesn't fire next time.
348 // +resolveClassMethod adds to self->ISA() a.k.a. cls
349 IMP imp = lookUpImpOrNil(inst, sel, cls);
350 if (resolved && PrintResolving) {
352 _objc_inform("RESOLVE: method %c[%s %s] "
353 "dynamically resolved to %p",
354 cls->isMetaClass() ? '+' : '-',
355 cls->nameForLogging(), sel_getName(sel), imp);
358 // Method resolver didn't add anything?
359 _objc_inform("RESOLVE: +[%s resolveClassMethod:%s] returned YES"
360 ", but no new implementation of %c[%s %s] was found",
361 cls->nameForLogging(), sel_getName(sel),
362 cls->isMetaClass() ? '+' : '-',
363 cls->nameForLogging(), sel_getName(sel));
369 /***********************************************************************
370 * _class_resolveInstanceMethod
371 * Call +resolveInstanceMethod, looking for a method to be added to class cls.
372 * cls may be a metaclass or a non-meta class.
373 * Does not check if the method already exists.
374 **********************************************************************/
375 static void _class_resolveInstanceMethod(id inst, SEL sel, Class cls)
377 SEL resolve_sel = @selector(resolveInstanceMethod:);
379 if (! lookUpImpOrNil(cls, resolve_sel, cls->ISA())) {
380 // Resolver not implemented.
384 BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
385 bool resolved = msg(cls, resolve_sel, sel);
387 // Cache the result (good or bad) so the resolver doesn't fire next time.
388 // +resolveInstanceMethod adds to self a.k.a. cls
389 IMP imp = lookUpImpOrNil(inst, sel, cls);
391 if (resolved && PrintResolving) {
393 _objc_inform("RESOLVE: method %c[%s %s] "
394 "dynamically resolved to %p",
395 cls->isMetaClass() ? '+' : '-',
396 cls->nameForLogging(), sel_getName(sel), imp);
399 // Method resolver didn't add anything?
400 _objc_inform("RESOLVE: +[%s resolveInstanceMethod:%s] returned YES"
401 ", but no new implementation of %c[%s %s] was found",
402 cls->nameForLogging(), sel_getName(sel),
403 cls->isMetaClass() ? '+' : '-',
404 cls->nameForLogging(), sel_getName(sel));
410 /***********************************************************************
411 * _class_resolveMethod
412 * Call +resolveClassMethod or +resolveInstanceMethod.
413 * Returns nothing; any result would be potentially out-of-date already.
414 * Does not check if the method already exists.
415 **********************************************************************/
417 _class_resolveMethod(id inst, SEL sel, Class cls)
419 if (! cls->isMetaClass()) {
420 // try [cls resolveInstanceMethod:sel]
421 _class_resolveInstanceMethod(inst, sel, cls);
424 // try [nonMetaClass resolveClassMethod:sel]
425 // and [cls resolveInstanceMethod:sel]
426 _class_resolveClassMethod(inst, sel, cls);
427 if (!lookUpImpOrNil(inst, sel, cls)) {
428 _class_resolveInstanceMethod(inst, sel, cls);
434 /***********************************************************************
436 * Log this method call. If the logger permits it, fill the method cache.
437 * cls is the method whose cache should be filled.
438 * implementer is the class that owns the implementation in question.
439 **********************************************************************/
441 log_and_fill_cache(Class cls, Class implementer, Method meth, SEL sel)
443 #if SUPPORT_MESSAGE_LOGGING
444 if (objcMsgLogEnabled) {
445 bool cacheIt = logMessageSend(implementer->isMetaClass(),
446 cls->nameForLogging(),
447 implementer->nameForLogging(),
449 if (!cacheIt) return;
452 _cache_fill (cls, meth, sel);
456 /***********************************************************************
457 * lookUpImpOrForward.
458 * The standard IMP lookup.
459 * Without LOOKUP_INITIALIZE: tries to avoid +initialize (but sometimes fails)
460 * Without LOOKUP_CACHE: skips optimistic unlocked lookup (but uses cache elsewhere)
461 * Most callers should use LOOKUP_INITIALIZE and LOOKUP_CACHE
462 * inst is an instance of cls or a subclass thereof, or nil if none is known.
463 * If cls is an un-initialized metaclass then a non-nil inst is faster.
464 * May return _objc_msgForward_impcache. IMPs destined for external use
465 * must be converted to _objc_msgForward or _objc_msgForward_stret.
466 * If you don't want forwarding at all, use LOOKUP_NIL.
467 **********************************************************************/
468 IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior)
473 bool triedResolver = NO;
475 methodListLock.assertUnlocked();
477 // Optimistic cache lookup
478 if (behavior & LOOKUP_CACHE) {
479 methodPC = _cache_getImp(cls, sel);
480 if (methodPC) goto out_nolock;
483 // Check for freed class
484 if (cls == _class_getFreedObjectClass())
485 return (IMP) _freedHandler;
487 // Check for +initialize
488 if ((behavior & LOOKUP_INITIALIZE) && !cls->isInitialized()) {
489 initializeNonMetaClass (_class_getNonMetaClass(cls, inst));
490 // If sel == initialize, initializeNonMetaClass will send +initialize
491 // and then the messenger will send +initialize again after this
492 // procedure finishes. Of course, if this is not being called
493 // from the messenger then it won't happen. 2778172
496 // The lock is held to make method-lookup + cache-fill atomic
497 // with respect to method addition. Otherwise, a category could
498 // be added but ignored indefinitely because the cache was re-filled
499 // with the old value after the cache flush on behalf of the category.
501 methodListLock.lock();
503 // Try this class's cache.
505 methodPC = _cache_getImp(cls, sel);
506 if (methodPC) goto done;
508 // Try this class's method lists.
510 meth = _class_getMethodNoSuper_nolock(cls, sel);
512 log_and_fill_cache(cls, cls, meth, sel);
513 methodPC = method_getImplementation(meth);
517 // Try superclass caches and method lists.
520 while ((curClass = curClass->superclass)) {
522 meth = _cache_getMethod(curClass, sel, _objc_msgForward_impcache);
524 if (meth != (Method)1) {
525 // Found the method in a superclass. Cache it in this class.
526 log_and_fill_cache(cls, curClass, meth, sel);
527 methodPC = method_getImplementation(meth);
531 // Found a forward:: entry in a superclass.
532 // Stop searching, but don't cache yet; call method
533 // resolver for this class first.
538 // Superclass method list.
539 meth = _class_getMethodNoSuper_nolock(curClass, sel);
541 log_and_fill_cache(cls, curClass, meth, sel);
542 methodPC = method_getImplementation(meth);
547 // No implementation found. Try method resolver once.
549 if ((behavior & LOOKUP_RESOLVER) && !triedResolver) {
550 methodListLock.unlock();
551 _class_resolveMethod(cls, sel, inst);
556 // No implementation found, and method resolver didn't help.
559 _cache_addForwardEntry(cls, sel);
560 methodPC = _objc_msgForward_impcache;
563 methodListLock.unlock();
566 if ((behavior & LOOKUP_NIL) && methodPC == (IMP)_objc_msgForward_impcache) {
573 /***********************************************************************
574 * lookupMethodInClassAndLoadCache.
575 * Like _class_lookupMethodAndLoadCache, but does not search superclasses.
576 * Caches and returns objc_msgForward if the method is not found in the class.
577 **********************************************************************/
578 IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel)
583 // fixme this still has the method list vs method cache race
584 // because it doesn't hold a lock across lookup+cache_fill,
585 // but it's only used for .cxx_construct/destruct and we assume
586 // categories don't change them.
588 // Search cache first.
589 imp = _cache_getImp(cls, sel);
592 // Cache miss. Search method list.
594 meth = _class_getMethodNoSuper(cls, sel);
597 // Hit in method list. Cache it.
598 _cache_fill(cls, meth, sel);
599 return method_getImplementation(meth);
601 // Miss in method list. Cache objc_msgForward.
602 _cache_addForwardEntry(cls, sel);
603 return _objc_msgForward_impcache;
608 /***********************************************************************
609 * _class_getClassForIvar
610 * Given a class and an ivar that is in it or one of its superclasses,
611 * find the actual class that defined the ivar.
612 **********************************************************************/
613 Class _class_getClassForIvar(Class cls, Ivar ivar)
615 for ( ; cls; cls = cls->superclass) {
616 if (auto ivars = cls->ivars) {
617 if (ivar >= &ivars->ivar_list[0] &&
618 ivar < &ivars->ivar_list[ivars->ivar_count])
629 /***********************************************************************
630 * class_getVariable. Return the named instance variable.
631 **********************************************************************/
633 Ivar _class_getVariable(Class cls, const char *name)
635 for (; cls != Nil; cls = cls->superclass) {
638 // Skip class having no ivars
639 if (!cls->ivars) continue;
641 for (i = 0; i < cls->ivars->ivar_count; i++) {
642 // Check this ivar's name. Be careful because the
643 // compiler generates ivar entries with nil ivar_name
644 // (e.g. for anonymous bit fields).
645 old_ivar *ivar = &cls->ivars->ivar_list[i];
646 if (ivar->ivar_name && 0 == strcmp(name, ivar->ivar_name)) {
658 property_list_nth(const old_property_list *plist, uint32_t i)
660 return (old_property *)(i*plist->entsize + (char *)&plist->first);
664 copyPropertyList(old_property_list *plist, unsigned int *outCount)
666 old_property **result = nil;
667 unsigned int count = 0;
670 count = plist->count;
675 result = (old_property **)malloc((count+1) * sizeof(old_property *));
677 for (i = 0; i < count; i++) {
678 result[i] = property_list_nth(plist, i);
683 if (outCount) *outCount = count;
688 static old_property_list *
689 nextPropertyList(Class cls, uintptr_t *indexp)
691 old_property_list *result = nil;
693 classLock.assertLocked();
694 if (! ((cls->info & CLS_EXT) && cls->ext)) {
697 } else if (!cls->ext->propertyLists) {
700 } else if (cls->info & CLS_NO_PROPERTY_ARRAY) {
701 // Only one property list
703 result = (old_property_list *)cls->ext->propertyLists;
708 // More than one property list
709 result = cls->ext->propertyLists[*indexp];
722 /***********************************************************************
723 * class_getIvarLayout
724 * nil means all-scanned. "" means non-scanned.
725 **********************************************************************/
727 class_getIvarLayout(Class cls)
729 if (cls && (cls->info & CLS_EXT)) {
730 return cls->ivar_layout;
732 return nil; // conservative scan
737 /***********************************************************************
738 * class_getWeakIvarLayout
739 * nil means no weak ivars.
740 **********************************************************************/
742 class_getWeakIvarLayout(Class cls)
744 if (cls && (cls->info & CLS_EXT) && cls->ext) {
745 return cls->ext->weak_ivar_layout;
747 return nil; // no weak ivars
752 /***********************************************************************
753 * class_setIvarLayout
754 * nil means all-scanned. "" means non-scanned.
755 **********************************************************************/
756 void class_setIvarLayout(Class cls, const uint8_t *layout)
760 if (! (cls->info & CLS_EXT)) {
761 _objc_inform("class '%s' needs to be recompiled", cls->name);
766 cls->ivar_layout = ustrdupMaybeNil(layout);
770 /***********************************************************************
771 * class_setWeakIvarLayout
772 * nil means no weak ivars.
773 **********************************************************************/
774 void class_setWeakIvarLayout(Class cls, const uint8_t *layout)
778 mutex_locker_t lock(classLock);
783 cls->ext->weak_ivar_layout = ustrdupMaybeNil(layout);
787 /***********************************************************************
788 * class_setVersion. Record the specified version with the class.
789 **********************************************************************/
790 void class_setVersion(Class cls, int version)
793 cls->version = version;
796 /***********************************************************************
797 * class_getVersion. Return the version recorded with the class.
798 **********************************************************************/
799 int class_getVersion(Class cls)
802 return (int)cls->version;
806 /***********************************************************************
808 **********************************************************************/
809 const char *class_getName(Class cls)
811 if (!cls) return "nil";
812 else return cls->demangledName();
816 /***********************************************************************
817 * _class_getNonMetaClass.
818 * Return the ordinary class for this class or metaclass.
819 * Used by +initialize.
820 **********************************************************************/
821 static Class _class_getNonMetaClass(Class cls, id obj)
824 if (cls->isMetaClass()) {
825 if (cls->info & CLS_CONSTRUCTING) {
826 // Class is under construction and isn't in the class_hash,
827 // so objc_getClass doesn't work.
828 cls = obj; // fixme this may be nil in some paths
830 else if (strncmp(cls->name, "_%", 2) == 0) {
831 // Posee's meta's name is smashed and isn't in the class_hash,
832 // so objc_getClass doesn't work.
833 const char *baseName = strchr(cls->name, '%'); // get posee's real name
834 cls = objc_getClass(baseName);
837 cls = objc_getClass(cls->name);
846 Class class_initialize(Class cls, id inst) {
847 if (!cls->isInitialized()) {
848 initializeNonMetaClass (_class_getNonMetaClass(cls, inst));
854 Cache _class_getCache(Class cls)
859 void _class_setCache(Class cls, Cache cache)
864 const char *_category_getName(Category cat)
866 return oldcategory(cat)->category_name;
869 const char *_category_getClassName(Category cat)
871 return oldcategory(cat)->class_name;
874 Class _category_getClass(Category cat)
876 return objc_getClass(oldcategory(cat)->class_name);
879 IMP _category_getLoadMethod(Category cat)
881 old_method_list *mlist = oldcategory(cat)->class_methods;
883 return lookupNamedMethodInMethodList(mlist, "load");
891 /***********************************************************************
892 * class_nextMethodList.
893 * External version of nextMethodList().
895 * This function is not fully thread-safe. A series of calls to
896 * class_nextMethodList() may fail if methods are added to or removed
897 * from the class between calls.
898 * If methods are added between calls to class_nextMethodList(), it may
899 * return previously-returned method lists again, and may fail to return
901 * If methods are removed between calls to class_nextMethodList(), it may
902 * omit surviving method lists or simply crash.
903 **********************************************************************/
904 struct objc_method_list *class_nextMethodList(Class cls, void **it)
906 OBJC_WARN_DEPRECATED;
908 mutex_locker_t lock(methodListLock);
909 return (struct objc_method_list *) nextMethodList(cls, it);
913 /***********************************************************************
916 * Formerly class_addInstanceMethods ()
917 **********************************************************************/
918 void class_addMethods(Class cls, struct objc_method_list *meths)
920 OBJC_WARN_DEPRECATED;
924 mutex_locker_t lock(methodListLock);
925 _objc_insertMethods(cls, (old_method_list *)meths, nil);
928 // Must flush when dynamically adding methods. No need to flush
929 // all the class method caches. If cls is a meta class, though,
930 // this will still flush it and any of its sub-meta classes.
931 flush_caches (cls, NO);
935 /***********************************************************************
936 * class_removeMethods.
937 **********************************************************************/
938 void class_removeMethods(Class cls, struct objc_method_list *meths)
940 OBJC_WARN_DEPRECATED;
942 // Remove the methods
944 mutex_locker_t lock(methodListLock);
945 _objc_removeMethods(cls, (old_method_list *)meths);
948 // Must flush when dynamically removing methods. No need to flush
949 // all the class method caches. If cls is a meta class, though,
950 // this will still flush it and any of its sub-meta classes.
951 flush_caches (cls, NO);
954 /***********************************************************************
955 * lookupNamedMethodInMethodList
956 * Only called to find +load/-.cxx_construct/-.cxx_destruct methods,
957 * without fixing up the entire method list.
958 * The class is not yet in use, so methodListLock is not taken.
959 **********************************************************************/
960 IMP lookupNamedMethodInMethodList(old_method_list *mlist, const char *meth_name)
963 m = meth_name ? _findNamedMethodInList(mlist, meth_name) : nil;
964 return (m ? m->method_imp : nil);
967 static Method _class_getMethod(Class cls, SEL sel)
969 mutex_locker_t lock(methodListLock);
970 return (Method)_getMethod(cls, sel);
973 static Method _class_getMethodNoSuper(Class cls, SEL sel)
975 mutex_locker_t lock(methodListLock);
976 return (Method)_findMethodInClass(cls, sel);
979 static Method _class_getMethodNoSuper_nolock(Class cls, SEL sel)
981 methodListLock.assertLocked();
982 return (Method)_findMethodInClass(cls, sel);
986 /***********************************************************************
987 * class_getInstanceMethod. Return the instance method for the
988 * specified class and selector.
989 **********************************************************************/
990 Method class_getInstanceMethod(Class cls, SEL sel)
992 if (!cls || !sel) return nil;
994 // This deliberately avoids +initialize because it historically did so.
996 // This implementation is a bit weird because it's the only place that
997 // wants a Method instead of an IMP.
1000 meth = _cache_getMethod(cls, sel, _objc_msgForward_impcache);
1001 if (meth == (Method)1) {
1002 // Cache contains forward:: . Stop searching.
1008 // Search method lists, try method resolver, etc.
1009 lookUpImpOrForward(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER);
1011 meth = _cache_getMethod(cls, sel, _objc_msgForward_impcache);
1012 if (meth == (Method)1) {
1013 // Cache contains forward:: . Stop searching.
1019 return _class_getMethod(cls, sel);
1023 BOOL class_conformsToProtocol(Class cls, Protocol *proto_gen)
1025 old_protocol *proto = oldprotocol(proto_gen);
1027 if (!cls) return NO;
1028 if (!proto) return NO;
1030 if (cls->ISA()->version >= 3) {
1031 old_protocol_list *list;
1032 for (list = cls->protocols; list != nil; list = list->next) {
1034 for (i = 0; i < list->count; i++) {
1035 if (list->list[i] == proto) return YES;
1036 if (protocol_conformsToProtocol((Protocol *)list->list[i], proto_gen)) return YES;
1038 if (cls->ISA()->version <= 4) break;
1045 static NXMapTable * posed_class_hash = nil;
1047 /***********************************************************************
1048 * objc_getOrigClass.
1049 **********************************************************************/
1051 Class _objc_getOrigClass(const char *name)
1053 // Look for class among the posers
1055 mutex_locker_t lock(classLock);
1056 if (posed_class_hash) {
1057 Class cls = (Class) NXMapGet (posed_class_hash, name);
1058 if (cls) return cls;
1062 // Not a poser. Do a normal lookup.
1063 Class cls = objc_getClass (name);
1064 if (cls) return cls;
1066 _objc_inform ("class `%s' not linked into application", name);
1070 Class objc_getOrigClass(const char *name)
1072 OBJC_WARN_DEPRECATED;
1073 return _objc_getOrigClass(name);
1076 /***********************************************************************
1077 * _objc_addOrigClass. This function is only used from class_poseAs.
1078 * Registers the original class names, before they get obscured by
1079 * posing, so that [super ..] will work correctly from categories
1080 * in posing classes and in categories in classes being posed for.
1081 **********************************************************************/
1082 static void _objc_addOrigClass (Class origClass)
1084 mutex_locker_t lock(classLock);
1086 // Create the poser's hash table on first use
1087 if (!posed_class_hash)
1089 posed_class_hash = NXCreateMapTable(NXStrValueMapPrototype, 8);
1092 // Add the named class iff it is not already there (or collides?)
1093 if (NXMapGet (posed_class_hash, origClass->name) == 0)
1094 NXMapInsert (posed_class_hash, origClass->name, origClass);
1098 /***********************************************************************
1099 * change_class_references
1100 * Change classrefs and superclass pointers from original to imposter
1101 * But if copy!=nil, don't change copy->superclass.
1102 * If changeSuperRefs==YES, also change [super message] classrefs.
1103 * Used by class_poseAs and objc_setFutureClass
1104 * classLock must be locked.
1105 **********************************************************************/
1106 void change_class_references(Class imposter,
1109 bool changeSuperRefs)
1115 // Change all subclasses of the original to point to the imposter.
1116 state = NXInitHashState (class_hash);
1117 while (NXNextHashState (class_hash, &state, (void **) &clsObject))
1119 while ((clsObject) && (clsObject != imposter) &&
1120 (clsObject != copy))
1122 if (clsObject->superclass == original)
1124 clsObject->superclass = imposter;
1125 clsObject->ISA()->superclass = imposter->ISA();
1126 // We must flush caches here!
1130 clsObject = clsObject->superclass;
1134 // Replace the original with the imposter in all class refs
1135 // Major loop - process all headers
1136 for (hInfo = FirstHeader; hInfo != nil; hInfo = hInfo->getNext())
1142 // Fix class refs associated with this header
1143 cls_refs = _getObjcClassRefs(hInfo, &refCount);
1145 for (index = 0; index < refCount; index += 1) {
1146 if (cls_refs[index] == original) {
1147 cls_refs[index] = imposter;
1155 /***********************************************************************
1158 * !!! class_poseAs () does not currently flush any caches.
1159 **********************************************************************/
1160 Class class_poseAs(Class imposter, Class original)
1162 char * imposterNamePtr;
1165 OBJC_WARN_DEPRECATED;
1167 // Trivial case is easy
1168 if (imposter == original)
1171 // Imposter must be an immediate subclass of the original
1172 if (imposter->superclass != original) {
1173 __objc_error(imposter,
1174 "[%s poseAs:%s]: target not immediate superclass",
1175 imposter->name, original->name);
1178 // Can't pose when you have instance variables (how could it work?)
1179 if (imposter->ivars) {
1180 __objc_error(imposter,
1181 "[%s poseAs:%s]: %s defines new instance variables",
1182 imposter->name, original->name, imposter->name);
1185 // Build a string to use to replace the name of the original class.
1187 # define imposterNamePrefix "_%"
1188 imposterNamePtr = malloc(strlen(original->name) + strlen(imposterNamePrefix) + 1);
1189 strcpy(imposterNamePtr, imposterNamePrefix);
1190 strcat(imposterNamePtr, original->name);
1191 # undef imposterNamePrefix
1193 asprintf(&imposterNamePtr, "_%%%s", original->name);
1196 // We lock the class hashtable, so we are thread safe with respect to
1197 // calls to objc_getClass (). However, the class names are not
1198 // changed atomically, nor are all of the subclasses updated
1199 // atomically. I have ordered the operations so that you will
1200 // never crash, but you may get inconsistent results....
1202 // Register the original class so that [super ..] knows
1203 // exactly which classes are the "original" classes.
1204 _objc_addOrigClass (original);
1205 _objc_addOrigClass (imposter);
1207 // Copy the imposter, so that the imposter can continue
1208 // its normal life in addition to changing the behavior of
1209 // the original. As a hack we don't bother to copy the metaclass.
1210 // For some reason we modify the original rather than the copy.
1211 copy = (Class)malloc(sizeof(objc_class));
1212 memmove(copy, imposter, sizeof(objc_class));
1214 mutex_locker_t lock(classLock);
1216 // Remove both the imposter and the original class.
1217 NXHashRemove (class_hash, imposter);
1218 NXHashRemove (class_hash, original);
1220 NXHashInsert (class_hash, copy);
1222 // Mark the imposter as such
1223 imposter->setInfo(CLS_POSING);
1224 imposter->ISA()->setInfo(CLS_POSING);
1226 // Change the name of the imposter to that of the original class.
1227 imposter->name = original->name;
1228 imposter->ISA()->name = original->ISA()->name;
1230 // Also copy the version field to avoid archiving problems.
1231 imposter->version = original->version;
1233 // Change classrefs and superclass pointers
1234 // Don't change copy->superclass
1235 // Don't change [super ...] messages
1236 change_class_references(imposter, original, copy, NO);
1238 // Change the name of the original class.
1239 original->name = imposterNamePtr + 1;
1240 original->ISA()->name = imposterNamePtr;
1242 // Restore the imposter and the original class with their new names.
1243 NXHashInsert (class_hash, imposter);
1244 NXHashInsert (class_hash, original);
1250 /***********************************************************************
1251 * _objc_flush_caches. Flush the instance and class method caches
1252 * of cls and all its subclasses.
1254 * Specifying Nil for the class "all classes."
1255 **********************************************************************/
1256 static void flush_caches(Class target, bool flush_meta)
1258 bool collectALot = (target == nil);
1261 #ifdef OBJC_INSTRUMENTED
1262 unsigned int classesVisited;
1263 unsigned int subclassCount;
1266 mutex_locker_t lock(classLock);
1267 mutex_locker_t lock2(cacheUpdateLock);
1269 // Leaf classes are fastest because there are no subclass caches to flush.
1271 if (target && (target->info & CLS_LEAF)) {
1272 _cache_flush (target);
1274 if (target->ISA() && (target->ISA()->info & CLS_LEAF)) {
1275 _cache_flush (target->ISA());
1278 // Reset target and handle it by one of the methods below.
1279 target = target->ISA();
1285 state = NXInitHashState(class_hash);
1287 // Handle nil and root instance class specially: flush all
1288 // instance and class method caches. Nice that this
1289 // loop is linear vs the N-squared loop just below.
1290 if (!target || !target->superclass)
1292 #ifdef OBJC_INSTRUMENTED
1293 LinearFlushCachesCount += 1;
1297 // Traverse all classes in the hash table
1298 while (NXNextHashState(class_hash, &state, (void**)&clsObject))
1300 Class metaClsObject;
1301 #ifdef OBJC_INSTRUMENTED
1302 classesVisited += 1;
1305 // Skip class that is known not to be a subclass of this root
1306 // (the isa pointer of any meta class points to the meta class
1308 // NOTE: When is an isa pointer of a hash tabled class ever nil?
1309 metaClsObject = clsObject->ISA();
1310 if (target && metaClsObject && target->ISA() != metaClsObject->ISA()) {
1314 #ifdef OBJC_INSTRUMENTED
1318 _cache_flush (clsObject);
1319 if (flush_meta && metaClsObject != nil) {
1320 _cache_flush (metaClsObject);
1323 #ifdef OBJC_INSTRUMENTED
1324 LinearFlushCachesVisitedCount += classesVisited;
1325 if (classesVisited > MaxLinearFlushCachesVisitedCount)
1326 MaxLinearFlushCachesVisitedCount = classesVisited;
1327 IdealFlushCachesCount += subclassCount;
1328 if (subclassCount > MaxIdealFlushCachesCount)
1329 MaxIdealFlushCachesCount = subclassCount;
1335 // Outer loop - flush any cache that could now get a method from
1336 // cls (i.e. the cache associated with cls and any of its subclasses).
1337 #ifdef OBJC_INSTRUMENTED
1338 NonlinearFlushCachesCount += 1;
1342 while (NXNextHashState(class_hash, &state, (void**)&clsObject))
1346 #ifdef OBJC_INSTRUMENTED
1347 NonlinearFlushCachesClassCount += 1;
1350 // Inner loop - Process a given class
1351 clsIter = clsObject;
1355 #ifdef OBJC_INSTRUMENTED
1356 classesVisited += 1;
1358 // Flush clsObject instance method cache if
1359 // clsObject is a subclass of cls, or is cls itself
1360 // Flush the class method cache if that was asked for
1361 if (clsIter == target)
1363 #ifdef OBJC_INSTRUMENTED
1366 _cache_flush (clsObject);
1368 _cache_flush (clsObject->ISA());
1374 // Flush clsObject class method cache if cls is
1375 // the meta class of clsObject or of one
1376 // of clsObject's superclasses
1377 else if (clsIter->ISA() == target)
1379 #ifdef OBJC_INSTRUMENTED
1382 _cache_flush (clsObject->ISA());
1386 // Move up superclass chain
1387 // else if (clsIter->isInitialized())
1388 clsIter = clsIter->superclass;
1390 // clsIter is not initialized, so its cache
1391 // must be empty. This happens only when
1392 // clsIter == clsObject, because
1393 // superclasses are initialized before
1394 // subclasses, and this loop traverses
1395 // from sub- to super- classes.
1400 #ifdef OBJC_INSTRUMENTED
1401 NonlinearFlushCachesVisitedCount += classesVisited;
1402 if (classesVisited > MaxNonlinearFlushCachesVisitedCount)
1403 MaxNonlinearFlushCachesVisitedCount = classesVisited;
1404 IdealFlushCachesCount += subclassCount;
1405 if (subclassCount > MaxIdealFlushCachesCount)
1406 MaxIdealFlushCachesCount = subclassCount;
1412 _cache_collect(true);
1417 void _objc_flush_caches(Class target)
1419 flush_caches(target, YES);
1424 /***********************************************************************
1425 * flush_marked_caches. Flush the method cache of any class marked
1426 * CLS_FLUSH_CACHE (and all subclasses thereof)
1428 **********************************************************************/
1429 void flush_marked_caches(void)
1435 mutex_locker_t lock(classLock);
1436 mutex_locker_t lock2(cacheUpdateLock);
1438 state = NXInitHashState(class_hash);
1439 while (NXNextHashState(class_hash, &state, (void**)&cls)) {
1440 for (supercls = cls; supercls; supercls = supercls->superclass) {
1441 if (supercls->info & CLS_FLUSH_CACHE) {
1447 for (supercls = cls->ISA(); supercls; supercls = supercls->superclass) {
1448 if (supercls->info & CLS_FLUSH_CACHE) {
1449 _cache_flush(cls->ISA());
1455 state = NXInitHashState(class_hash);
1456 while (NXNextHashState(class_hash, &state, (void**)&cls)) {
1457 if (cls->info & CLS_FLUSH_CACHE) {
1458 cls->clearInfo(CLS_FLUSH_CACHE);
1460 if (cls->ISA()->info & CLS_FLUSH_CACHE) {
1461 cls->ISA()->clearInfo(CLS_FLUSH_CACHE);
1467 /***********************************************************************
1468 * get_base_method_list
1469 * Returns the method list containing the class's own methods,
1470 * ignoring any method lists added by categories or class_addMethods.
1471 * Called only by add_class_to_loadable_list.
1472 * Does not hold methodListLock because add_class_to_loadable_list
1473 * does not manipulate in-use classes.
1474 **********************************************************************/
1475 static old_method_list *get_base_method_list(Class cls)
1477 old_method_list **ptr;
1479 if (!cls->methodLists) return nil;
1480 if (cls->info & CLS_NO_METHOD_ARRAY) return (old_method_list *)cls->methodLists;
1481 ptr = cls->methodLists;
1482 if (!*ptr || *ptr == END_OF_METHODS_LIST) return nil;
1483 while ( *ptr != 0 && *ptr != END_OF_METHODS_LIST ) { ptr++; }
1489 static IMP _class_getLoadMethod_nocheck(Class cls)
1491 old_method_list *mlist;
1492 mlist = get_base_method_list(cls->ISA());
1494 return lookupNamedMethodInMethodList (mlist, "load");
1500 bool _class_hasLoadMethod(Class cls)
1502 if (cls->ISA()->info & CLS_HAS_LOAD_METHOD) return YES;
1503 return _class_getLoadMethod_nocheck(cls);
1507 /***********************************************************************
1508 * objc_class::getLoadMethod
1509 * Returns cls's +load implementation, or nil if it doesn't have one.
1510 **********************************************************************/
1511 IMP objc_class::getLoadMethod()
1513 if (ISA()->info & CLS_HAS_LOAD_METHOD) {
1514 return _class_getLoadMethod_nocheck((Class)this);
1519 ptrdiff_t ivar_getOffset(Ivar ivar)
1521 return oldivar(ivar)->ivar_offset;
1524 const char *ivar_getName(Ivar ivar)
1526 return oldivar(ivar)->ivar_name;
1529 const char *ivar_getTypeEncoding(Ivar ivar)
1531 return oldivar(ivar)->ivar_type;
1535 IMP method_getImplementation(Method m)
1538 return oldmethod(m)->method_imp;
1541 SEL method_getName(Method m)
1544 return oldmethod(m)->method_name;
1547 const char *method_getTypeEncoding(Method m)
1550 return oldmethod(m)->method_types;
1553 unsigned int method_getSizeOfArguments(Method m)
1555 OBJC_WARN_DEPRECATED;
1557 return encoding_getSizeOfArguments(method_getTypeEncoding(m));
1560 // This function was accidentally un-exported beginning in macOS 10.9.
1561 // As of macOS 10.13 nobody had complained.
1563 unsigned int method_getArgumentInfo(Method m, int arg,
1564 const char **type, int *offset)
1566 OBJC_WARN_DEPRECATED;
1568 return encoding_getArgumentInfo(method_getTypeEncoding(m),
1576 IMP method_setImplementation(Method m_gen, IMP imp)
1579 old_method *m = oldmethod(m_gen);
1581 if (!imp) return nil;
1584 old = m->method_imp;
1585 m->method_imp = imp;
1591 void method_exchangeImplementations(Method m1_gen, Method m2_gen)
1594 old_method *m1 = oldmethod(m1_gen);
1595 old_method *m2 = oldmethod(m2_gen);
1596 if (!m1 || !m2) return;
1599 m1_imp = m1->method_imp;
1600 m1->method_imp = m2->method_imp;
1601 m2->method_imp = m1_imp;
1606 struct objc_method_description * method_getDescription(Method m)
1609 return (struct objc_method_description *)oldmethod(m);
1613 const char *property_getName(objc_property_t prop)
1615 return oldproperty(prop)->name;
1618 const char *property_getAttributes(objc_property_t prop)
1620 return oldproperty(prop)->attributes;
1623 objc_property_attribute_t *property_copyAttributeList(objc_property_t prop,
1624 unsigned int *outCount)
1627 if (outCount) *outCount = 0;
1631 mutex_locker_t lock(classLock);
1632 return copyPropertyAttributeList(oldproperty(prop)->attributes,outCount);
1635 char * property_copyAttributeValue(objc_property_t prop, const char *name)
1637 if (!prop || !name || *name == '\0') return nil;
1639 mutex_locker_t lock(classLock);
1640 return copyPropertyAttributeValue(oldproperty(prop)->attributes, name);
1644 /***********************************************************************
1646 **********************************************************************/
1647 static IMP _class_addMethod(Class cls, SEL name, IMP imp,
1648 const char *types, bool replace)
1653 if (!types) types = "";
1655 mutex_locker_t lock(methodListLock);
1657 if ((m = _findMethodInClass(cls, name))) {
1660 result = method_getImplementation((Method)m);
1662 method_setImplementation((Method)m, imp);
1665 // fixme could be faster
1666 old_method_list *mlist =
1667 (old_method_list *)calloc(sizeof(old_method_list), 1);
1668 mlist->obsolete = fixed_up_method_list;
1669 mlist->method_count = 1;
1670 mlist->method_list[0].method_name = name;
1671 mlist->method_list[0].method_types = strdup(types);
1672 mlist->method_list[0].method_imp = imp;
1674 _objc_insertMethods(cls, mlist, nil);
1675 if (!(cls->info & CLS_CONSTRUCTING)) {
1676 flush_caches(cls, NO);
1678 // in-construction class has no subclasses
1688 /***********************************************************************
1690 **********************************************************************/
1691 BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
1694 if (!cls) return NO;
1696 old = _class_addMethod(cls, name, imp, types, NO);
1701 /***********************************************************************
1702 * class_replaceMethod
1703 **********************************************************************/
1704 IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
1706 if (!cls) return nil;
1708 return _class_addMethod(cls, name, imp, types, YES);
1712 /***********************************************************************
1714 **********************************************************************/
1715 BOOL class_addIvar(Class cls, const char *name, size_t size,
1716 uint8_t alignment, const char *type)
1720 if (!cls) return NO;
1721 if (ISMETA(cls)) return NO;
1722 if (!(cls->info & CLS_CONSTRUCTING)) return NO;
1724 if (!type) type = "";
1725 if (name && 0 == strcmp(name, "")) name = nil;
1727 mutex_locker_t lock(classLock);
1729 // Check for existing ivar with this name
1730 // fixme check superclasses?
1733 for (i = 0; i < cls->ivars->ivar_count; i++) {
1734 if (0 == strcmp(cls->ivars->ivar_list[i].ivar_name, name)) {
1742 old_ivar_list *old = cls->ivars;
1750 oldSize = sizeof(old_ivar_list) +
1751 (old->ivar_count - 1) * sizeof(old_ivar);
1752 newCount = 1 + old->ivar_count;
1754 oldSize = sizeof(old_ivar_list) - sizeof(old_ivar);
1758 // allocate new ivar list
1759 cls->ivars = (old_ivar_list *)
1760 calloc(oldSize+sizeof(old_ivar), 1);
1761 if (old) memcpy(cls->ivars, old, oldSize);
1762 if (old && malloc_size(old)) free(old);
1763 cls->ivars->ivar_count = newCount;
1764 ivar = &cls->ivars->ivar_list[newCount-1];
1766 // set ivar name and type
1767 ivar->ivar_name = strdup(name);
1768 ivar->ivar_type = strdup(type);
1770 // align if necessary
1771 alignBytes = 1 << alignment;
1772 misalign = cls->instance_size % alignBytes;
1773 if (misalign) cls->instance_size += (long)(alignBytes - misalign);
1775 // set ivar offset and increase instance size
1776 ivar->ivar_offset = (int)cls->instance_size;
1777 cls->instance_size += (long)size;
1784 /***********************************************************************
1786 **********************************************************************/
1787 BOOL class_addProtocol(Class cls, Protocol *protocol_gen)
1789 old_protocol *protocol = oldprotocol(protocol_gen);
1790 old_protocol_list *plist;
1792 if (!cls) return NO;
1793 if (class_conformsToProtocol(cls, protocol_gen)) return NO;
1795 mutex_locker_t lock(classLock);
1797 // fixme optimize - protocol list doesn't escape?
1798 plist = (old_protocol_list*)calloc(sizeof(old_protocol_list), 1);
1800 plist->list[0] = protocol;
1801 plist->next = cls->protocols;
1802 cls->protocols = plist;
1810 /***********************************************************************
1811 * _class_addProperties
1812 * Internal helper to add properties to a class.
1813 * Used by category attachment and class_addProperty()
1814 * Locking: acquires classLock
1815 **********************************************************************/
1817 _class_addProperties(Class cls,
1818 old_property_list *additions)
1820 old_property_list *newlist;
1822 if (!(cls->info & CLS_EXT)) return NO;
1824 newlist = (old_property_list *)
1825 memdup(additions, sizeof(*newlist) - sizeof(newlist->first)
1826 + (additions->entsize * additions->count));
1828 mutex_locker_t lock(classLock);
1831 if (!cls->ext->propertyLists) {
1832 // cls has no properties - simply use this list
1833 cls->ext->propertyLists = (old_property_list **)newlist;
1834 cls->setInfo(CLS_NO_PROPERTY_ARRAY);
1836 else if (cls->info & CLS_NO_PROPERTY_ARRAY) {
1837 // cls has one property list - make a new array
1838 old_property_list **newarray = (old_property_list **)
1839 malloc(3 * sizeof(*newarray));
1840 newarray[0] = newlist;
1841 newarray[1] = (old_property_list *)cls->ext->propertyLists;
1843 cls->ext->propertyLists = newarray;
1844 cls->clearInfo(CLS_NO_PROPERTY_ARRAY);
1847 // cls has a property array - make a bigger one
1848 old_property_list **newarray;
1850 while (cls->ext->propertyLists[count]) count++;
1851 newarray = (old_property_list **)
1852 malloc((count+2) * sizeof(*newarray));
1853 newarray[0] = newlist;
1854 memcpy(&newarray[1], &cls->ext->propertyLists[0],
1855 count * sizeof(*newarray));
1856 newarray[count+1] = nil;
1857 free(cls->ext->propertyLists);
1858 cls->ext->propertyLists = newarray;
1865 /***********************************************************************
1867 * Adds a property to a class. Returns NO if the proeprty already exists.
1868 * Locking: acquires classLock
1869 **********************************************************************/
1871 _class_addProperty(Class cls, const char *name,
1872 const objc_property_attribute_t *attrs, unsigned int count,
1875 if (!cls) return NO;
1876 if (!name) return NO;
1878 old_property *prop = oldproperty(class_getProperty(cls, name));
1879 if (prop && !replace) {
1880 // already exists, refuse to replace
1885 mutex_locker_t lock(classLock);
1886 try_free(prop->attributes);
1887 prop->attributes = copyPropertyAttributeString(attrs, count);
1892 old_property_list proplist;
1893 proplist.entsize = sizeof(old_property);
1895 proplist.first.name = strdup(name);
1896 proplist.first.attributes = copyPropertyAttributeString(attrs, count);
1898 return _class_addProperties(cls, &proplist);
1903 class_addProperty(Class cls, const char *name,
1904 const objc_property_attribute_t *attrs, unsigned int n)
1906 return _class_addProperty(cls, name, attrs, n, NO);
1910 class_replaceProperty(Class cls, const char *name,
1911 const objc_property_attribute_t *attrs, unsigned int n)
1913 _class_addProperty(cls, name, attrs, n, YES);
1917 /***********************************************************************
1918 * class_copyProtocolList. Returns a heap block containing the
1919 * protocols implemented by the class, or nil if the class
1920 * implements no protocols. Caller must free the block.
1921 * Does not copy any superclass's protocols.
1922 **********************************************************************/
1923 Protocol * __unsafe_unretained *
1924 class_copyProtocolList(Class cls, unsigned int *outCount)
1926 old_protocol_list *plist;
1927 Protocol **result = nil;
1928 unsigned int count = 0;
1932 if (outCount) *outCount = 0;
1936 mutex_locker_t lock(classLock);
1938 for (plist = cls->protocols; plist != nil; plist = plist->next) {
1939 count += (int)plist->count;
1943 result = (Protocol **)malloc((count+1) * sizeof(Protocol *));
1945 for (p = 0, plist = cls->protocols;
1947 plist = plist->next)
1950 for (i = 0; i < plist->count; i++) {
1951 result[p++] = (Protocol *)plist->list[i];
1957 if (outCount) *outCount = count;
1962 /***********************************************************************
1963 * class_getProperty. Return the named property.
1964 **********************************************************************/
1965 objc_property_t class_getProperty(Class cls, const char *name)
1967 if (!cls || !name) return nil;
1969 mutex_locker_t lock(classLock);
1971 for (; cls; cls = cls->superclass) {
1972 uintptr_t iterator = 0;
1973 old_property_list *plist;
1974 while ((plist = nextPropertyList(cls, &iterator))) {
1976 for (i = 0; i < plist->count; i++) {
1977 old_property *p = property_list_nth(plist, i);
1978 if (0 == strcmp(name, p->name)) {
1979 return (objc_property_t)p;
1989 /***********************************************************************
1990 * class_copyPropertyList. Returns a heap block containing the
1991 * properties declared in the class, or nil if the class
1992 * declares no properties. Caller must free the block.
1993 * Does not copy any superclass's properties.
1994 **********************************************************************/
1995 objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
1997 old_property_list *plist;
1998 uintptr_t iterator = 0;
1999 old_property **result = nil;
2000 unsigned int count = 0;
2004 if (outCount) *outCount = 0;
2008 mutex_locker_t lock(classLock);
2011 while ((plist = nextPropertyList(cls, &iterator))) {
2012 count += plist->count;
2016 result = (old_property **)malloc((count+1) * sizeof(old_property *));
2020 while ((plist = nextPropertyList(cls, &iterator))) {
2021 for (i = 0; i < plist->count; i++) {
2022 result[p++] = property_list_nth(plist, i);
2028 if (outCount) *outCount = count;
2029 return (objc_property_t *)result;
2033 /***********************************************************************
2034 * class_copyMethodList. Returns a heap block containing the
2035 * methods implemented by the class, or nil if the class
2036 * implements no methods. Caller must free the block.
2037 * Does not copy any superclass's methods.
2038 **********************************************************************/
2039 Method *class_copyMethodList(Class cls, unsigned int *outCount)
2041 old_method_list *mlist;
2042 void *iterator = nil;
2043 Method *result = nil;
2044 unsigned int count = 0;
2048 if (outCount) *outCount = 0;
2052 mutex_locker_t lock(methodListLock);
2055 while ((mlist = nextMethodList(cls, &iterator))) {
2056 count += mlist->method_count;
2060 result = (Method *)malloc((count+1) * sizeof(Method));
2064 while ((mlist = nextMethodList(cls, &iterator))) {
2066 for (i = 0; i < mlist->method_count; i++) {
2067 result[m++] = (Method)&mlist->method_list[i];
2073 if (outCount) *outCount = count;
2078 /***********************************************************************
2079 * class_copyIvarList. Returns a heap block containing the
2080 * ivars declared in the class, or nil if the class
2081 * declares no ivars. Caller must free the block.
2082 * Does not copy any superclass's ivars.
2083 **********************************************************************/
2084 Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
2087 unsigned int count = 0;
2091 if (outCount) *outCount = 0;
2096 count = cls->ivars->ivar_count;
2100 result = (Ivar *)malloc((count+1) * sizeof(Ivar));
2102 for (i = 0; i < cls->ivars->ivar_count; i++) {
2103 result[i] = (Ivar)&cls->ivars->ivar_list[i];
2108 if (outCount) *outCount = count;
2113 /***********************************************************************
2114 * objc_allocateClass.
2115 **********************************************************************/
2117 void set_superclass(Class cls, Class supercls, bool cls_is_new)
2119 Class meta = cls->ISA();
2122 cls->superclass = supercls;
2123 meta->superclass = supercls->ISA();
2124 meta->initIsa(supercls->ISA()->ISA());
2126 // Propagate C++ cdtors from superclass.
2127 if (supercls->info & CLS_HAS_CXX_STRUCTORS) {
2128 if (cls_is_new) cls->info |= CLS_HAS_CXX_STRUCTORS;
2129 else cls->setInfo(CLS_HAS_CXX_STRUCTORS);
2132 // Superclass is no longer a leaf for cache flushing
2133 if (supercls->info & CLS_LEAF) {
2134 supercls->clearInfo(CLS_LEAF);
2135 supercls->ISA()->clearInfo(CLS_LEAF);
2138 cls->superclass = Nil; // superclass of root class is nil
2139 meta->superclass = cls; // superclass of root metaclass is root class
2140 meta->initIsa(meta); // metaclass of root metaclass is root metaclass
2142 // Root class is never a leaf for cache flushing, because the
2143 // root metaclass is a subclass. (This could be optimized, but
2144 // is too uncommon to bother.)
2145 cls->clearInfo(CLS_LEAF);
2146 meta->clearInfo(CLS_LEAF);
2150 // &UnsetLayout is the default ivar layout during class construction
2151 static const uint8_t UnsetLayout = 0;
2153 Class objc_initializeClassPair(Class supercls, const char *name, Class cls, Class meta)
2155 // Connect to superclasses and metaclasses
2157 set_superclass(cls, supercls, YES);
2160 cls->name = strdup(name);
2161 meta->name = strdup(name);
2164 cls->info = CLS_CLASS | CLS_CONSTRUCTING | CLS_EXT | CLS_LEAF;
2165 meta->info = CLS_META | CLS_CONSTRUCTING | CLS_EXT | CLS_LEAF;
2167 // Set instance size based on superclass.
2169 cls->instance_size = supercls->instance_size;
2170 meta->instance_size = supercls->ISA()->instance_size;
2172 cls->instance_size = sizeof(Class); // just an isa
2173 meta->instance_size = sizeof(objc_class);
2176 // No ivars. No methods. Empty cache. No protocols. No layout. Empty ext.
2178 cls->methodLists = nil;
2179 cls->cache = (Cache)&_objc_empty_cache;
2180 cls->protocols = nil;
2181 cls->ivar_layout = &UnsetLayout;
2184 cls->ext->weak_ivar_layout = &UnsetLayout;
2187 meta->methodLists = nil;
2188 meta->cache = (Cache)&_objc_empty_cache;
2189 meta->protocols = nil;
2195 Class objc_allocateClassPair(Class supercls, const char *name,
2200 if (objc_getClass(name)) return nil;
2201 // fixme reserve class name against simultaneous allocation
2203 if (supercls && (supercls->info & CLS_CONSTRUCTING)) {
2204 // Can't make subclass of an in-construction class
2208 // Allocate new classes.
2210 cls = _calloc_class(supercls->ISA()->alignedInstanceSize() + extraBytes);
2211 meta = _calloc_class(supercls->ISA()->ISA()->alignedInstanceSize() + extraBytes);
2213 cls = _calloc_class(sizeof(objc_class) + extraBytes);
2214 meta = _calloc_class(sizeof(objc_class) + extraBytes);
2218 objc_initializeClassPair(supercls, name, cls, meta);
2224 void objc_registerClassPair(Class cls)
2226 if ((cls->info & CLS_CONSTRUCTED) ||
2227 (cls->ISA()->info & CLS_CONSTRUCTED))
2229 _objc_inform("objc_registerClassPair: class '%s' was already "
2230 "registered!", cls->name);
2234 if (!(cls->info & CLS_CONSTRUCTING) ||
2235 !(cls->ISA()->info & CLS_CONSTRUCTING))
2237 _objc_inform("objc_registerClassPair: class '%s' was not "
2238 "allocated with objc_allocateClassPair!", cls->name);
2243 _objc_inform("objc_registerClassPair: class '%s' is a metaclass, "
2244 "not a class!", cls->name);
2248 mutex_locker_t lock(classLock);
2250 // Clear "under construction" bit, set "done constructing" bit
2251 cls->info &= ~CLS_CONSTRUCTING;
2252 cls->ISA()->info &= ~CLS_CONSTRUCTING;
2253 cls->info |= CLS_CONSTRUCTED;
2254 cls->ISA()->info |= CLS_CONSTRUCTED;
2256 NXHashInsertIfAbsent(class_hash, cls);
2260 Class objc_duplicateClass(Class original, const char *name, size_t extraBytes)
2262 unsigned int count, i;
2263 old_method **originalMethods;
2264 old_method_list *duplicateMethods;
2265 // Don't use sizeof(objc_class) here because
2266 // instance_size has historically contained two extra words,
2267 // and instance_size is what objc_getIndexedIvars() actually uses.
2269 _calloc_class(original->ISA()->alignedInstanceSize() + extraBytes);
2271 duplicate->initIsa(original->ISA());
2272 duplicate->superclass = original->superclass;
2273 duplicate->name = strdup(name);
2274 duplicate->version = original->version;
2275 duplicate->info = original->info & (CLS_CLASS|CLS_META|CLS_INITIALIZED|CLS_JAVA_HYBRID|CLS_JAVA_CLASS|CLS_HAS_CXX_STRUCTORS|CLS_HAS_LOAD_METHOD);
2276 duplicate->instance_size = original->instance_size;
2277 duplicate->ivars = original->ivars;
2278 // methodLists handled below
2279 duplicate->cache = (Cache)&_objc_empty_cache;
2280 duplicate->protocols = original->protocols;
2281 if (original->info & CLS_EXT) {
2282 duplicate->info |= original->info & (CLS_EXT|CLS_NO_PROPERTY_ARRAY);
2283 duplicate->ivar_layout = original->ivar_layout;
2284 if (original->ext) {
2285 duplicate->ext = (old_class_ext *)malloc(original->ext->size);
2286 memcpy(duplicate->ext, original->ext, original->ext->size);
2288 duplicate->ext = nil;
2292 // Method lists are deep-copied so they can be stomped.
2293 originalMethods = (old_method **)class_copyMethodList(original, &count);
2294 if (originalMethods) {
2295 duplicateMethods = (old_method_list *)
2296 calloc(sizeof(old_method_list) +
2297 (count-1)*sizeof(old_method), 1);
2298 duplicateMethods->obsolete = fixed_up_method_list;
2299 duplicateMethods->method_count = count;
2300 for (i = 0; i < count; i++) {
2301 duplicateMethods->method_list[i] = *(originalMethods[i]);
2303 duplicate->methodLists = (old_method_list **)duplicateMethods;
2304 duplicate->info |= CLS_NO_METHOD_ARRAY;
2305 free(originalMethods);
2308 mutex_locker_t lock(classLock);
2309 NXHashInsert(class_hash, duplicate);
2315 void objc_disposeClassPair(Class cls)
2317 if (!(cls->info & (CLS_CONSTRUCTED|CLS_CONSTRUCTING)) ||
2318 !(cls->ISA()->info & (CLS_CONSTRUCTED|CLS_CONSTRUCTING)))
2320 // class not allocated with objc_allocateClassPair
2321 // disposing still-unregistered class is OK!
2322 _objc_inform("objc_disposeClassPair: class '%s' was not "
2323 "allocated with objc_allocateClassPair!", cls->name);
2328 _objc_inform("objc_disposeClassPair: class '%s' is a metaclass, "
2329 "not a class!", cls->name);
2333 mutex_locker_t lock(classLock);
2334 NXHashRemove(class_hash, cls);
2335 unload_class(cls->ISA());
2340 /***********************************************************************
2341 * objc_constructInstance
2342 * Creates an instance of `cls` at the location pointed to by `bytes`.
2343 * `bytes` must point to at least class_getInstanceSize(cls) bytes of
2344 * well-aligned zero-filled memory.
2345 * The new object's isa is set. Any C++ constructors are called.
2346 * Returns `bytes` if successful. Returns nil if `cls` or `bytes` is
2347 * nil, or if C++ constructors fail.
2348 **********************************************************************/
2350 objc_constructInstance(Class cls, void *bytes)
2352 if (!cls || !bytes) return nil;
2358 if (cls->hasCxxCtor()) {
2359 return object_cxxConstructFromClass(obj, cls, OBJECT_CONSTRUCT_NONE);
2366 /***********************************************************************
2367 * _class_createInstanceFromZone. Allocate an instance of the
2368 * specified class with the specified number of bytes for indexed
2369 * variables, in the specified zone. The isa field is set to the
2370 * class, C++ default constructors are called, and all other fields are zeroed.
2371 **********************************************************************/
2373 _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone)
2378 // Can't create something for nothing
2379 if (!cls) return nil;
2381 // Allocate and initialize
2382 size = cls->alignedInstanceSize() + extraBytes;
2384 // CF requires all objects be at least 16 bytes.
2385 if (size < 16) size = 16;
2388 bytes = malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
2390 bytes = calloc(1, size);
2393 return objc_constructInstance(cls, bytes);
2397 /***********************************************************************
2398 * _class_createInstance. Allocate an instance of the specified
2399 * class with the specified number of bytes for indexed variables, in
2400 * the default zone, using _class_createInstanceFromZone.
2401 **********************************************************************/
2402 static id _class_createInstance(Class cls, size_t extraBytes)
2404 return _class_createInstanceFromZone (cls, extraBytes, nil);
2408 static id _object_copyFromZone(id oldObj, size_t extraBytes, void *zone)
2413 if (!oldObj) return nil;
2415 obj = (*_zoneAlloc)(oldObj->ISA(), extraBytes, zone);
2416 size = oldObj->ISA()->alignedInstanceSize() + extraBytes;
2418 // fixme need C++ copy constructor
2419 memmove(obj, oldObj, size);
2421 fixupCopiedIvars(obj, oldObj);
2427 /***********************************************************************
2428 * objc_destructInstance
2429 * Destroys an instance without freeing memory.
2430 * Calls C++ destructors.
2431 * Removes associative references.
2432 * Returns `obj`. Does nothing if `obj` is nil.
2433 * CoreFoundation and other clients do call this under GC.
2434 **********************************************************************/
2435 void *objc_destructInstance(id obj)
2438 Class isa = obj->getIsa();
2440 if (isa->hasCxxDtor()) {
2441 object_cxxDestruct(obj);
2444 if (isa->instancesHaveAssociatedObjects()) {
2445 _object_remove_assocations(obj);
2448 objc_clear_deallocating(obj);
2455 _object_dispose(id anObject)
2457 if (anObject==nil) return nil;
2459 objc_destructInstance(anObject);
2461 anObject->initIsa(_objc_getFreedObjectClass ());
2467 static id _object_copy(id oldObj, size_t extraBytes)
2469 void *z = malloc_zone_from_ptr(oldObj);
2470 return _object_copyFromZone(oldObj, extraBytes,
2471 z ? z : malloc_default_zone());
2474 static id _object_reallocFromZone(id anObject, size_t nBytes, void *zone)
2479 if (anObject == nil)
2480 __objc_error(nil, "reallocating nil object");
2482 if (anObject->ISA() == _objc_getFreedObjectClass ())
2483 __objc_error(anObject, "reallocating freed object");
2485 if (nBytes < anObject->ISA()->alignedInstanceSize())
2486 __objc_error(anObject, "(%s, %zu) requested size too small",
2487 object_getClassName(anObject), nBytes);
2489 // fixme need C++ copy constructor
2491 // Make sure not to modify space that has been declared free
2492 tmp = anObject->ISA();
2493 anObject->initIsa(_objc_getFreedObjectClass ());
2494 newObject = (id)malloc_zone_realloc((malloc_zone_t *)zone, anObject, nBytes);
2496 newObject->initIsa(tmp);
2498 // realloc failed, anObject is still alive
2499 anObject->initIsa(tmp);
2505 static id _object_realloc(id anObject, size_t nBytes)
2507 void *z = malloc_zone_from_ptr(anObject);
2508 return _object_reallocFromZone(anObject,
2510 z ? z : malloc_default_zone());
2513 id (*_alloc)(Class, size_t) = _class_createInstance;
2514 id (*_copy)(id, size_t) = _object_copy;
2515 id (*_realloc)(id, size_t) = _object_realloc;
2516 id (*_dealloc)(id) = _object_dispose;
2517 id (*_zoneAlloc)(Class, size_t, void *) = _class_createInstanceFromZone;
2518 id (*_zoneCopy)(id, size_t, void *) = _object_copyFromZone;
2519 id (*_zoneRealloc)(id, size_t, void *) = _object_reallocFromZone;
2520 void (*_error)(id, const char *, va_list) = _objc_error;
2523 id class_createInstance(Class cls, size_t extraBytes)
2525 return (*_alloc)(cls, extraBytes);
2528 id class_createInstanceFromZone(Class cls, size_t extraBytes, void *z)
2530 OBJC_WARN_DEPRECATED;
2531 return (*_zoneAlloc)(cls, extraBytes, z);
2535 _objc_rootAllocWithZone(Class cls, malloc_zone_t *zone)
2539 if (fastpath(!zone)) {
2540 obj = class_createInstance(cls, 0);
2542 obj = class_createInstanceFromZone(cls, 0, zone);
2545 if (slowpath(!obj)) obj = _objc_callBadAllocHandler(cls);
2549 unsigned class_createInstances(Class cls, size_t extraBytes,
2550 id *results, unsigned num_requested)
2552 if (_alloc == &_class_createInstance) {
2553 return _class_createInstancesFromZone(cls, extraBytes, nil,
2554 results, num_requested);
2556 // _alloc in use, which isn't understood by the batch allocator
2561 id object_copy(id obj, size_t extraBytes)
2563 return (*_copy)(obj, extraBytes);
2566 id object_copyFromZone(id obj, size_t extraBytes, void *z)
2568 OBJC_WARN_DEPRECATED;
2569 return (*_zoneCopy)(obj, extraBytes, z);
2572 id object_dispose(id obj)
2574 return (*_dealloc)(obj);
2577 id object_realloc(id obj, size_t nBytes)
2579 OBJC_WARN_DEPRECATED;
2580 return (*_realloc)(obj, nBytes);
2583 id object_reallocFromZone(id obj, size_t nBytes, void *z)
2585 OBJC_WARN_DEPRECATED;
2586 return (*_zoneRealloc)(obj, nBytes, z);
2590 /***********************************************************************
2591 * object_getIndexedIvars.
2592 **********************************************************************/
2593 void *object_getIndexedIvars(id obj)
2595 // ivars are tacked onto the end of the object
2596 if (!obj) return nil;
2597 if (obj->isTaggedPointer()) return nil;
2598 return ((char *) obj) + obj->ISA()->alignedInstanceSize();
2603 Class class_setSuperclass(Class cls, Class newSuper)
2605 Class oldSuper = cls->superclass;
2606 set_superclass(cls, newSuper, NO);
2607 flush_caches(cls, YES);