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 void flush_caches(Class cls, bool flush_meta);
42 // Freed objects have their isa set to point to this dummy class.
43 // This avoids the need to check for Nil classes in the messenger.
44 static const void* freedObjectClass[12] =
54 (Cache) &_objc_empty_cache, // cache
61 /***********************************************************************
62 * _class_getFreedObjectClass. Return a pointer to the dummy freed
63 * object class. Freed objects get their isa pointers replaced with
64 * a pointer to the freedObjectClass, so that we can catch usages of
66 **********************************************************************/
67 static Class _class_getFreedObjectClass(void)
69 return (Class)freedObjectClass;
73 /***********************************************************************
74 * _objc_getFreedObjectClass. Return a pointer to the dummy freed
75 * object class. Freed objects get their isa pointers replaced with
76 * a pointer to the freedObjectClass, so that we can catch usages of
78 **********************************************************************/
79 Class _objc_getFreedObjectClass(void)
81 return _class_getFreedObjectClass();
85 static void allocateExt(Class cls)
87 if (! (cls->info & CLS_EXT)) {
88 _objc_inform("class '%s' needs to be recompiled", cls->name);
92 uint32_t size = (uint32_t)sizeof(old_class_ext);
93 cls->ext = (old_class_ext *)calloc(size, 1);
94 cls->ext->size = size;
99 static inline old_method *_findNamedMethodInList(old_method_list * mlist, const char *meth_name) {
101 if (!mlist) return nil;
102 if (ignoreSelectorNamed(meth_name)) 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 * Also replaces imps for GC-ignored selectors
138 * The given method list must be non-nil and not already fixed-up.
139 * If the class was loaded from a bundle:
140 * fixes up the given list in place with heap-allocated selector strings
141 * If the class was not from a bundle:
142 * allocates a copy of the method list, fixes up the copy, and returns
143 * the copy. The given list is unmodified.
145 * If cls is already in use, methodListLock must be held by the caller.
146 **********************************************************************/
147 static old_method_list *fixupSelectorsInMethodList(Class cls, old_method_list *mlist)
152 old_method_list *old_mlist;
154 if ( ! mlist ) return nil;
155 if ( mlist->obsolete == fixed_up_method_list ) {
158 bool isBundle = cls->info & CLS_FROM_BUNDLE;
161 size = sizeof(old_method_list) - sizeof(old_method) + old_mlist->method_count * sizeof(old_method);
162 mlist = (old_method_list *)malloc(size);
163 memmove(mlist, old_mlist, size);
165 // Mach-O bundles are fixed up in place.
166 // This prevents leaks when a bundle is unloaded.
169 for ( i = 0; i < mlist->method_count; i += 1 ) {
170 method = &mlist->method_list[i];
171 method->method_name =
172 sel_registerNameNoLock((const char *)method->method_name, isBundle); // Always copy selector data from bundles.
174 if (ignoreSelector(method->method_name)) {
175 method->method_imp = (IMP)&_objc_ignored_method;
179 mlist->obsolete = fixed_up_method_list;
185 /***********************************************************************
187 * Returns successive method lists from the given class.
188 * Method lists are returned in method search order (i.e. highest-priority
189 * implementations first).
190 * All necessary method list fixups are performed, so the
191 * returned method list is fully-constructed.
193 * If cls is already in use, methodListLock must be held by the caller.
194 * For full thread-safety, methodListLock must be continuously held by the
195 * caller across all calls to nextMethodList(). If the lock is released,
196 * the bad results listed in class_nextMethodList() may occur.
198 * void *iterator = nil;
199 * old_method_list *mlist;
200 * mutex_locker_t lock(methodListLock);
201 * while ((mlist = nextMethodList(cls, &iterator))) {
202 * // do something with mlist
204 **********************************************************************/
205 static old_method_list *nextMethodList(Class cls,
208 uintptr_t index = *(uintptr_t *)it;
209 old_method_list **resultp;
212 // First call to nextMethodList.
213 if (!cls->methodLists) {
215 } else if (cls->info & CLS_NO_METHOD_ARRAY) {
216 resultp = (old_method_list **)&cls->methodLists;
218 resultp = &cls->methodLists[0];
219 if (!*resultp || *resultp == END_OF_METHODS_LIST) {
224 // Subsequent call to nextMethodList.
225 if (!cls->methodLists) {
227 } else if (cls->info & CLS_NO_METHOD_ARRAY) {
230 resultp = &cls->methodLists[index];
231 if (!*resultp || *resultp == END_OF_METHODS_LIST) {
237 // resultp now is nil, meaning there are no more method lists,
238 // OR the address of the method list pointer to fix up and return.
242 *resultp = fixupSelectorsInMethodList(cls, *resultp);
244 *it = (void *)(index + 1);
253 /* These next three functions are the heart of ObjC method lookup.
254 * If the class is currently in use, methodListLock must be held by the caller.
256 static inline old_method *_findMethodInList(old_method_list * mlist, SEL sel) {
258 if (!mlist) return nil;
259 for (i = 0; i < mlist->method_count; i++) {
260 old_method *m = &mlist->method_list[i];
261 if (m->method_name == sel) {
268 static inline old_method * _findMethodInClass(Class cls, SEL sel) __attribute__((always_inline));
269 static inline old_method * _findMethodInClass(Class cls, SEL sel) {
270 // Flattened version of nextMethodList(). The optimizer doesn't
271 // do a good job with hoisting the conditionals out of the loop.
272 // Conceptually, this looks like:
273 // while ((mlist = nextMethodList(cls, &iterator))) {
274 // old_method *m = _findMethodInList(mlist, sel);
278 if (!cls->methodLists) {
282 else if (cls->info & CLS_NO_METHOD_ARRAY) {
284 old_method_list **mlistp;
285 mlistp = (old_method_list **)&cls->methodLists;
286 *mlistp = fixupSelectorsInMethodList(cls, *mlistp);
287 return _findMethodInList(*mlistp, sel);
290 // Multiple method lists.
291 old_method_list **mlistp;
292 for (mlistp = cls->methodLists;
293 *mlistp != nil && *mlistp != END_OF_METHODS_LIST;
297 *mlistp = fixupSelectorsInMethodList(cls, *mlistp);
298 m = _findMethodInList(*mlistp, sel);
305 static inline old_method * _getMethod(Class cls, SEL sel) {
306 for (; cls; cls = cls->superclass) {
308 m = _findMethodInClass(cls, sel);
315 // fixme for gc debugging temporary use
316 IMP findIMPInClass(Class cls, SEL sel)
318 old_method *m = _findMethodInClass(cls, sel);
319 if (m) return m->method_imp;
324 /***********************************************************************
326 **********************************************************************/
327 static void _freedHandler(id obj, SEL sel)
329 __objc_error (obj, "message %s sent to freed object=%p",
330 sel_getName(sel), (void*)obj);
334 /***********************************************************************
336 * Log this method call. If the logger permits it, fill the method cache.
337 * cls is the method whose cache should be filled.
338 * implementer is the class that owns the implementation in question.
339 **********************************************************************/
341 log_and_fill_cache(Class cls, Class implementer, Method meth, SEL sel)
343 #if SUPPORT_MESSAGE_LOGGING
344 if (objcMsgLogEnabled) {
345 bool cacheIt = logMessageSend(implementer->isMetaClass(),
346 cls->nameForLogging(),
347 implementer->nameForLogging(),
349 if (!cacheIt) return;
352 _cache_fill (cls, meth, sel);
356 /***********************************************************************
357 * _class_lookupMethodAndLoadCache.
358 * Method lookup for dispatchers ONLY. OTHER CODE SHOULD USE lookUpImp().
359 * This lookup avoids optimistic cache scan because the dispatcher
360 * already tried that.
361 **********************************************************************/
362 IMP _class_lookupMethodAndLoadCache3(id obj, SEL sel, Class cls)
364 return lookUpImpOrForward(cls, sel, obj,
365 YES/*initialize*/, NO/*cache*/, YES/*resolver*/);
369 /***********************************************************************
370 * lookUpImpOrForward.
371 * The standard IMP lookup.
372 * initialize==NO tries to avoid +initialize (but sometimes fails)
373 * cache==NO skips optimistic unlocked lookup (but uses cache elsewhere)
374 * Most callers should use initialize==YES and cache==YES.
375 * inst is an instance of cls or a subclass thereof, or nil if none is known.
376 * If cls is an un-initialized metaclass then a non-nil inst is faster.
377 * May return _objc_msgForward_impcache. IMPs destined for external use
378 * must be converted to _objc_msgForward or _objc_msgForward_stret.
379 * If you don't want forwarding at all, use lookUpImpOrNil() instead.
380 **********************************************************************/
381 IMP lookUpImpOrForward(Class cls, SEL sel, id inst,
382 bool initialize, bool cache, bool resolver)
387 bool triedResolver = NO;
389 methodListLock.assertUnlocked();
391 // Optimistic cache lookup
393 methodPC = _cache_getImp(cls, sel);
394 if (methodPC) return methodPC;
397 // Check for freed class
398 if (cls == _class_getFreedObjectClass())
399 return (IMP) _freedHandler;
401 // Check for +initialize
402 if (initialize && !cls->isInitialized()) {
403 _class_initialize (_class_getNonMetaClass(cls, inst));
404 // If sel == initialize, _class_initialize will send +initialize and
405 // then the messenger will send +initialize again after this
406 // procedure finishes. Of course, if this is not being called
407 // from the messenger then it won't happen. 2778172
410 // The lock is held to make method-lookup + cache-fill atomic
411 // with respect to method addition. Otherwise, a category could
412 // be added but ignored indefinitely because the cache was re-filled
413 // with the old value after the cache flush on behalf of the category.
415 methodListLock.lock();
417 // Ignore GC selectors
418 if (ignoreSelector(sel)) {
419 methodPC = _cache_addIgnoredEntry(cls, sel);
423 // Try this class's cache.
425 methodPC = _cache_getImp(cls, sel);
426 if (methodPC) goto done;
428 // Try this class's method lists.
430 meth = _class_getMethodNoSuper_nolock(cls, sel);
432 log_and_fill_cache(cls, cls, meth, sel);
433 methodPC = method_getImplementation(meth);
437 // Try superclass caches and method lists.
440 while ((curClass = curClass->superclass)) {
442 meth = _cache_getMethod(curClass, sel, _objc_msgForward_impcache);
444 if (meth != (Method)1) {
445 // Found the method in a superclass. Cache it in this class.
446 log_and_fill_cache(cls, curClass, meth, sel);
447 methodPC = method_getImplementation(meth);
451 // Found a forward:: entry in a superclass.
452 // Stop searching, but don't cache yet; call method
453 // resolver for this class first.
458 // Superclass method list.
459 meth = _class_getMethodNoSuper_nolock(curClass, sel);
461 log_and_fill_cache(cls, curClass, meth, sel);
462 methodPC = method_getImplementation(meth);
467 // No implementation found. Try method resolver once.
469 if (resolver && !triedResolver) {
470 methodListLock.unlock();
471 _class_resolveMethod(cls, sel, inst);
476 // No implementation found, and method resolver didn't help.
479 _cache_addForwardEntry(cls, sel);
480 methodPC = _objc_msgForward_impcache;
483 methodListLock.unlock();
485 // paranoia: look for ignored selectors with non-ignored implementations
486 assert(!(ignoreSelector(sel) && methodPC != (IMP)&_objc_ignored_method));
492 /***********************************************************************
494 * Like lookUpImpOrForward, but returns nil instead of _objc_msgForward_impcache
495 **********************************************************************/
496 IMP lookUpImpOrNil(Class cls, SEL sel, id inst,
497 bool initialize, bool cache, bool resolver)
499 IMP imp = lookUpImpOrForward(cls, sel, inst, initialize, cache, resolver);
500 if (imp == _objc_msgForward_impcache) return nil;
505 /***********************************************************************
506 * lookupMethodInClassAndLoadCache.
507 * Like _class_lookupMethodAndLoadCache, but does not search superclasses.
508 * Caches and returns objc_msgForward if the method is not found in the class.
509 **********************************************************************/
510 IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel)
515 // fixme this still has the method list vs method cache race
516 // because it doesn't hold a lock across lookup+cache_fill,
517 // but it's only used for .cxx_construct/destruct and we assume
518 // categories don't change them.
520 // Search cache first.
521 imp = _cache_getImp(cls, sel);
524 // Cache miss. Search method list.
526 meth = _class_getMethodNoSuper(cls, sel);
529 // Hit in method list. Cache it.
530 _cache_fill(cls, meth, sel);
531 return method_getImplementation(meth);
533 // Miss in method list. Cache objc_msgForward.
534 _cache_addForwardEntry(cls, sel);
535 return _objc_msgForward_impcache;
540 /***********************************************************************
541 * class_getVariable. Return the named instance variable.
542 **********************************************************************/
544 Ivar _class_getVariable(Class cls, const char *name, Class *memberOf)
546 for (; cls != Nil; cls = cls->superclass) {
549 // Skip class having no ivars
550 if (!cls->ivars) continue;
552 for (i = 0; i < cls->ivars->ivar_count; i++) {
553 // Check this ivar's name. Be careful because the
554 // compiler generates ivar entries with nil ivar_name
555 // (e.g. for anonymous bit fields).
556 old_ivar *ivar = &cls->ivars->ivar_list[i];
557 if (ivar->ivar_name && 0 == strcmp(name, ivar->ivar_name)) {
558 if (memberOf) *memberOf = cls;
570 property_list_nth(const old_property_list *plist, uint32_t i)
572 return (old_property *)(i*plist->entsize + (char *)&plist->first);
576 copyPropertyList(old_property_list *plist, unsigned int *outCount)
578 old_property **result = nil;
579 unsigned int count = 0;
582 count = plist->count;
587 result = (old_property **)malloc((count+1) * sizeof(old_property *));
589 for (i = 0; i < count; i++) {
590 result[i] = property_list_nth(plist, i);
595 if (outCount) *outCount = count;
600 static old_property_list *
601 nextPropertyList(Class cls, uintptr_t *indexp)
603 old_property_list *result = nil;
605 classLock.assertLocked();
606 if (! ((cls->info & CLS_EXT) && cls->ext)) {
609 } else if (!cls->ext->propertyLists) {
612 } else if (cls->info & CLS_NO_PROPERTY_ARRAY) {
613 // Only one property list
615 result = (old_property_list *)cls->ext->propertyLists;
620 // More than one property list
621 result = cls->ext->propertyLists[*indexp];
634 /***********************************************************************
635 * class_getIvarLayout
636 * nil means all-scanned. "" means non-scanned.
637 **********************************************************************/
639 class_getIvarLayout(Class cls)
641 if (cls && (cls->info & CLS_EXT)) {
642 return cls->ivar_layout;
644 return nil; // conservative scan
649 /***********************************************************************
650 * class_getWeakIvarLayout
651 * nil means no weak ivars.
652 **********************************************************************/
654 class_getWeakIvarLayout(Class cls)
656 if (cls && (cls->info & CLS_EXT) && cls->ext) {
657 return cls->ext->weak_ivar_layout;
659 return nil; // no weak ivars
664 /***********************************************************************
665 * class_setIvarLayout
666 * nil means all-scanned. "" means non-scanned.
667 **********************************************************************/
668 void class_setIvarLayout(Class cls, const uint8_t *layout)
672 if (! (cls->info & CLS_EXT)) {
673 _objc_inform("class '%s' needs to be recompiled", cls->name);
678 cls->ivar_layout = ustrdupMaybeNil(layout);
681 // SPI: Instance-specific object layout.
683 void _class_setIvarLayoutAccessor(Class cls, const uint8_t* (*accessor) (id object)) {
686 if (! (cls->info & CLS_EXT)) {
687 _objc_inform("class '%s' needs to be recompiled", cls->name);
692 cls->ivar_layout = (const uint8_t *)accessor;
693 cls->setInfo(CLS_HAS_INSTANCE_SPECIFIC_LAYOUT);
696 const uint8_t *_object_getIvarLayout(Class cls, id object) {
697 if (cls && (cls->info & CLS_EXT)) {
698 const uint8_t* layout = cls->ivar_layout;
699 if (cls->info & CLS_HAS_INSTANCE_SPECIFIC_LAYOUT) {
700 const uint8_t* (*accessor) (id object) = (const uint8_t* (*)(id))layout;
701 layout = accessor(object);
709 /***********************************************************************
710 * class_setWeakIvarLayout
711 * nil means no weak ivars.
712 **********************************************************************/
713 void class_setWeakIvarLayout(Class cls, const uint8_t *layout)
717 mutex_locker_t lock(classLock);
722 cls->ext->weak_ivar_layout = ustrdupMaybeNil(layout);
726 /***********************************************************************
727 * class_setVersion. Record the specified version with the class.
728 **********************************************************************/
729 void class_setVersion(Class cls, int version)
732 cls->version = version;
735 /***********************************************************************
736 * class_getVersion. Return the version recorded with the class.
737 **********************************************************************/
738 int class_getVersion(Class cls)
741 return (int)cls->version;
745 /***********************************************************************
747 **********************************************************************/
748 const char *class_getName(Class cls)
750 if (!cls) return "nil";
751 else return cls->demangledName();
755 /***********************************************************************
756 * _class_getNonMetaClass.
757 * Return the ordinary class for this class or metaclass.
758 * Used by +initialize.
759 **********************************************************************/
760 Class _class_getNonMetaClass(Class cls, id obj)
763 if (cls->isMetaClass()) {
764 if (cls->info & CLS_CONSTRUCTING) {
765 // Class is under construction and isn't in the class_hash,
766 // so objc_getClass doesn't work.
767 cls = obj; // fixme this may be nil in some paths
769 else if (strncmp(cls->name, "_%", 2) == 0) {
770 // Posee's meta's name is smashed and isn't in the class_hash,
771 // so objc_getClass doesn't work.
772 const char *baseName = strchr(cls->name, '%'); // get posee's real name
773 cls = objc_getClass(baseName);
776 cls = objc_getClass(cls->name);
785 Cache _class_getCache(Class cls)
790 void _class_setCache(Class cls, Cache cache)
795 const char *_category_getName(Category cat)
797 return oldcategory(cat)->category_name;
800 const char *_category_getClassName(Category cat)
802 return oldcategory(cat)->class_name;
805 Class _category_getClass(Category cat)
807 return objc_getClass(oldcategory(cat)->class_name);
810 IMP _category_getLoadMethod(Category cat)
812 old_method_list *mlist = oldcategory(cat)->class_methods;
814 return lookupNamedMethodInMethodList(mlist, "load");
822 /***********************************************************************
823 * class_nextMethodList.
824 * External version of nextMethodList().
826 * This function is not fully thread-safe. A series of calls to
827 * class_nextMethodList() may fail if methods are added to or removed
828 * from the class between calls.
829 * If methods are added between calls to class_nextMethodList(), it may
830 * return previously-returned method lists again, and may fail to return
832 * If methods are removed between calls to class_nextMethodList(), it may
833 * omit surviving method lists or simply crash.
834 **********************************************************************/
835 OBJC_EXPORT struct objc_method_list *class_nextMethodList(Class cls, void **it)
837 OBJC_WARN_DEPRECATED;
839 mutex_locker_t lock(methodListLock);
840 return (struct objc_method_list *) nextMethodList(cls, it);
844 /***********************************************************************
847 * Formerly class_addInstanceMethods ()
848 **********************************************************************/
849 OBJC_EXPORT void class_addMethods(Class cls, struct objc_method_list *meths)
851 OBJC_WARN_DEPRECATED;
855 mutex_locker_t lock(methodListLock);
856 _objc_insertMethods(cls, (old_method_list *)meths, nil);
859 // Must flush when dynamically adding methods. No need to flush
860 // all the class method caches. If cls is a meta class, though,
861 // this will still flush it and any of its sub-meta classes.
862 flush_caches (cls, NO);
866 /***********************************************************************
867 * class_removeMethods.
868 **********************************************************************/
869 OBJC_EXPORT void class_removeMethods(Class cls, struct objc_method_list *meths)
871 OBJC_WARN_DEPRECATED;
873 // Remove the methods
875 mutex_locker_t lock(methodListLock);
876 _objc_removeMethods(cls, (old_method_list *)meths);
879 // Must flush when dynamically removing methods. No need to flush
880 // all the class method caches. If cls is a meta class, though,
881 // this will still flush it and any of its sub-meta classes.
882 flush_caches (cls, NO);
885 /***********************************************************************
886 * lookupNamedMethodInMethodList
887 * Only called to find +load/-.cxx_construct/-.cxx_destruct methods,
888 * without fixing up the entire method list.
889 * The class is not yet in use, so methodListLock is not taken.
890 **********************************************************************/
891 IMP lookupNamedMethodInMethodList(old_method_list *mlist, const char *meth_name)
894 m = meth_name ? _findNamedMethodInList(mlist, meth_name) : nil;
895 return (m ? m->method_imp : nil);
898 static Method _class_getMethod(Class cls, SEL sel)
900 mutex_locker_t lock(methodListLock);
901 return (Method)_getMethod(cls, sel);
904 static Method _class_getMethodNoSuper(Class cls, SEL sel)
906 mutex_locker_t lock(methodListLock);
907 return (Method)_findMethodInClass(cls, sel);
910 static Method _class_getMethodNoSuper_nolock(Class cls, SEL sel)
912 methodListLock.assertLocked();
913 return (Method)_findMethodInClass(cls, sel);
917 /***********************************************************************
918 * class_getInstanceMethod. Return the instance method for the
919 * specified class and selector.
920 **********************************************************************/
921 Method class_getInstanceMethod(Class cls, SEL sel)
923 if (!cls || !sel) return nil;
925 // This deliberately avoids +initialize because it historically did so.
927 // This implementation is a bit weird because it's the only place that
928 // wants a Method instead of an IMP.
931 meth = _cache_getMethod(cls, sel, _objc_msgForward_impcache);
932 if (meth == (Method)1) {
933 // Cache contains forward:: . Stop searching.
939 // Search method lists, try method resolver, etc.
940 lookUpImpOrNil(cls, sel, nil,
941 NO/*initialize*/, NO/*cache*/, YES/*resolver*/);
943 meth = _cache_getMethod(cls, sel, _objc_msgForward_impcache);
944 if (meth == (Method)1) {
945 // Cache contains forward:: . Stop searching.
951 return _class_getMethod(cls, sel);
955 BOOL class_conformsToProtocol(Class cls, Protocol *proto_gen)
957 old_protocol *proto = oldprotocol(proto_gen);
960 if (!proto) return NO;
962 if (cls->ISA()->version >= 3) {
963 old_protocol_list *list;
964 for (list = cls->protocols; list != nil; list = list->next) {
966 for (i = 0; i < list->count; i++) {
967 if (list->list[i] == proto) return YES;
968 if (protocol_conformsToProtocol((Protocol *)list->list[i], proto_gen)) return YES;
970 if (cls->ISA()->version <= 4) break;
977 static NXMapTable * posed_class_hash = nil;
979 /***********************************************************************
981 **********************************************************************/
983 Class _objc_getOrigClass(const char *name)
985 // Look for class among the posers
987 mutex_locker_t lock(classLock);
988 if (posed_class_hash) {
989 Class cls = (Class) NXMapGet (posed_class_hash, name);
994 // Not a poser. Do a normal lookup.
995 Class cls = objc_getClass (name);
998 _objc_inform ("class `%s' not linked into application", name);
1002 Class objc_getOrigClass(const char *name)
1004 OBJC_WARN_DEPRECATED;
1005 return _objc_getOrigClass(name);
1008 /***********************************************************************
1009 * _objc_addOrigClass. This function is only used from class_poseAs.
1010 * Registers the original class names, before they get obscured by
1011 * posing, so that [super ..] will work correctly from categories
1012 * in posing classes and in categories in classes being posed for.
1013 **********************************************************************/
1014 static void _objc_addOrigClass (Class origClass)
1016 mutex_locker_t lock(classLock);
1018 // Create the poser's hash table on first use
1019 if (!posed_class_hash)
1021 posed_class_hash = NXCreateMapTable(NXStrValueMapPrototype, 8);
1024 // Add the named class iff it is not already there (or collides?)
1025 if (NXMapGet (posed_class_hash, origClass->name) == 0)
1026 NXMapInsert (posed_class_hash, origClass->name, origClass);
1030 /***********************************************************************
1031 * change_class_references
1032 * Change classrefs and superclass pointers from original to imposter
1033 * But if copy!=nil, don't change copy->superclass.
1034 * If changeSuperRefs==YES, also change [super message] classrefs.
1035 * Used by class_poseAs and objc_setFutureClass
1036 * classLock must be locked.
1037 **********************************************************************/
1038 void change_class_references(Class imposter,
1041 bool changeSuperRefs)
1047 // Change all subclasses of the original to point to the imposter.
1048 state = NXInitHashState (class_hash);
1049 while (NXNextHashState (class_hash, &state, (void **) &clsObject))
1051 while ((clsObject) && (clsObject != imposter) &&
1052 (clsObject != copy))
1054 if (clsObject->superclass == original)
1056 clsObject->superclass = imposter;
1057 clsObject->ISA()->superclass = imposter->ISA();
1058 // We must flush caches here!
1062 clsObject = clsObject->superclass;
1066 // Replace the original with the imposter in all class refs
1067 // Major loop - process all headers
1068 for (hInfo = FirstHeader; hInfo != nil; hInfo = hInfo->next)
1074 // Fix class refs associated with this header
1075 cls_refs = _getObjcClassRefs(hInfo, &refCount);
1077 for (index = 0; index < refCount; index += 1) {
1078 if (cls_refs[index] == original) {
1079 cls_refs[index] = imposter;
1087 /***********************************************************************
1090 * !!! class_poseAs () does not currently flush any caches.
1091 **********************************************************************/
1092 Class class_poseAs(Class imposter, Class original)
1094 char * imposterNamePtr;
1097 OBJC_WARN_DEPRECATED;
1099 // Trivial case is easy
1100 if (imposter == original)
1103 // Imposter must be an immediate subclass of the original
1104 if (imposter->superclass != original) {
1105 __objc_error(imposter,
1106 "[%s poseAs:%s]: target not immediate superclass",
1107 imposter->name, original->name);
1110 // Can't pose when you have instance variables (how could it work?)
1111 if (imposter->ivars) {
1112 __objc_error(imposter,
1113 "[%s poseAs:%s]: %s defines new instance variables",
1114 imposter->name, original->name, imposter->name);
1117 // Build a string to use to replace the name of the original class.
1119 # define imposterNamePrefix "_%"
1120 imposterNamePtr = malloc(strlen(original->name) + strlen(imposterNamePrefix) + 1);
1121 strcpy(imposterNamePtr, imposterNamePrefix);
1122 strcat(imposterNamePtr, original->name);
1123 # undef imposterNamePrefix
1125 asprintf(&imposterNamePtr, "_%%%s", original->name);
1128 // We lock the class hashtable, so we are thread safe with respect to
1129 // calls to objc_getClass (). However, the class names are not
1130 // changed atomically, nor are all of the subclasses updated
1131 // atomically. I have ordered the operations so that you will
1132 // never crash, but you may get inconsistent results....
1134 // Register the original class so that [super ..] knows
1135 // exactly which classes are the "original" classes.
1136 _objc_addOrigClass (original);
1137 _objc_addOrigClass (imposter);
1139 // Copy the imposter, so that the imposter can continue
1140 // its normal life in addition to changing the behavior of
1141 // the original. As a hack we don't bother to copy the metaclass.
1142 // For some reason we modify the original rather than the copy.
1143 copy = (Class)malloc(sizeof(objc_class));
1144 memmove(copy, imposter, sizeof(objc_class));
1146 mutex_locker_t lock(classLock);
1148 // Remove both the imposter and the original class.
1149 NXHashRemove (class_hash, imposter);
1150 NXHashRemove (class_hash, original);
1152 NXHashInsert (class_hash, copy);
1153 objc_addRegisteredClass(copy); // imposter & original will rejoin later, just track the new guy
1155 // Mark the imposter as such
1156 imposter->setInfo(CLS_POSING);
1157 imposter->ISA()->setInfo(CLS_POSING);
1159 // Change the name of the imposter to that of the original class.
1160 imposter->name = original->name;
1161 imposter->ISA()->name = original->ISA()->name;
1163 // Also copy the version field to avoid archiving problems.
1164 imposter->version = original->version;
1166 // Change classrefs and superclass pointers
1167 // Don't change copy->superclass
1168 // Don't change [super ...] messages
1169 change_class_references(imposter, original, copy, NO);
1171 // Change the name of the original class.
1172 original->name = imposterNamePtr + 1;
1173 original->ISA()->name = imposterNamePtr;
1175 // Restore the imposter and the original class with their new names.
1176 NXHashInsert (class_hash, imposter);
1177 NXHashInsert (class_hash, original);
1183 /***********************************************************************
1184 * _objc_flush_caches. Flush the instance and class method caches
1185 * of cls and all its subclasses.
1187 * Specifying Nil for the class "all classes."
1188 **********************************************************************/
1189 static void flush_caches(Class target, bool flush_meta)
1191 bool collectALot = (target == nil);
1194 #ifdef OBJC_INSTRUMENTED
1195 unsigned int classesVisited;
1196 unsigned int subclassCount;
1199 mutex_locker_t lock(classLock);
1200 mutex_locker_t lock2(cacheUpdateLock);
1202 // Leaf classes are fastest because there are no subclass caches to flush.
1204 if (target && (target->info & CLS_LEAF)) {
1205 _cache_flush (target);
1207 if (target->ISA() && (target->ISA()->info & CLS_LEAF)) {
1208 _cache_flush (target->ISA());
1211 // Reset target and handle it by one of the methods below.
1212 target = target->ISA();
1218 state = NXInitHashState(class_hash);
1220 // Handle nil and root instance class specially: flush all
1221 // instance and class method caches. Nice that this
1222 // loop is linear vs the N-squared loop just below.
1223 if (!target || !target->superclass)
1225 #ifdef OBJC_INSTRUMENTED
1226 LinearFlushCachesCount += 1;
1230 // Traverse all classes in the hash table
1231 while (NXNextHashState(class_hash, &state, (void**)&clsObject))
1233 Class metaClsObject;
1234 #ifdef OBJC_INSTRUMENTED
1235 classesVisited += 1;
1238 // Skip class that is known not to be a subclass of this root
1239 // (the isa pointer of any meta class points to the meta class
1241 // NOTE: When is an isa pointer of a hash tabled class ever nil?
1242 metaClsObject = clsObject->ISA();
1243 if (target && metaClsObject && target->ISA() != metaClsObject->ISA()) {
1247 #ifdef OBJC_INSTRUMENTED
1251 _cache_flush (clsObject);
1252 if (flush_meta && metaClsObject != nil) {
1253 _cache_flush (metaClsObject);
1256 #ifdef OBJC_INSTRUMENTED
1257 LinearFlushCachesVisitedCount += classesVisited;
1258 if (classesVisited > MaxLinearFlushCachesVisitedCount)
1259 MaxLinearFlushCachesVisitedCount = classesVisited;
1260 IdealFlushCachesCount += subclassCount;
1261 if (subclassCount > MaxIdealFlushCachesCount)
1262 MaxIdealFlushCachesCount = subclassCount;
1268 // Outer loop - flush any cache that could now get a method from
1269 // cls (i.e. the cache associated with cls and any of its subclasses).
1270 #ifdef OBJC_INSTRUMENTED
1271 NonlinearFlushCachesCount += 1;
1275 while (NXNextHashState(class_hash, &state, (void**)&clsObject))
1279 #ifdef OBJC_INSTRUMENTED
1280 NonlinearFlushCachesClassCount += 1;
1283 // Inner loop - Process a given class
1284 clsIter = clsObject;
1288 #ifdef OBJC_INSTRUMENTED
1289 classesVisited += 1;
1291 // Flush clsObject instance method cache if
1292 // clsObject is a subclass of cls, or is cls itself
1293 // Flush the class method cache if that was asked for
1294 if (clsIter == target)
1296 #ifdef OBJC_INSTRUMENTED
1299 _cache_flush (clsObject);
1301 _cache_flush (clsObject->ISA());
1307 // Flush clsObject class method cache if cls is
1308 // the meta class of clsObject or of one
1309 // of clsObject's superclasses
1310 else if (clsIter->ISA() == target)
1312 #ifdef OBJC_INSTRUMENTED
1315 _cache_flush (clsObject->ISA());
1319 // Move up superclass chain
1320 // else if (clsIter->isInitialized())
1321 clsIter = clsIter->superclass;
1323 // clsIter is not initialized, so its cache
1324 // must be empty. This happens only when
1325 // clsIter == clsObject, because
1326 // superclasses are initialized before
1327 // subclasses, and this loop traverses
1328 // from sub- to super- classes.
1333 #ifdef OBJC_INSTRUMENTED
1334 NonlinearFlushCachesVisitedCount += classesVisited;
1335 if (classesVisited > MaxNonlinearFlushCachesVisitedCount)
1336 MaxNonlinearFlushCachesVisitedCount = classesVisited;
1337 IdealFlushCachesCount += subclassCount;
1338 if (subclassCount > MaxIdealFlushCachesCount)
1339 MaxIdealFlushCachesCount = subclassCount;
1345 _cache_collect(true);
1350 void _objc_flush_caches(Class target)
1352 flush_caches(target, YES);
1357 /***********************************************************************
1358 * flush_marked_caches. Flush the method cache of any class marked
1359 * CLS_FLUSH_CACHE (and all subclasses thereof)
1361 **********************************************************************/
1362 void flush_marked_caches(void)
1368 mutex_locker_t lock(classLock);
1369 mutex_locker_t lock2(cacheUpdateLock);
1371 state = NXInitHashState(class_hash);
1372 while (NXNextHashState(class_hash, &state, (void**)&cls)) {
1373 for (supercls = cls; supercls; supercls = supercls->superclass) {
1374 if (supercls->info & CLS_FLUSH_CACHE) {
1380 for (supercls = cls->ISA(); supercls; supercls = supercls->superclass) {
1381 if (supercls->info & CLS_FLUSH_CACHE) {
1382 _cache_flush(cls->ISA());
1388 state = NXInitHashState(class_hash);
1389 while (NXNextHashState(class_hash, &state, (void**)&cls)) {
1390 if (cls->info & CLS_FLUSH_CACHE) {
1391 cls->clearInfo(CLS_FLUSH_CACHE);
1393 if (cls->ISA()->info & CLS_FLUSH_CACHE) {
1394 cls->ISA()->clearInfo(CLS_FLUSH_CACHE);
1400 /***********************************************************************
1401 * get_base_method_list
1402 * Returns the method list containing the class's own methods,
1403 * ignoring any method lists added by categories or class_addMethods.
1404 * Called only by add_class_to_loadable_list.
1405 * Does not hold methodListLock because add_class_to_loadable_list
1406 * does not manipulate in-use classes.
1407 **********************************************************************/
1408 static old_method_list *get_base_method_list(Class cls)
1410 old_method_list **ptr;
1412 if (!cls->methodLists) return nil;
1413 if (cls->info & CLS_NO_METHOD_ARRAY) return (old_method_list *)cls->methodLists;
1414 ptr = cls->methodLists;
1415 if (!*ptr || *ptr == END_OF_METHODS_LIST) return nil;
1416 while ( *ptr != 0 && *ptr != END_OF_METHODS_LIST ) { ptr++; }
1422 static IMP _class_getLoadMethod_nocheck(Class cls)
1424 old_method_list *mlist;
1425 mlist = get_base_method_list(cls->ISA());
1427 return lookupNamedMethodInMethodList (mlist, "load");
1433 bool _class_hasLoadMethod(Class cls)
1435 if (cls->ISA()->info & CLS_HAS_LOAD_METHOD) return YES;
1436 return _class_getLoadMethod_nocheck(cls);
1440 /***********************************************************************
1441 * objc_class::getLoadMethod
1442 * Returns cls's +load implementation, or nil if it doesn't have one.
1443 **********************************************************************/
1444 IMP objc_class::getLoadMethod()
1446 if (ISA()->info & CLS_HAS_LOAD_METHOD) {
1447 return _class_getLoadMethod_nocheck((Class)this);
1452 BOOL _class_usesAutomaticRetainRelease(Class cls)
1457 uint32_t _class_getInstanceStart(Class cls)
1459 _objc_fatal("_class_getInstanceStart() unimplemented for fragile instance variables");
1460 return 0; // PCB: never used just provided for ARR consistency.
1463 ptrdiff_t ivar_getOffset(Ivar ivar)
1465 return oldivar(ivar)->ivar_offset;
1468 const char *ivar_getName(Ivar ivar)
1470 return oldivar(ivar)->ivar_name;
1473 const char *ivar_getTypeEncoding(Ivar ivar)
1475 return oldivar(ivar)->ivar_type;
1479 IMP method_getImplementation(Method m)
1482 return oldmethod(m)->method_imp;
1485 SEL method_getName(Method m)
1488 return oldmethod(m)->method_name;
1491 const char *method_getTypeEncoding(Method m)
1494 return oldmethod(m)->method_types;
1497 unsigned int method_getSizeOfArguments(Method m)
1499 OBJC_WARN_DEPRECATED;
1501 return encoding_getSizeOfArguments(method_getTypeEncoding(m));
1504 unsigned int method_getArgumentInfo(Method m, int arg,
1505 const char **type, int *offset)
1507 OBJC_WARN_DEPRECATED;
1509 return encoding_getArgumentInfo(method_getTypeEncoding(m),
1514 static spinlock_t impLock;
1516 IMP method_setImplementation(Method m_gen, IMP imp)
1519 old_method *m = oldmethod(m_gen);
1521 if (!imp) return nil;
1523 if (ignoreSelector(m->method_name)) {
1524 // Ignored methods stay ignored
1525 return m->method_imp;
1529 old = m->method_imp;
1530 m->method_imp = imp;
1536 void method_exchangeImplementations(Method m1_gen, Method m2_gen)
1539 old_method *m1 = oldmethod(m1_gen);
1540 old_method *m2 = oldmethod(m2_gen);
1541 if (!m1 || !m2) return;
1543 if (ignoreSelector(m1->method_name) || ignoreSelector(m2->method_name)) {
1544 // Ignored methods stay ignored. Now they're both ignored.
1545 m1->method_imp = (IMP)&_objc_ignored_method;
1546 m2->method_imp = (IMP)&_objc_ignored_method;
1551 m1_imp = m1->method_imp;
1552 m1->method_imp = m2->method_imp;
1553 m2->method_imp = m1_imp;
1558 struct objc_method_description * method_getDescription(Method m)
1561 return (struct objc_method_description *)oldmethod(m);
1565 const char *property_getName(objc_property_t prop)
1567 return oldproperty(prop)->name;
1570 const char *property_getAttributes(objc_property_t prop)
1572 return oldproperty(prop)->attributes;
1575 objc_property_attribute_t *property_copyAttributeList(objc_property_t prop,
1576 unsigned int *outCount)
1579 if (outCount) *outCount = 0;
1583 mutex_locker_t lock(classLock);
1584 return copyPropertyAttributeList(oldproperty(prop)->attributes,outCount);
1587 char * property_copyAttributeValue(objc_property_t prop, const char *name)
1589 if (!prop || !name || *name == '\0') return nil;
1591 mutex_locker_t lock(classLock);
1592 return copyPropertyAttributeValue(oldproperty(prop)->attributes, name);
1596 /***********************************************************************
1598 **********************************************************************/
1599 static IMP _class_addMethod(Class cls, SEL name, IMP imp,
1600 const char *types, bool replace)
1605 if (!types) types = "";
1607 mutex_locker_t lock(methodListLock);
1609 if ((m = _findMethodInClass(cls, name))) {
1612 result = method_getImplementation((Method)m);
1614 method_setImplementation((Method)m, imp);
1617 // fixme could be faster
1618 old_method_list *mlist =
1619 (old_method_list *)calloc(sizeof(old_method_list), 1);
1620 mlist->obsolete = fixed_up_method_list;
1621 mlist->method_count = 1;
1622 mlist->method_list[0].method_name = name;
1623 mlist->method_list[0].method_types = strdup(types);
1624 if (!ignoreSelector(name)) {
1625 mlist->method_list[0].method_imp = imp;
1627 mlist->method_list[0].method_imp = (IMP)&_objc_ignored_method;
1630 _objc_insertMethods(cls, mlist, nil);
1631 if (!(cls->info & CLS_CONSTRUCTING)) {
1632 flush_caches(cls, NO);
1634 // in-construction class has no subclasses
1644 /***********************************************************************
1646 **********************************************************************/
1647 BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
1650 if (!cls) return NO;
1652 old = _class_addMethod(cls, name, imp, types, NO);
1657 /***********************************************************************
1658 * class_replaceMethod
1659 **********************************************************************/
1660 IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
1662 if (!cls) return nil;
1664 return _class_addMethod(cls, name, imp, types, YES);
1668 /***********************************************************************
1670 **********************************************************************/
1671 BOOL class_addIvar(Class cls, const char *name, size_t size,
1672 uint8_t alignment, const char *type)
1676 if (!cls) return NO;
1677 if (ISMETA(cls)) return NO;
1678 if (!(cls->info & CLS_CONSTRUCTING)) return NO;
1680 if (!type) type = "";
1681 if (name && 0 == strcmp(name, "")) name = nil;
1683 mutex_locker_t lock(classLock);
1685 // Check for existing ivar with this name
1686 // fixme check superclasses?
1689 for (i = 0; i < cls->ivars->ivar_count; i++) {
1690 if (0 == strcmp(cls->ivars->ivar_list[i].ivar_name, name)) {
1698 old_ivar_list *old = cls->ivars;
1706 oldSize = sizeof(old_ivar_list) +
1707 (old->ivar_count - 1) * sizeof(old_ivar);
1708 newCount = 1 + old->ivar_count;
1710 oldSize = sizeof(old_ivar_list) - sizeof(old_ivar);
1714 // allocate new ivar list
1715 cls->ivars = (old_ivar_list *)
1716 calloc(oldSize+sizeof(old_ivar), 1);
1717 if (old) memcpy(cls->ivars, old, oldSize);
1718 if (old && malloc_size(old)) free(old);
1719 cls->ivars->ivar_count = newCount;
1720 ivar = &cls->ivars->ivar_list[newCount-1];
1722 // set ivar name and type
1723 ivar->ivar_name = strdup(name);
1724 ivar->ivar_type = strdup(type);
1726 // align if necessary
1727 alignBytes = 1 << alignment;
1728 misalign = cls->instance_size % alignBytes;
1729 if (misalign) cls->instance_size += (long)(alignBytes - misalign);
1731 // set ivar offset and increase instance size
1732 ivar->ivar_offset = (int)cls->instance_size;
1733 cls->instance_size += (long)size;
1740 /***********************************************************************
1742 **********************************************************************/
1743 BOOL class_addProtocol(Class cls, Protocol *protocol_gen)
1745 old_protocol *protocol = oldprotocol(protocol_gen);
1746 old_protocol_list *plist;
1748 if (!cls) return NO;
1749 if (class_conformsToProtocol(cls, protocol_gen)) return NO;
1751 mutex_locker_t lock(classLock);
1753 // fixme optimize - protocol list doesn't escape?
1754 plist = (old_protocol_list*)calloc(sizeof(old_protocol_list), 1);
1756 plist->list[0] = protocol;
1757 plist->next = cls->protocols;
1758 cls->protocols = plist;
1766 /***********************************************************************
1767 * _class_addProperties
1768 * Internal helper to add properties to a class.
1769 * Used by category attachment and class_addProperty()
1770 * Locking: acquires classLock
1771 **********************************************************************/
1773 _class_addProperties(Class cls,
1774 old_property_list *additions)
1776 old_property_list *newlist;
1778 if (!(cls->info & CLS_EXT)) return NO;
1780 newlist = (old_property_list *)
1781 memdup(additions, sizeof(*newlist) - sizeof(newlist->first)
1782 + (additions->entsize * additions->count));
1784 mutex_locker_t lock(classLock);
1787 if (!cls->ext->propertyLists) {
1788 // cls has no properties - simply use this list
1789 cls->ext->propertyLists = (old_property_list **)newlist;
1790 cls->setInfo(CLS_NO_PROPERTY_ARRAY);
1792 else if (cls->info & CLS_NO_PROPERTY_ARRAY) {
1793 // cls has one property list - make a new array
1794 old_property_list **newarray = (old_property_list **)
1795 malloc(3 * sizeof(*newarray));
1796 newarray[0] = newlist;
1797 newarray[1] = (old_property_list *)cls->ext->propertyLists;
1799 cls->ext->propertyLists = newarray;
1800 cls->clearInfo(CLS_NO_PROPERTY_ARRAY);
1803 // cls has a property array - make a bigger one
1804 old_property_list **newarray;
1806 while (cls->ext->propertyLists[count]) count++;
1807 newarray = (old_property_list **)
1808 malloc((count+2) * sizeof(*newarray));
1809 newarray[0] = newlist;
1810 memcpy(&newarray[1], &cls->ext->propertyLists[0],
1811 count * sizeof(*newarray));
1812 newarray[count+1] = nil;
1813 free(cls->ext->propertyLists);
1814 cls->ext->propertyLists = newarray;
1821 /***********************************************************************
1823 * Adds a property to a class. Returns NO if the proeprty already exists.
1824 * Locking: acquires classLock
1825 **********************************************************************/
1827 _class_addProperty(Class cls, const char *name,
1828 const objc_property_attribute_t *attrs, unsigned int count,
1831 if (!cls) return NO;
1832 if (!name) return NO;
1834 old_property *prop = oldproperty(class_getProperty(cls, name));
1835 if (prop && !replace) {
1836 // already exists, refuse to replace
1841 mutex_locker_t lock(classLock);
1842 try_free(prop->attributes);
1843 prop->attributes = copyPropertyAttributeString(attrs, count);
1848 old_property_list proplist;
1849 proplist.entsize = sizeof(old_property);
1851 proplist.first.name = strdup(name);
1852 proplist.first.attributes = copyPropertyAttributeString(attrs, count);
1854 return _class_addProperties(cls, &proplist);
1859 class_addProperty(Class cls, const char *name,
1860 const objc_property_attribute_t *attrs, unsigned int n)
1862 return _class_addProperty(cls, name, attrs, n, NO);
1866 class_replaceProperty(Class cls, const char *name,
1867 const objc_property_attribute_t *attrs, unsigned int n)
1869 _class_addProperty(cls, name, attrs, n, YES);
1873 /***********************************************************************
1874 * class_copyProtocolList. Returns a heap block containing the
1875 * protocols implemented by the class, or nil if the class
1876 * implements no protocols. Caller must free the block.
1877 * Does not copy any superclass's protocols.
1878 **********************************************************************/
1879 Protocol * __unsafe_unretained *
1880 class_copyProtocolList(Class cls, unsigned int *outCount)
1882 old_protocol_list *plist;
1883 Protocol **result = nil;
1884 unsigned int count = 0;
1888 if (outCount) *outCount = 0;
1892 mutex_locker_t lock(classLock);
1894 for (plist = cls->protocols; plist != nil; plist = plist->next) {
1895 count += (int)plist->count;
1899 result = (Protocol **)malloc((count+1) * sizeof(Protocol *));
1901 for (p = 0, plist = cls->protocols;
1903 plist = plist->next)
1906 for (i = 0; i < plist->count; i++) {
1907 result[p++] = (Protocol *)plist->list[i];
1913 if (outCount) *outCount = count;
1918 /***********************************************************************
1919 * class_getProperty. Return the named property.
1920 **********************************************************************/
1921 objc_property_t class_getProperty(Class cls, const char *name)
1923 if (!cls || !name) return nil;
1925 mutex_locker_t lock(classLock);
1927 for (; cls; cls = cls->superclass) {
1928 uintptr_t iterator = 0;
1929 old_property_list *plist;
1930 while ((plist = nextPropertyList(cls, &iterator))) {
1932 for (i = 0; i < plist->count; i++) {
1933 old_property *p = property_list_nth(plist, i);
1934 if (0 == strcmp(name, p->name)) {
1935 return (objc_property_t)p;
1945 /***********************************************************************
1946 * class_copyPropertyList. Returns a heap block containing the
1947 * properties declared in the class, or nil if the class
1948 * declares no properties. Caller must free the block.
1949 * Does not copy any superclass's properties.
1950 **********************************************************************/
1951 objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
1953 old_property_list *plist;
1954 uintptr_t iterator = 0;
1955 old_property **result = nil;
1956 unsigned int count = 0;
1960 if (outCount) *outCount = 0;
1964 mutex_locker_t lock(classLock);
1967 while ((plist = nextPropertyList(cls, &iterator))) {
1968 count += plist->count;
1972 result = (old_property **)malloc((count+1) * sizeof(old_property *));
1976 while ((plist = nextPropertyList(cls, &iterator))) {
1977 for (i = 0; i < plist->count; i++) {
1978 result[p++] = property_list_nth(plist, i);
1984 if (outCount) *outCount = count;
1985 return (objc_property_t *)result;
1989 /***********************************************************************
1990 * class_copyMethodList. Returns a heap block containing the
1991 * methods implemented by the class, or nil if the class
1992 * implements no methods. Caller must free the block.
1993 * Does not copy any superclass's methods.
1994 **********************************************************************/
1995 Method *class_copyMethodList(Class cls, unsigned int *outCount)
1997 old_method_list *mlist;
1998 void *iterator = nil;
1999 Method *result = nil;
2000 unsigned int count = 0;
2004 if (outCount) *outCount = 0;
2008 mutex_locker_t lock(methodListLock);
2011 while ((mlist = nextMethodList(cls, &iterator))) {
2012 count += mlist->method_count;
2016 result = (Method *)malloc((count+1) * sizeof(Method));
2020 while ((mlist = nextMethodList(cls, &iterator))) {
2022 for (i = 0; i < mlist->method_count; i++) {
2023 Method aMethod = (Method)&mlist->method_list[i];
2024 if (ignoreSelector(method_getName(aMethod))) {
2028 result[m++] = aMethod;
2034 if (outCount) *outCount = count;
2039 /***********************************************************************
2040 * class_copyIvarList. Returns a heap block containing the
2041 * ivars declared in the class, or nil if the class
2042 * declares no ivars. Caller must free the block.
2043 * Does not copy any superclass's ivars.
2044 **********************************************************************/
2045 Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
2048 unsigned int count = 0;
2052 if (outCount) *outCount = 0;
2057 count = cls->ivars->ivar_count;
2061 result = (Ivar *)malloc((count+1) * sizeof(Ivar));
2063 for (i = 0; i < cls->ivars->ivar_count; i++) {
2064 result[i] = (Ivar)&cls->ivars->ivar_list[i];
2069 if (outCount) *outCount = count;
2074 /***********************************************************************
2075 * objc_allocateClass.
2076 **********************************************************************/
2078 void set_superclass(Class cls, Class supercls, bool cls_is_new)
2080 Class meta = cls->ISA();
2083 cls->superclass = supercls;
2084 meta->superclass = supercls->ISA();
2085 meta->initIsa(supercls->ISA()->ISA());
2087 // Propagate C++ cdtors from superclass.
2088 if (supercls->info & CLS_HAS_CXX_STRUCTORS) {
2089 if (cls_is_new) cls->info |= CLS_HAS_CXX_STRUCTORS;
2090 else cls->setInfo(CLS_HAS_CXX_STRUCTORS);
2093 // Superclass is no longer a leaf for cache flushing
2094 if (supercls->info & CLS_LEAF) {
2095 supercls->clearInfo(CLS_LEAF);
2096 supercls->ISA()->clearInfo(CLS_LEAF);
2099 cls->superclass = Nil; // superclass of root class is nil
2100 meta->superclass = cls; // superclass of root metaclass is root class
2101 meta->initIsa(meta); // metaclass of root metaclass is root metaclass
2103 // Root class is never a leaf for cache flushing, because the
2104 // root metaclass is a subclass. (This could be optimized, but
2105 // is too uncommon to bother.)
2106 cls->clearInfo(CLS_LEAF);
2107 meta->clearInfo(CLS_LEAF);
2111 // &UnsetLayout is the default ivar layout during class construction
2112 static const uint8_t UnsetLayout = 0;
2114 Class objc_initializeClassPair(Class supercls, const char *name, Class cls, Class meta)
2116 // Connect to superclasses and metaclasses
2118 set_superclass(cls, supercls, YES);
2121 cls->name = strdup(name);
2122 meta->name = strdup(name);
2125 cls->info = CLS_CLASS | CLS_CONSTRUCTING | CLS_EXT | CLS_LEAF;
2126 meta->info = CLS_META | CLS_CONSTRUCTING | CLS_EXT | CLS_LEAF;
2128 // Set instance size based on superclass.
2130 cls->instance_size = supercls->instance_size;
2131 meta->instance_size = supercls->ISA()->instance_size;
2133 cls->instance_size = sizeof(Class); // just an isa
2134 meta->instance_size = sizeof(objc_class);
2137 // No ivars. No methods. Empty cache. No protocols. No layout. Empty ext.
2139 cls->methodLists = nil;
2140 cls->cache = (Cache)&_objc_empty_cache;
2141 cls->protocols = nil;
2142 cls->ivar_layout = &UnsetLayout;
2145 cls->ext->weak_ivar_layout = &UnsetLayout;
2148 meta->methodLists = nil;
2149 meta->cache = (Cache)&_objc_empty_cache;
2150 meta->protocols = nil;
2156 Class objc_allocateClassPair(Class supercls, const char *name,
2161 if (objc_getClass(name)) return nil;
2162 // fixme reserve class name against simultaneous allocation
2164 if (supercls && (supercls->info & CLS_CONSTRUCTING)) {
2165 // Can't make subclass of an in-construction class
2169 // Allocate new classes.
2171 cls = _calloc_class(supercls->ISA()->alignedInstanceSize() + extraBytes);
2172 meta = _calloc_class(supercls->ISA()->ISA()->alignedInstanceSize() + extraBytes);
2174 cls = _calloc_class(sizeof(objc_class) + extraBytes);
2175 meta = _calloc_class(sizeof(objc_class) + extraBytes);
2179 objc_initializeClassPair(supercls, name, cls, meta);
2185 void objc_registerClassPair(Class cls)
2187 if ((cls->info & CLS_CONSTRUCTED) ||
2188 (cls->ISA()->info & CLS_CONSTRUCTED))
2190 _objc_inform("objc_registerClassPair: class '%s' was already "
2191 "registered!", cls->name);
2195 if (!(cls->info & CLS_CONSTRUCTING) ||
2196 !(cls->ISA()->info & CLS_CONSTRUCTING))
2198 _objc_inform("objc_registerClassPair: class '%s' was not "
2199 "allocated with objc_allocateClassPair!", cls->name);
2204 _objc_inform("objc_registerClassPair: class '%s' is a metaclass, "
2205 "not a class!", cls->name);
2209 mutex_locker_t lock(classLock);
2211 // Build ivar layouts
2213 if (cls->ivar_layout != &UnsetLayout) {
2214 // Class builder already called class_setIvarLayout.
2216 else if (!cls->superclass) {
2217 // Root class. Scan conservatively (should be isa ivar only).
2218 cls->ivar_layout = nil;
2220 else if (cls->ivars == nil) {
2221 // No local ivars. Use superclass's layout.
2223 ustrdupMaybeNil(cls->superclass->ivar_layout);
2226 // Has local ivars. Build layout based on superclass.
2227 Class supercls = cls->superclass;
2228 const uint8_t *superlayout =
2229 class_getIvarLayout(supercls);
2230 layout_bitmap bitmap =
2231 layout_bitmap_create(superlayout, supercls->instance_size,
2232 cls->instance_size, NO);
2234 for (i = 0; i < cls->ivars->ivar_count; i++) {
2235 old_ivar *iv = &cls->ivars->ivar_list[i];
2236 layout_bitmap_set_ivar(bitmap, iv->ivar_type, iv->ivar_offset);
2238 cls->ivar_layout = layout_string_create(bitmap);
2239 layout_bitmap_free(bitmap);
2242 if (cls->ext->weak_ivar_layout != &UnsetLayout) {
2243 // Class builder already called class_setWeakIvarLayout.
2245 else if (!cls->superclass) {
2246 // Root class. No weak ivars (should be isa ivar only)
2247 cls->ext->weak_ivar_layout = nil;
2249 else if (cls->ivars == nil) {
2250 // No local ivars. Use superclass's layout.
2251 const uint8_t *weak =
2252 class_getWeakIvarLayout(cls->superclass);
2253 cls->ext->weak_ivar_layout = ustrdupMaybeNil(weak);
2256 // Has local ivars. Build layout based on superclass.
2257 // No way to add weak ivars yet.
2258 const uint8_t *weak =
2259 class_getWeakIvarLayout(cls->superclass);
2260 cls->ext->weak_ivar_layout = ustrdupMaybeNil(weak);
2264 // Clear "under construction" bit, set "done constructing" bit
2265 cls->info &= ~CLS_CONSTRUCTING;
2266 cls->ISA()->info &= ~CLS_CONSTRUCTING;
2267 cls->info |= CLS_CONSTRUCTED;
2268 cls->ISA()->info |= CLS_CONSTRUCTED;
2270 NXHashInsertIfAbsent(class_hash, cls);
2271 objc_addRegisteredClass(cls);
2272 //objc_addRegisteredClass(cls->ISA()); if we ever allocate classes from GC
2276 Class objc_duplicateClass(Class original, const char *name, size_t extraBytes)
2278 unsigned int count, i;
2279 old_method **originalMethods;
2280 old_method_list *duplicateMethods;
2281 // Don't use sizeof(objc_class) here because
2282 // instance_size has historically contained two extra words,
2283 // and instance_size is what objc_getIndexedIvars() actually uses.
2285 _calloc_class(original->ISA()->alignedInstanceSize() + extraBytes);
2287 duplicate->initIsa(original->ISA());
2288 duplicate->superclass = original->superclass;
2289 duplicate->name = strdup(name);
2290 duplicate->version = original->version;
2291 duplicate->info = original->info & (CLS_CLASS|CLS_META|CLS_INITIALIZED|CLS_JAVA_HYBRID|CLS_JAVA_CLASS|CLS_HAS_CXX_STRUCTORS|CLS_HAS_LOAD_METHOD);
2292 duplicate->instance_size = original->instance_size;
2293 duplicate->ivars = original->ivars;
2294 // methodLists handled below
2295 duplicate->cache = (Cache)&_objc_empty_cache;
2296 duplicate->protocols = original->protocols;
2297 if (original->info & CLS_EXT) {
2298 duplicate->info |= original->info & (CLS_EXT|CLS_NO_PROPERTY_ARRAY);
2299 duplicate->ivar_layout = original->ivar_layout;
2300 if (original->ext) {
2301 duplicate->ext = (old_class_ext *)malloc(original->ext->size);
2302 memcpy(duplicate->ext, original->ext, original->ext->size);
2304 duplicate->ext = nil;
2308 // Method lists are deep-copied so they can be stomped.
2309 originalMethods = (old_method **)class_copyMethodList(original, &count);
2310 if (originalMethods) {
2311 duplicateMethods = (old_method_list *)
2312 calloc(sizeof(old_method_list) +
2313 (count-1)*sizeof(old_method), 1);
2314 duplicateMethods->obsolete = fixed_up_method_list;
2315 duplicateMethods->method_count = count;
2316 for (i = 0; i < count; i++) {
2317 duplicateMethods->method_list[i] = *(originalMethods[i]);
2319 duplicate->methodLists = (old_method_list **)duplicateMethods;
2320 duplicate->info |= CLS_NO_METHOD_ARRAY;
2321 free(originalMethods);
2324 mutex_locker_t lock(classLock);
2325 NXHashInsert(class_hash, duplicate);
2326 objc_addRegisteredClass(duplicate);
2332 void objc_disposeClassPair(Class cls)
2334 if (!(cls->info & (CLS_CONSTRUCTED|CLS_CONSTRUCTING)) ||
2335 !(cls->ISA()->info & (CLS_CONSTRUCTED|CLS_CONSTRUCTING)))
2337 // class not allocated with objc_allocateClassPair
2338 // disposing still-unregistered class is OK!
2339 _objc_inform("objc_disposeClassPair: class '%s' was not "
2340 "allocated with objc_allocateClassPair!", cls->name);
2345 _objc_inform("objc_disposeClassPair: class '%s' is a metaclass, "
2346 "not a class!", cls->name);
2350 mutex_locker_t lock(classLock);
2351 NXHashRemove(class_hash, cls);
2352 objc_removeRegisteredClass(cls);
2353 unload_class(cls->ISA());
2358 /***********************************************************************
2359 * objc_constructInstance
2360 * Creates an instance of `cls` at the location pointed to by `bytes`.
2361 * `bytes` must point to at least class_getInstanceSize(cls) bytes of
2362 * well-aligned zero-filled memory.
2363 * The new object's isa is set. Any C++ constructors are called.
2364 * Returns `bytes` if successful. Returns nil if `cls` or `bytes` is
2365 * nil, or if C++ constructors fail.
2366 **********************************************************************/
2368 objc_constructInstance(Class cls, void *bytes)
2370 if (!cls || !bytes) return nil;
2376 if (cls->hasCxxCtor()) {
2377 return object_cxxConstructFromClass(obj, cls);
2384 /***********************************************************************
2385 * _class_createInstanceFromZone. Allocate an instance of the
2386 * specified class with the specified number of bytes for indexed
2387 * variables, in the specified zone. The isa field is set to the
2388 * class, C++ default constructors are called, and all other fields are zeroed.
2389 **********************************************************************/
2391 _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone)
2396 // Can't create something for nothing
2397 if (!cls) return nil;
2399 // Allocate and initialize
2400 size = cls->alignedInstanceSize() + extraBytes;
2402 // CF requires all objects be at least 16 bytes.
2403 if (size < 16) size = 16;
2407 bytes = auto_zone_allocate_object(gc_zone, size,
2408 AUTO_OBJECT_SCANNED, 0, 1);
2412 bytes = malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
2414 bytes = calloc(1, size);
2417 return objc_constructInstance(cls, bytes);
2421 /***********************************************************************
2422 * _class_createInstance. Allocate an instance of the specified
2423 * class with the specified number of bytes for indexed variables, in
2424 * the default zone, using _class_createInstanceFromZone.
2425 **********************************************************************/
2426 static id _class_createInstance(Class cls, size_t extraBytes)
2428 return _class_createInstanceFromZone (cls, extraBytes, nil);
2432 static id _object_copyFromZone(id oldObj, size_t extraBytes, void *zone)
2437 if (!oldObj) return nil;
2439 obj = (*_zoneAlloc)(oldObj->ISA(), extraBytes, zone);
2440 size = oldObj->ISA()->alignedInstanceSize() + extraBytes;
2442 // fixme need C++ copy constructor
2443 objc_memmove_collectable(obj, oldObj, size);
2446 if (UseGC) gc_fixup_weakreferences(obj, oldObj);
2453 /***********************************************************************
2454 * objc_destructInstance
2455 * Destroys an instance without freeing memory.
2456 * Calls C++ destructors.
2457 * Removes associative references.
2458 * Returns `obj`. Does nothing if `obj` is nil.
2459 * Be warned that GC DOES NOT CALL THIS. If you edit this, also edit finalize.
2460 * CoreFoundation and other clients do call this under GC.
2461 **********************************************************************/
2462 void *objc_destructInstance(id obj)
2465 Class isa = obj->getIsa();
2467 if (isa->hasCxxDtor()) {
2468 object_cxxDestruct(obj);
2471 if (isa->instancesHaveAssociatedObjects()) {
2472 _object_remove_assocations(obj);
2475 if (!UseGC) objc_clear_deallocating(obj);
2482 _object_dispose(id anObject)
2484 if (anObject==nil) return nil;
2486 objc_destructInstance(anObject);
2490 auto_zone_retain(gc_zone, anObject); // gc free expects rc==1
2494 // only clobber isa for non-gc
2495 anObject->initIsa(_objc_getFreedObjectClass ());
2501 static id _object_copy(id oldObj, size_t extraBytes)
2503 void *z = malloc_zone_from_ptr(oldObj);
2504 return _object_copyFromZone(oldObj, extraBytes,
2505 z ? z : malloc_default_zone());
2508 static id _object_reallocFromZone(id anObject, size_t nBytes, void *zone)
2513 if (anObject == nil)
2514 __objc_error(nil, "reallocating nil object");
2516 if (anObject->ISA() == _objc_getFreedObjectClass ())
2517 __objc_error(anObject, "reallocating freed object");
2519 if (nBytes < anObject->ISA()->alignedInstanceSize())
2520 __objc_error(anObject, "(%s, %zu) requested size too small",
2521 object_getClassName(anObject), nBytes);
2523 // fixme need C++ copy constructor
2525 // Make sure not to modify space that has been declared free
2526 tmp = anObject->ISA();
2527 anObject->initIsa(_objc_getFreedObjectClass ());
2528 newObject = (id)malloc_zone_realloc((malloc_zone_t *)zone, anObject, nBytes);
2530 newObject->initIsa(tmp);
2532 // realloc failed, anObject is still alive
2533 anObject->initIsa(tmp);
2539 static id _object_realloc(id anObject, size_t nBytes)
2541 void *z = malloc_zone_from_ptr(anObject);
2542 return _object_reallocFromZone(anObject,
2544 z ? z : malloc_default_zone());
2547 id (*_alloc)(Class, size_t) = _class_createInstance;
2548 id (*_copy)(id, size_t) = _object_copy;
2549 id (*_realloc)(id, size_t) = _object_realloc;
2550 id (*_dealloc)(id) = _object_dispose;
2551 id (*_zoneAlloc)(Class, size_t, void *) = _class_createInstanceFromZone;
2552 id (*_zoneCopy)(id, size_t, void *) = _object_copyFromZone;
2553 id (*_zoneRealloc)(id, size_t, void *) = _object_reallocFromZone;
2554 void (*_error)(id, const char *, va_list) = _objc_error;
2557 id class_createInstance(Class cls, size_t extraBytes)
2560 return _class_createInstance(cls, extraBytes);
2562 return (*_alloc)(cls, extraBytes);
2566 id class_createInstanceFromZone(Class cls, size_t extraBytes, void *z)
2568 OBJC_WARN_DEPRECATED;
2570 return _class_createInstanceFromZone(cls, extraBytes, z);
2572 return (*_zoneAlloc)(cls, extraBytes, z);
2576 unsigned class_createInstances(Class cls, size_t extraBytes,
2577 id *results, unsigned num_requested)
2579 if (UseGC || _alloc == &_class_createInstance) {
2580 return _class_createInstancesFromZone(cls, extraBytes, nil,
2581 results, num_requested);
2583 // _alloc in use, which isn't understood by the batch allocator
2588 id object_copy(id obj, size_t extraBytes)
2590 if (UseGC) return _object_copy(obj, extraBytes);
2591 else return (*_copy)(obj, extraBytes);
2594 id object_copyFromZone(id obj, size_t extraBytes, void *z)
2596 OBJC_WARN_DEPRECATED;
2597 if (UseGC) return _object_copyFromZone(obj, extraBytes, z);
2598 else return (*_zoneCopy)(obj, extraBytes, z);
2601 id object_dispose(id obj)
2603 if (UseGC) return _object_dispose(obj);
2604 else return (*_dealloc)(obj);
2607 id object_realloc(id obj, size_t nBytes)
2609 OBJC_WARN_DEPRECATED;
2610 if (UseGC) return _object_realloc(obj, nBytes);
2611 else return (*_realloc)(obj, nBytes);
2614 id object_reallocFromZone(id obj, size_t nBytes, void *z)
2616 OBJC_WARN_DEPRECATED;
2617 if (UseGC) return _object_reallocFromZone(obj, nBytes, z);
2618 else return (*_zoneRealloc)(obj, nBytes, z);
2622 /***********************************************************************
2623 * object_getIndexedIvars.
2624 **********************************************************************/
2625 void *object_getIndexedIvars(id obj)
2627 // ivars are tacked onto the end of the object
2628 if (!obj) return nil;
2629 if (obj->isTaggedPointer()) return nil;
2630 return ((char *) obj) + obj->ISA()->alignedInstanceSize();
2635 Class class_setSuperclass(Class cls, Class newSuper)
2637 Class oldSuper = cls->superclass;
2638 set_superclass(cls, newSuper, NO);
2639 flush_caches(cls, YES);