2 * Copyright (c) 2005-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 new-ABI classes and images.
27 **********************************************************************/
31 #include "objc-private.h"
32 #include "objc-runtime-new.h"
33 #include "objc-file.h"
34 #include "objc-cache.h"
36 #include <objc/message.h>
37 #include <mach/shared_region.h>
39 #define newprotocol(p) ((protocol_t *)p)
41 static void disableTaggedPointers();
42 static void detach_class(Class cls, bool isMeta);
43 static void free_class(Class cls);
44 static Class setSuperclass(Class cls, Class newSuper);
45 static Class realizeClass(Class cls);
46 static method_t *getMethodNoSuper_nolock(Class cls, SEL sel);
47 static method_t *getMethod_nolock(Class cls, SEL sel);
48 static IMP addMethod(Class cls, SEL name, IMP imp, const char *types, bool replace);
49 static bool isRRSelector(SEL sel);
50 static bool isAWZSelector(SEL sel);
51 static bool methodListImplementsRR(const method_list_t *mlist);
52 static bool methodListImplementsAWZ(const method_list_t *mlist);
53 static void updateCustomRR_AWZ(Class cls, method_t *meth);
54 static method_t *search_method_list(const method_list_t *mlist, SEL sel);
55 static void flushCaches(Class cls);
57 static void fixupMessageRef(message_ref_t *msg);
60 static bool MetaclassNSObjectAWZSwizzled;
61 static bool ClassNSObjectRRSwizzled;
63 id objc_noop_imp(id self, SEL _cmd __unused) {
68 /***********************************************************************
70 **********************************************************************/
73 mutex_t cacheUpdateLock;
74 recursive_mutex_t loadMethodLock;
77 pthread_priority_t BackgroundPriority = 0;
78 pthread_priority_t MainPriority = 0;
80 static __unused void destroyQOSKey(void *arg) {
81 _objc_fatal("QoS override level at thread exit is %zu instead of zero",
82 (size_t)(uintptr_t)arg);
90 BackgroundPriority = _pthread_qos_class_encode(QOS_CLASS_BACKGROUND, 0, 0);
91 MainPriority = _pthread_qos_class_encode(qos_class_main(), 0, 0);
93 pthread_key_init_np(QOS_KEY, &destroyQOSKey);
99 /***********************************************************************
100 * Non-pointer isa decoding
101 **********************************************************************/
102 #if SUPPORT_INDEXED_ISA
104 // Indexed non-pointer isa.
106 // These are used to mask the ISA and see if its got an index or not.
107 const uintptr_t objc_debug_indexed_isa_magic_mask = ISA_INDEX_MAGIC_MASK;
108 const uintptr_t objc_debug_indexed_isa_magic_value = ISA_INDEX_MAGIC_VALUE;
110 // die if masks overlap
111 STATIC_ASSERT((ISA_INDEX_MASK & ISA_INDEX_MAGIC_MASK) == 0);
113 // die if magic is wrong
114 STATIC_ASSERT((~ISA_INDEX_MAGIC_MASK & ISA_INDEX_MAGIC_VALUE) == 0);
116 // Then these are used to extract the index from the ISA.
117 const uintptr_t objc_debug_indexed_isa_index_mask = ISA_INDEX_MASK;
118 const uintptr_t objc_debug_indexed_isa_index_shift = ISA_INDEX_SHIFT;
120 asm("\n .globl _objc_absolute_indexed_isa_magic_mask" \
121 "\n _objc_absolute_indexed_isa_magic_mask = " STRINGIFY2(ISA_INDEX_MAGIC_MASK));
122 asm("\n .globl _objc_absolute_indexed_isa_magic_value" \
123 "\n _objc_absolute_indexed_isa_magic_value = " STRINGIFY2(ISA_INDEX_MAGIC_VALUE));
124 asm("\n .globl _objc_absolute_indexed_isa_index_mask" \
125 "\n _objc_absolute_indexed_isa_index_mask = " STRINGIFY2(ISA_INDEX_MASK));
126 asm("\n .globl _objc_absolute_indexed_isa_index_shift" \
127 "\n _objc_absolute_indexed_isa_index_shift = " STRINGIFY2(ISA_INDEX_SHIFT));
130 // And then we can use that index to get the class from this array. Note
131 // the size is provided so that clients can ensure the index they get is in
132 // bounds and not read off the end of the array.
133 // Defined in the objc-msg-*.s files
134 // const Class objc_indexed_classes[]
136 // When we don't have enough bits to store a class*, we can instead store an
137 // index in to this array. Classes are added here when they are realized.
138 // Note, an index of 0 is illegal.
139 uintptr_t objc_indexed_classes_count = 0;
141 // SUPPORT_INDEXED_ISA
143 // not SUPPORT_INDEXED_ISA
145 // These variables exist but are all set to 0 so that they are ignored.
146 const uintptr_t objc_debug_indexed_isa_magic_mask = 0;
147 const uintptr_t objc_debug_indexed_isa_magic_value = 0;
148 const uintptr_t objc_debug_indexed_isa_index_mask = 0;
149 const uintptr_t objc_debug_indexed_isa_index_shift = 0;
150 Class objc_indexed_classes[1] = { nil };
151 uintptr_t objc_indexed_classes_count = 0;
153 // not SUPPORT_INDEXED_ISA
157 #if SUPPORT_PACKED_ISA
159 // Packed non-pointer isa.
161 asm("\n .globl _objc_absolute_packed_isa_class_mask" \
162 "\n _objc_absolute_packed_isa_class_mask = " STRINGIFY2(ISA_MASK));
164 const uintptr_t objc_debug_isa_class_mask = ISA_MASK;
165 const uintptr_t objc_debug_isa_magic_mask = ISA_MAGIC_MASK;
166 const uintptr_t objc_debug_isa_magic_value = ISA_MAGIC_VALUE;
168 // die if masks overlap
169 STATIC_ASSERT((ISA_MASK & ISA_MAGIC_MASK) == 0);
171 // die if magic is wrong
172 STATIC_ASSERT((~ISA_MAGIC_MASK & ISA_MAGIC_VALUE) == 0);
174 // die if virtual address space bound goes up
175 STATIC_ASSERT((~ISA_MASK & MACH_VM_MAX_ADDRESS) == 0 ||
176 ISA_MASK + sizeof(void*) == MACH_VM_MAX_ADDRESS);
178 // SUPPORT_PACKED_ISA
180 // not SUPPORT_PACKED_ISA
182 // These variables exist but enforce pointer alignment only.
183 const uintptr_t objc_debug_isa_class_mask = (~WORD_MASK);
184 const uintptr_t objc_debug_isa_magic_mask = WORD_MASK;
185 const uintptr_t objc_debug_isa_magic_value = 0;
187 // not SUPPORT_PACKED_ISA
191 typedef locstamped_category_list_t category_list;
195 Low two bits of mlist->entsize is used as the fixed-up marker.
196 PREOPTIMIZED VERSION:
197 Method lists from shared cache are 1 (uniqued) or 3 (uniqued and sorted).
198 (Protocol method lists are not sorted because of their extra parallel data)
199 Runtime fixed-up method lists get 3.
200 UN-PREOPTIMIZED VERSION:
201 Method lists from shared cache are 1 (uniqued) or 3 (uniqued and sorted)
202 Shared cache's sorting and uniquing are not trusted, but do affect the
203 location of the selector name string.
204 Runtime fixed-up method lists get 2.
206 High two bits of protocol->flags is used as the fixed-up marker.
207 PREOPTIMIZED VERSION:
208 Protocols from shared cache are 1<<30.
209 Runtime fixed-up protocols get 1<<30.
210 UN-PREOPTIMIZED VERSION:
211 Protocols from shared cache are 1<<30.
212 Shared cache's fixups are not trusted.
213 Runtime fixed-up protocols get 3<<30.
216 static uint32_t fixed_up_method_list = 3;
217 static uint32_t fixed_up_protocol = PROTOCOL_FIXED_UP_1;
220 disableSharedCacheOptimizations(void)
222 fixed_up_method_list = 2;
223 fixed_up_protocol = PROTOCOL_FIXED_UP_1 | PROTOCOL_FIXED_UP_2;
226 bool method_list_t::isFixedUp() const {
227 return flags() == fixed_up_method_list;
230 void method_list_t::setFixedUp() {
231 runtimeLock.assertWriting();
232 assert(!isFixedUp());
233 entsizeAndFlags = entsize() | fixed_up_method_list;
236 bool protocol_t::isFixedUp() const {
237 return (flags & PROTOCOL_FIXED_UP_MASK) == fixed_up_protocol;
240 void protocol_t::setFixedUp() {
241 runtimeLock.assertWriting();
242 assert(!isFixedUp());
243 flags = (flags & ~PROTOCOL_FIXED_UP_MASK) | fixed_up_protocol;
247 method_list_t **method_array_t::endCategoryMethodLists(Class cls)
249 method_list_t **mlists = beginLists();
250 method_list_t **mlistsEnd = endLists();
252 if (mlists == mlistsEnd || !cls->data()->ro->baseMethods())
254 // No methods, or no base methods.
255 // Everything here is a category method.
259 // Have base methods. Category methods are
260 // everything except the last method list.
261 return mlistsEnd - 1;
264 static const char *sel_cname(SEL sel)
266 return (const char *)(void *)sel;
270 static size_t protocol_list_size(const protocol_list_t *plist)
272 return sizeof(protocol_list_t) + plist->count * sizeof(protocol_t *);
276 static void try_free(const void *p)
278 if (p && malloc_size(p)) free((void *)p);
283 alloc_class_for_subclass(Class supercls, size_t extraBytes)
285 if (!supercls || !supercls->isSwift()) {
286 return _calloc_class(sizeof(objc_class) + extraBytes);
289 // Superclass is a Swift class. New subclass must duplicate its extra bits.
291 // Allocate the new class, with space for super's prefix and suffix
292 // and self's extraBytes.
293 swift_class_t *swiftSupercls = (swift_class_t *)supercls;
294 size_t superSize = swiftSupercls->classSize;
295 void *superBits = swiftSupercls->baseAddress();
296 void *bits = malloc(superSize + extraBytes);
298 // Copy all of the superclass's data to the new class.
299 memcpy(bits, superBits, superSize);
301 // Erase the objc data and the Swift description in the new class.
302 swift_class_t *swcls = (swift_class_t *)
303 ((uint8_t *)bits + swiftSupercls->classAddressOffset);
304 bzero(swcls, sizeof(objc_class));
305 swcls->description = nil;
307 // Mark this class as Swift-enhanced.
308 swcls->bits.setIsSwift();
314 /***********************************************************************
315 * object_getIndexedIvars.
316 **********************************************************************/
317 void *object_getIndexedIvars(id obj)
319 uint8_t *base = (uint8_t *)obj;
321 if (!obj) return nil;
322 if (obj->isTaggedPointer()) return nil;
324 if (!obj->isClass()) return base + obj->ISA()->alignedInstanceSize();
326 Class cls = (Class)obj;
327 if (!cls->isSwift()) return base + sizeof(objc_class);
329 swift_class_t *swcls = (swift_class_t *)cls;
330 return base - swcls->classAddressOffset + word_align(swcls->classSize);
334 /***********************************************************************
336 * Reallocates rw->ro if necessary to make it writeable.
337 * Locking: runtimeLock must be held by the caller.
338 **********************************************************************/
339 static class_ro_t *make_ro_writeable(class_rw_t *rw)
341 runtimeLock.assertWriting();
343 if (rw->flags & RW_COPIED_RO) {
344 // already writeable, do nothing
346 class_ro_t *ro = (class_ro_t *)
347 memdup(rw->ro, sizeof(*rw->ro));
349 rw->flags |= RW_COPIED_RO;
351 return (class_ro_t *)rw->ro;
355 /***********************************************************************
356 * unattachedCategories
357 * Returns the class => categories map of unattached categories.
358 * Locking: runtimeLock must be held by the caller.
359 **********************************************************************/
360 static NXMapTable *unattachedCategories(void)
362 runtimeLock.assertWriting();
364 static NXMapTable *category_map = nil;
366 if (category_map) return category_map;
368 // fixme initial map size
369 category_map = NXCreateMapTable(NXPtrValueMapPrototype, 16);
375 /***********************************************************************
376 * addUnattachedCategoryForClass
377 * Records an unattached category.
378 * Locking: runtimeLock must be held by the caller.
379 **********************************************************************/
380 static void addUnattachedCategoryForClass(category_t *cat, Class cls,
381 header_info *catHeader)
383 runtimeLock.assertWriting();
385 // DO NOT use cat->cls! cls may be cat->cls->isa instead
386 NXMapTable *cats = unattachedCategories();
389 list = (category_list *)NXMapGet(cats, cls);
391 list = (category_list *)
392 calloc(sizeof(*list) + sizeof(list->list[0]), 1);
394 list = (category_list *)
395 realloc(list, sizeof(*list) + sizeof(list->list[0]) * (list->count + 1));
397 list->list[list->count++] = (locstamped_category_t){cat, catHeader};
398 NXMapInsert(cats, cls, list);
402 /***********************************************************************
403 * removeUnattachedCategoryForClass
404 * Removes an unattached category.
405 * Locking: runtimeLock must be held by the caller.
406 **********************************************************************/
407 static void removeUnattachedCategoryForClass(category_t *cat, Class cls)
409 runtimeLock.assertWriting();
411 // DO NOT use cat->cls! cls may be cat->cls->isa instead
412 NXMapTable *cats = unattachedCategories();
415 list = (category_list *)NXMapGet(cats, cls);
419 for (i = 0; i < list->count; i++) {
420 if (list->list[i].cat == cat) {
421 // shift entries to preserve list order
422 memmove(&list->list[i], &list->list[i+1],
423 (list->count-i-1) * sizeof(list->list[i]));
431 /***********************************************************************
432 * unattachedCategoriesForClass
433 * Returns the list of unattached categories for a class, and
434 * deletes them from the list.
435 * The result must be freed by the caller.
436 * Locking: runtimeLock must be held by the caller.
437 **********************************************************************/
438 static category_list *
439 unattachedCategoriesForClass(Class cls, bool realizing)
441 runtimeLock.assertWriting();
442 return (category_list *)NXMapRemove(unattachedCategories(), cls);
446 /***********************************************************************
447 * removeAllUnattachedCategoriesForClass
448 * Deletes all unattached categories (loaded or not) for a class.
449 * Locking: runtimeLock must be held by the caller.
450 **********************************************************************/
451 static void removeAllUnattachedCategoriesForClass(Class cls)
453 runtimeLock.assertWriting();
455 void *list = NXMapRemove(unattachedCategories(), cls);
456 if (list) free(list);
460 /***********************************************************************
462 * Returns class NSObject.
464 **********************************************************************/
465 static Class classNSObject(void)
467 extern objc_class OBJC_CLASS_$_NSObject;
468 return (Class)&OBJC_CLASS_$_NSObject;
472 /***********************************************************************
474 * Implementation of PrintReplacedMethods / OBJC_PRINT_REPLACED_METHODS.
475 * Warn about methods from cats that override other methods in cats or cls.
476 * Assumes no methods from cats have been added to cls yet.
477 **********************************************************************/
478 static void printReplacements(Class cls, category_list *cats)
481 bool isMeta = cls->isMetaClass();
485 // Newest categories are LAST in cats
486 // Later categories override earlier ones.
487 for (c = 0; c < cats->count; c++) {
488 category_t *cat = cats->list[c].cat;
490 method_list_t *mlist = cat->methodsForMeta(isMeta);
491 if (!mlist) continue;
493 for (const auto& meth : *mlist) {
494 SEL s = sel_registerName(sel_cname(meth.name));
496 // Search for replaced methods in method lookup order.
497 // Complain about the first duplicate only.
499 // Look for method in earlier categories
500 for (uint32_t c2 = 0; c2 < c; c2++) {
501 category_t *cat2 = cats->list[c2].cat;
503 const method_list_t *mlist2 = cat2->methodsForMeta(isMeta);
504 if (!mlist2) continue;
506 for (const auto& meth2 : *mlist2) {
507 SEL s2 = sel_registerName(sel_cname(meth2.name));
509 logReplacedMethod(cls->nameForLogging(), s,
510 cls->isMetaClass(), cat->name,
511 meth2.imp, meth.imp);
517 // Look for method in cls
518 for (const auto& meth2 : cls->data()->methods) {
519 SEL s2 = sel_registerName(sel_cname(meth2.name));
521 logReplacedMethod(cls->nameForLogging(), s,
522 cls->isMetaClass(), cat->name,
523 meth2.imp, meth.imp);
535 static bool isBundleClass(Class cls)
537 return cls->data()->ro->flags & RO_FROM_BUNDLE;
542 fixupMethodList(method_list_t *mlist, bool bundleCopy, bool sort)
544 runtimeLock.assertWriting();
545 assert(!mlist->isFixedUp());
547 // fixme lock less in attachMethodLists ?
550 // Unique selectors in list.
551 for (auto& meth : *mlist) {
552 const char *name = sel_cname(meth.name);
553 meth.name = sel_registerNameNoLock(name, bundleCopy);
558 // Sort by selector address.
560 method_t::SortBySELAddress sorter;
561 std::stable_sort(mlist->begin(), mlist->end(), sorter);
564 // Mark method list as uniqued and sorted
570 prepareMethodLists(Class cls, method_list_t **addedLists, int addedCount,
571 bool baseMethods, bool methodsFromBundle)
573 runtimeLock.assertWriting();
575 if (addedCount == 0) return;
577 // Don't scan redundantly
578 bool scanForCustomRR = !cls->hasCustomRR();
579 bool scanForCustomAWZ = !cls->hasCustomAWZ();
581 // There exist RR/AWZ special cases for some class's base methods.
582 // But this code should never need to scan base methods for RR/AWZ:
583 // default RR/AWZ cannot be set before setInitialized().
584 // Therefore we need not handle any special cases here.
586 assert(!scanForCustomRR && !scanForCustomAWZ);
589 // Add method lists to array.
590 // Reallocate un-fixed method lists.
591 // The new methods are PREPENDED to the method list array.
593 for (int i = 0; i < addedCount; i++) {
594 method_list_t *mlist = addedLists[i];
597 // Fixup selectors if necessary
598 if (!mlist->isFixedUp()) {
599 fixupMethodList(mlist, methodsFromBundle, true/*sort*/);
602 // Scan for method implementations tracked by the class's flags
603 if (scanForCustomRR && methodListImplementsRR(mlist)) {
604 cls->setHasCustomRR();
605 scanForCustomRR = false;
607 if (scanForCustomAWZ && methodListImplementsAWZ(mlist)) {
608 cls->setHasCustomAWZ();
609 scanForCustomAWZ = false;
615 // Attach method lists and properties and protocols from categories to a class.
616 // Assumes the categories in cats are all loaded and sorted by load order,
617 // oldest categories first.
619 attachCategories(Class cls, category_list *cats, bool flush_caches)
622 if (PrintReplacedMethods) printReplacements(cls, cats);
624 bool isMeta = cls->isMetaClass();
626 // fixme rearrange to remove these intermediate allocations
627 method_list_t **mlists = (method_list_t **)
628 malloc(cats->count * sizeof(*mlists));
629 property_list_t **proplists = (property_list_t **)
630 malloc(cats->count * sizeof(*proplists));
631 protocol_list_t **protolists = (protocol_list_t **)
632 malloc(cats->count * sizeof(*protolists));
634 // Count backwards through cats to get newest categories first
639 bool fromBundle = NO;
641 auto& entry = cats->list[i];
643 method_list_t *mlist = entry.cat->methodsForMeta(isMeta);
645 mlists[mcount++] = mlist;
646 fromBundle |= entry.hi->isBundle();
649 property_list_t *proplist =
650 entry.cat->propertiesForMeta(isMeta, entry.hi);
652 proplists[propcount++] = proplist;
655 protocol_list_t *protolist = entry.cat->protocols;
657 protolists[protocount++] = protolist;
661 auto rw = cls->data();
663 prepareMethodLists(cls, mlists, mcount, NO, fromBundle);
664 rw->methods.attachLists(mlists, mcount);
666 if (flush_caches && mcount > 0) flushCaches(cls);
668 rw->properties.attachLists(proplists, propcount);
671 rw->protocols.attachLists(protolists, protocount);
676 /***********************************************************************
678 * Fixes up cls's method list, protocol list, and property list.
679 * Attaches any outstanding categories.
680 * Locking: runtimeLock must be held by the caller
681 **********************************************************************/
682 static void methodizeClass(Class cls)
684 runtimeLock.assertWriting();
686 bool isMeta = cls->isMetaClass();
687 auto rw = cls->data();
690 // Methodizing for the first time
691 if (PrintConnecting) {
692 _objc_inform("CLASS: methodizing class '%s' %s",
693 cls->nameForLogging(), isMeta ? "(meta)" : "");
696 // Install methods and properties that the class implements itself.
697 method_list_t *list = ro->baseMethods();
699 prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));
700 rw->methods.attachLists(&list, 1);
703 property_list_t *proplist = ro->baseProperties;
705 rw->properties.attachLists(&proplist, 1);
708 protocol_list_t *protolist = ro->baseProtocols;
710 rw->protocols.attachLists(&protolist, 1);
713 // Root classes get bonus method implementations if they don't have
714 // them already. These apply before category replacements.
715 if (cls->isRootMetaclass()) {
717 addMethod(cls, SEL_initialize, (IMP)&objc_noop_imp, "", NO);
720 // Attach categories.
721 category_list *cats = unattachedCategoriesForClass(cls, true /*realizing*/);
722 attachCategories(cls, cats, false /*don't flush caches*/);
724 if (PrintConnecting) {
726 for (uint32_t i = 0; i < cats->count; i++) {
727 _objc_inform("CLASS: attached category %c%s(%s)",
729 cls->nameForLogging(), cats->list[i].cat->name);
734 if (cats) free(cats);
737 // Debug: sanity-check all SELs; log method list contents
738 for (const auto& meth : rw->methods) {
739 if (PrintConnecting) {
740 _objc_inform("METHOD %c[%s %s]", isMeta ? '+' : '-',
741 cls->nameForLogging(), sel_getName(meth.name));
743 assert(sel_registerName(sel_getName(meth.name)) == meth.name);
749 /***********************************************************************
751 * Attach outstanding categories to an existing class.
752 * Fixes up cls's method list, protocol list, and property list.
753 * Updates method caches for cls and its subclasses.
754 * Locking: runtimeLock must be held by the caller
755 **********************************************************************/
756 static void remethodizeClass(Class cls)
761 runtimeLock.assertWriting();
763 isMeta = cls->isMetaClass();
765 // Re-methodizing: check for more categories
766 if ((cats = unattachedCategoriesForClass(cls, false/*not realizing*/))) {
767 if (PrintConnecting) {
768 _objc_inform("CLASS: attaching categories to class '%s' %s",
769 cls->nameForLogging(), isMeta ? "(meta)" : "");
772 attachCategories(cls, cats, true /*flush caches*/);
778 /***********************************************************************
780 * Returns the secondary metaclass => class map
781 * Used for some cases of +initialize and +resolveClassMethod:.
782 * This map does not contain all class and metaclass pairs. It only
783 * contains metaclasses whose classes would be in the runtime-allocated
784 * named-class table, but are not because some other class with the same name
786 * Classes with no duplicates are not included.
787 * Classes in the preoptimized named-class table are not included.
788 * Classes whose duplicates are in the preoptimized table are not included.
789 * Most code should use getNonMetaClass() instead of reading this table.
790 * Locking: runtimeLock must be read- or write-locked by the caller
791 **********************************************************************/
792 static NXMapTable *nonmeta_class_map = nil;
793 static NXMapTable *nonMetaClasses(void)
795 runtimeLock.assertLocked();
797 if (nonmeta_class_map) return nonmeta_class_map;
799 // nonmeta_class_map is typically small
800 INIT_ONCE_PTR(nonmeta_class_map,
801 NXCreateMapTable(NXPtrValueMapPrototype, 32),
804 return nonmeta_class_map;
808 /***********************************************************************
810 * Adds metacls => cls to the secondary metaclass map
811 * Locking: runtimeLock must be held by the caller
812 **********************************************************************/
813 static void addNonMetaClass(Class cls)
815 runtimeLock.assertWriting();
817 old = NXMapInsert(nonMetaClasses(), cls->ISA(), cls);
819 assert(!cls->isMetaClass());
820 assert(cls->ISA()->isMetaClass());
825 static void removeNonMetaClass(Class cls)
827 runtimeLock.assertWriting();
828 NXMapRemove(nonMetaClasses(), cls->ISA());
832 static bool scanMangledField(const char *&string, const char *end,
833 const char *&field, int& length)
835 // Leading zero not allowed.
836 if (*string == '0') return false;
840 while (field < end) {
842 if (!isdigit(c)) break;
844 if (__builtin_smul_overflow(length, 10, &length)) return false;
845 if (__builtin_sadd_overflow(length, c - '0', &length)) return false;
848 string = field + length;
849 return length > 0 && string <= end;
853 /***********************************************************************
854 * copySwiftV1DemangledName
855 * Returns the pretty form of the given Swift-v1-mangled class or protocol name.
856 * Returns nil if the string doesn't look like a mangled Swift v1 name.
857 * The result must be freed with free().
858 **********************************************************************/
859 static char *copySwiftV1DemangledName(const char *string, bool isProtocol = false)
861 if (!string) return nil;
863 // Swift mangling prefix.
864 if (strncmp(string, isProtocol ? "_TtP" : "_TtC", 4) != 0) return nil;
867 const char *end = string + strlen(string);
872 if (string[0] == 's') {
873 // "s" is the Swift module.
878 if (! scanMangledField(string, end, prefix, prefixLength)) return nil;
881 // Class or protocol name.
884 if (! scanMangledField(string, end, suffix, suffixLength)) return nil;
887 // Remainder must be "_".
888 if (strcmp(string, "_") != 0) return nil;
890 // Remainder must be empty.
891 if (string != end) return nil;
895 asprintf(&result, "%.*s.%.*s", prefixLength,prefix, suffixLength,suffix);
900 /***********************************************************************
901 * copySwiftV1MangledName
902 * Returns the Swift 1.0 mangled form of the given class or protocol name.
903 * Returns nil if the string doesn't look like an unmangled Swift name.
904 * The result must be freed with free().
905 **********************************************************************/
906 static char *copySwiftV1MangledName(const char *string, bool isProtocol = false)
908 if (!string) return nil;
913 for (s = string; *s; s++) {
916 dotIndex = s - string;
919 size_t stringLength = s - string;
921 if (dotCount != 1 || dotIndex == 0 || dotIndex >= stringLength-1) {
925 const char *prefix = string;
926 size_t prefixLength = dotIndex;
927 const char *suffix = string + dotIndex + 1;
928 size_t suffixLength = stringLength - (dotIndex + 1);
932 if (prefixLength == 5 && memcmp(prefix, "Swift", 5) == 0) {
933 asprintf(&name, "_Tt%cs%zu%.*s%s",
934 isProtocol ? 'P' : 'C',
935 suffixLength, (int)suffixLength, suffix,
936 isProtocol ? "_" : "");
938 asprintf(&name, "_Tt%c%zu%.*s%zu%.*s%s",
939 isProtocol ? 'P' : 'C',
940 prefixLength, (int)prefixLength, prefix,
941 suffixLength, (int)suffixLength, suffix,
942 isProtocol ? "_" : "");
948 /***********************************************************************
950 * Looks up a class by name. The class MIGHT NOT be realized.
951 * Demangled Swift names are recognized.
952 * Locking: runtimeLock must be read- or write-locked by the caller.
953 **********************************************************************/
955 // This is a misnomer: gdb_objc_realized_classes is actually a list of
956 // named classes not in the dyld shared cache, whether realized or not.
957 NXMapTable *gdb_objc_realized_classes; // exported for debuggers in objc-gdb.h
959 static Class getClass_impl(const char *name)
961 runtimeLock.assertLocked();
963 // allocated in _read_images
964 assert(gdb_objc_realized_classes);
966 // Try runtime-allocated table
967 Class result = (Class)NXMapGet(gdb_objc_realized_classes, name);
968 if (result) return result;
970 // Try table from dyld shared cache
971 return getPreoptimizedClass(name);
974 static Class getClass(const char *name)
976 runtimeLock.assertLocked();
979 Class result = getClass_impl(name);
980 if (result) return result;
982 // Try Swift-mangled equivalent of the given name.
983 if (char *swName = copySwiftV1MangledName(name)) {
984 result = getClass_impl(swName);
993 /***********************************************************************
995 * Adds name => cls to the named non-meta class map.
996 * Warns about duplicate class names and keeps the old mapping.
997 * Locking: runtimeLock must be held by the caller
998 **********************************************************************/
999 static void addNamedClass(Class cls, const char *name, Class replacing = nil)
1001 runtimeLock.assertWriting();
1003 if ((old = getClass(name)) && old != replacing) {
1004 inform_duplicate(name, old, cls);
1006 // getNonMetaClass uses name lookups. Classes not found by name
1007 // lookup must be in the secondary meta->nonmeta table.
1008 addNonMetaClass(cls);
1010 NXMapInsert(gdb_objc_realized_classes, name, cls);
1012 assert(!(cls->data()->flags & RO_META));
1014 // wrong: constructed classes are already realized when they get here
1015 // assert(!cls->isRealized());
1019 /***********************************************************************
1021 * Removes cls from the name => cls map.
1022 * Locking: runtimeLock must be held by the caller
1023 **********************************************************************/
1024 static void removeNamedClass(Class cls, const char *name)
1026 runtimeLock.assertWriting();
1027 assert(!(cls->data()->flags & RO_META));
1028 if (cls == NXMapGet(gdb_objc_realized_classes, name)) {
1029 NXMapRemove(gdb_objc_realized_classes, name);
1031 // cls has a name collision with another class - don't remove the other
1032 // but do remove cls from the secondary metaclass->class map.
1033 removeNonMetaClass(cls);
1038 /***********************************************************************
1039 * unreasonableClassCount
1040 * Provides an upper bound for any iteration of classes,
1041 * to prevent spins when runtime metadata is corrupted.
1042 **********************************************************************/
1043 unsigned unreasonableClassCount()
1045 runtimeLock.assertLocked();
1047 int base = NXCountMapTable(gdb_objc_realized_classes) +
1048 getPreoptimizedClassUnreasonableCount();
1050 // Provide lots of slack here. Some iterations touch metaclasses too.
1051 // Some iterations backtrack (like realized class iteration).
1052 // We don't need an efficient bound, merely one that prevents spins.
1053 return (base + 1) * 16;
1057 /***********************************************************************
1058 * futureNamedClasses
1059 * Returns the classname => future class map for unrealized future classes.
1060 * Locking: runtimeLock must be held by the caller
1061 **********************************************************************/
1062 static NXMapTable *future_named_class_map = nil;
1063 static NXMapTable *futureNamedClasses()
1065 runtimeLock.assertWriting();
1067 if (future_named_class_map) return future_named_class_map;
1069 // future_named_class_map is big enough for CF's classes and a few others
1070 future_named_class_map =
1071 NXCreateMapTable(NXStrValueMapPrototype, 32);
1073 return future_named_class_map;
1077 static bool haveFutureNamedClasses() {
1078 return future_named_class_map && NXCountMapTable(future_named_class_map);
1082 /***********************************************************************
1083 * addFutureNamedClass
1084 * Installs cls as the class structure to use for the named class if it appears.
1085 * Locking: runtimeLock must be held by the caller
1086 **********************************************************************/
1087 static void addFutureNamedClass(const char *name, Class cls)
1091 runtimeLock.assertWriting();
1094 _objc_inform("FUTURE: reserving %p for %s", (void*)cls, name);
1097 class_rw_t *rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1);
1098 class_ro_t *ro = (class_ro_t *)calloc(sizeof(class_ro_t), 1);
1099 ro->name = strdupIfMutable(name);
1102 cls->data()->flags = RO_FUTURE;
1104 old = NXMapKeyCopyingInsert(futureNamedClasses(), name, cls);
1109 /***********************************************************************
1110 * popFutureNamedClass
1111 * Removes the named class from the unrealized future class list,
1112 * because it has been realized.
1113 * Returns nil if the name is not used by a future class.
1114 * Locking: runtimeLock must be held by the caller
1115 **********************************************************************/
1116 static Class popFutureNamedClass(const char *name)
1118 runtimeLock.assertWriting();
1122 if (future_named_class_map) {
1123 cls = (Class)NXMapKeyFreeingRemove(future_named_class_map, name);
1124 if (cls && NXCountMapTable(future_named_class_map) == 0) {
1125 NXFreeMapTable(future_named_class_map);
1126 future_named_class_map = nil;
1134 /***********************************************************************
1136 * Returns the oldClass => newClass map for realized future classes.
1137 * Returns the oldClass => nil map for ignored weak-linked classes.
1138 * Locking: runtimeLock must be read- or write-locked by the caller
1139 **********************************************************************/
1140 static NXMapTable *remappedClasses(bool create)
1142 static NXMapTable *remapped_class_map = nil;
1144 runtimeLock.assertLocked();
1146 if (remapped_class_map) return remapped_class_map;
1147 if (!create) return nil;
1149 // remapped_class_map is big enough to hold CF's classes and a few others
1150 INIT_ONCE_PTR(remapped_class_map,
1151 NXCreateMapTable(NXPtrValueMapPrototype, 32),
1154 return remapped_class_map;
1158 /***********************************************************************
1160 * Returns YES if no classes have been remapped
1161 * Locking: runtimeLock must be read- or write-locked by the caller
1162 **********************************************************************/
1163 static bool noClassesRemapped(void)
1165 runtimeLock.assertLocked();
1167 bool result = (remappedClasses(NO) == nil);
1169 // Catch construction of an empty table, which defeats optimization.
1170 NXMapTable *map = remappedClasses(NO);
1171 if (map) assert(NXCountMapTable(map) > 0);
1177 /***********************************************************************
1179 * newcls is a realized future class, replacing oldcls.
1180 * OR newcls is nil, replacing ignored weak-linked class oldcls.
1181 * Locking: runtimeLock must be write-locked by the caller
1182 **********************************************************************/
1183 static void addRemappedClass(Class oldcls, Class newcls)
1185 runtimeLock.assertWriting();
1188 _objc_inform("FUTURE: using %p instead of %p for %s",
1189 (void*)newcls, (void*)oldcls, oldcls->nameForLogging());
1193 old = NXMapInsert(remappedClasses(YES), oldcls, newcls);
1198 /***********************************************************************
1200 * Returns the live class pointer for cls, which may be pointing to
1201 * a class struct that has been reallocated.
1202 * Returns nil if cls is ignored because of weak linking.
1203 * Locking: runtimeLock must be read- or write-locked by the caller
1204 **********************************************************************/
1205 static Class remapClass(Class cls)
1207 runtimeLock.assertLocked();
1211 if (!cls) return nil;
1213 NXMapTable *map = remappedClasses(NO);
1214 if (!map || NXMapMember(map, cls, (void**)&c2) == NX_MAPNOTAKEY) {
1221 static Class remapClass(classref_t cls)
1223 return remapClass((Class)cls);
1226 Class _class_remap(Class cls)
1228 rwlock_reader_t lock(runtimeLock);
1229 return remapClass(cls);
1232 /***********************************************************************
1234 * Fix up a class ref, in case the class referenced has been reallocated
1235 * or is an ignored weak-linked class.
1236 * Locking: runtimeLock must be read- or write-locked by the caller
1237 **********************************************************************/
1238 static void remapClassRef(Class *clsref)
1240 runtimeLock.assertLocked();
1242 Class newcls = remapClass(*clsref);
1243 if (*clsref != newcls) *clsref = newcls;
1247 /***********************************************************************
1249 * Return the ordinary class for this class or metaclass.
1250 * `inst` is an instance of `cls` or a subclass thereof, or nil.
1251 * Non-nil inst is faster.
1252 * Used by +initialize.
1253 * Locking: runtimeLock must be read- or write-locked by the caller
1254 **********************************************************************/
1255 static Class getNonMetaClass(Class metacls, id inst)
1257 static int total, named, secondary, sharedcache;
1258 runtimeLock.assertLocked();
1260 realizeClass(metacls);
1264 // return cls itself if it's already a non-meta class
1265 if (!metacls->isMetaClass()) return metacls;
1267 // metacls really is a metaclass
1269 // special case for root metaclass
1270 // where inst == inst->ISA() == metacls is possible
1271 if (metacls->ISA() == metacls) {
1272 Class cls = metacls->superclass;
1273 assert(cls->isRealized());
1274 assert(!cls->isMetaClass());
1275 assert(cls->ISA() == metacls);
1276 if (cls->ISA() == metacls) return cls;
1279 // use inst if available
1281 Class cls = (Class)inst;
1283 // cls may be a subclass - find the real class for metacls
1284 while (cls && cls->ISA() != metacls) {
1285 cls = cls->superclass;
1289 assert(!cls->isMetaClass());
1290 assert(cls->ISA() == metacls);
1294 _objc_fatal("cls is not an instance of metacls");
1296 // release build: be forgiving and fall through to slow lookups
1302 Class cls = getClass(metacls->mangledName());
1303 if (cls->ISA() == metacls) {
1305 if (PrintInitializing) {
1306 _objc_inform("INITIALIZE: %d/%d (%g%%) "
1307 "successful by-name metaclass lookups",
1308 named, total, named*100.0/total);
1316 // try secondary table
1318 Class cls = (Class)NXMapGet(nonMetaClasses(), metacls);
1321 if (PrintInitializing) {
1322 _objc_inform("INITIALIZE: %d/%d (%g%%) "
1323 "successful secondary metaclass lookups",
1324 secondary, total, secondary*100.0/total);
1327 assert(cls->ISA() == metacls);
1333 // try any duplicates in the dyld shared cache
1338 Class *classes = copyPreoptimizedClasses(metacls->mangledName(),&count);
1340 for (int i = 0; i < count; i++) {
1341 if (classes[i]->ISA() == metacls) {
1351 if (PrintInitializing) {
1352 _objc_inform("INITIALIZE: %d/%d (%g%%) "
1353 "successful shared cache metaclass lookups",
1354 sharedcache, total, sharedcache*100.0/total);
1362 _objc_fatal("no class for metaclass %p", (void*)metacls);
1366 /***********************************************************************
1367 * _class_getNonMetaClass
1368 * Return the ordinary class for this class or metaclass.
1369 * Used by +initialize.
1370 * Locking: acquires runtimeLock
1371 **********************************************************************/
1372 Class _class_getNonMetaClass(Class cls, id obj)
1374 rwlock_writer_t lock(runtimeLock);
1375 cls = getNonMetaClass(cls, obj);
1376 assert(cls->isRealized());
1381 /***********************************************************************
1383 * Adds cls as a new realized root class.
1384 * Locking: runtimeLock must be held by the caller.
1385 **********************************************************************/
1386 static Class _firstRealizedClass = nil;
1387 Class firstRealizedClass()
1389 runtimeLock.assertLocked();
1390 return _firstRealizedClass;
1393 static void addRootClass(Class cls)
1395 runtimeLock.assertWriting();
1397 assert(cls->isRealized());
1398 cls->data()->nextSiblingClass = _firstRealizedClass;
1399 _firstRealizedClass = cls;
1402 static void removeRootClass(Class cls)
1404 runtimeLock.assertWriting();
1407 for (classp = &_firstRealizedClass;
1409 classp = &(*classp)->data()->nextSiblingClass)
1412 *classp = (*classp)->data()->nextSiblingClass;
1416 /***********************************************************************
1418 * Adds subcls as a subclass of supercls.
1419 * Locking: runtimeLock must be held by the caller.
1420 **********************************************************************/
1421 static void addSubclass(Class supercls, Class subcls)
1423 runtimeLock.assertWriting();
1425 if (supercls && subcls) {
1426 assert(supercls->isRealized());
1427 assert(subcls->isRealized());
1428 subcls->data()->nextSiblingClass = supercls->data()->firstSubclass;
1429 supercls->data()->firstSubclass = subcls;
1431 if (supercls->hasCxxCtor()) {
1432 subcls->setHasCxxCtor();
1435 if (supercls->hasCxxDtor()) {
1436 subcls->setHasCxxDtor();
1439 if (supercls->hasCustomRR()) {
1440 subcls->setHasCustomRR(true);
1443 if (supercls->hasCustomAWZ()) {
1444 subcls->setHasCustomAWZ(true);
1447 // Special case: instancesRequireRawIsa does not propagate
1448 // from root class to root metaclass
1449 if (supercls->instancesRequireRawIsa() && supercls->superclass) {
1450 subcls->setInstancesRequireRawIsa(true);
1456 /***********************************************************************
1458 * Removes subcls as a subclass of supercls.
1459 * Locking: runtimeLock must be held by the caller.
1460 **********************************************************************/
1461 static void removeSubclass(Class supercls, Class subcls)
1463 runtimeLock.assertWriting();
1464 assert(supercls->isRealized());
1465 assert(subcls->isRealized());
1466 assert(subcls->superclass == supercls);
1469 for (cp = &supercls->data()->firstSubclass;
1470 *cp && *cp != subcls;
1471 cp = &(*cp)->data()->nextSiblingClass)
1473 assert(*cp == subcls);
1474 *cp = subcls->data()->nextSiblingClass;
1479 /***********************************************************************
1481 * Returns the protocol name => protocol map for protocols.
1482 * Locking: runtimeLock must read- or write-locked by the caller
1483 **********************************************************************/
1484 static NXMapTable *protocols(void)
1486 static NXMapTable *protocol_map = nil;
1488 runtimeLock.assertLocked();
1490 INIT_ONCE_PTR(protocol_map,
1491 NXCreateMapTable(NXStrValueMapPrototype, 16),
1492 NXFreeMapTable(v) );
1494 return protocol_map;
1498 /***********************************************************************
1500 * Looks up a protocol by name. Demangled Swift names are recognized.
1501 * Locking: runtimeLock must be read- or write-locked by the caller.
1502 **********************************************************************/
1503 static Protocol *getProtocol(const char *name)
1505 runtimeLock.assertLocked();
1508 Protocol *result = (Protocol *)NXMapGet(protocols(), name);
1509 if (result) return result;
1511 // Try Swift-mangled equivalent of the given name.
1512 if (char *swName = copySwiftV1MangledName(name, true/*isProtocol*/)) {
1513 result = (Protocol *)NXMapGet(protocols(), swName);
1522 /***********************************************************************
1524 * Returns the live protocol pointer for proto, which may be pointing to
1525 * a protocol struct that has been reallocated.
1526 * Locking: runtimeLock must be read- or write-locked by the caller
1527 **********************************************************************/
1528 static protocol_t *remapProtocol(protocol_ref_t proto)
1530 runtimeLock.assertLocked();
1532 protocol_t *newproto = (protocol_t *)
1533 getProtocol(((protocol_t *)proto)->mangledName);
1534 return newproto ? newproto : (protocol_t *)proto;
1538 /***********************************************************************
1540 * Fix up a protocol ref, in case the protocol referenced has been reallocated.
1541 * Locking: runtimeLock must be read- or write-locked by the caller
1542 **********************************************************************/
1543 static size_t UnfixedProtocolReferences;
1544 static void remapProtocolRef(protocol_t **protoref)
1546 runtimeLock.assertLocked();
1548 protocol_t *newproto = remapProtocol((protocol_ref_t)*protoref);
1549 if (*protoref != newproto) {
1550 *protoref = newproto;
1551 UnfixedProtocolReferences++;
1556 /***********************************************************************
1558 * Slides a class's ivars to accommodate the given superclass size.
1559 * Ivars are NOT compacted to compensate for a superclass that shrunk.
1560 * Locking: runtimeLock must be held by the caller.
1561 **********************************************************************/
1562 static void moveIvars(class_ro_t *ro, uint32_t superSize)
1564 runtimeLock.assertWriting();
1568 assert(superSize > ro->instanceStart);
1569 diff = superSize - ro->instanceStart;
1572 // Find maximum alignment in this class's ivars
1573 uint32_t maxAlignment = 1;
1574 for (const auto& ivar : *ro->ivars) {
1575 if (!ivar.offset) continue; // anonymous bitfield
1577 uint32_t alignment = ivar.alignment();
1578 if (alignment > maxAlignment) maxAlignment = alignment;
1581 // Compute a slide value that preserves that alignment
1582 uint32_t alignMask = maxAlignment - 1;
1583 diff = (diff + alignMask) & ~alignMask;
1585 // Slide all of this class's ivars en masse
1586 for (const auto& ivar : *ro->ivars) {
1587 if (!ivar.offset) continue; // anonymous bitfield
1589 uint32_t oldOffset = (uint32_t)*ivar.offset;
1590 uint32_t newOffset = oldOffset + diff;
1591 *ivar.offset = newOffset;
1594 _objc_inform("IVARS: offset %u -> %u for %s "
1595 "(size %u, align %u)",
1596 oldOffset, newOffset, ivar.name,
1597 ivar.size, ivar.alignment());
1602 *(uint32_t *)&ro->instanceStart += diff;
1603 *(uint32_t *)&ro->instanceSize += diff;
1607 static void reconcileInstanceVariables(Class cls, Class supercls, const class_ro_t*& ro)
1609 class_rw_t *rw = cls->data();
1612 assert(!cls->isMetaClass());
1614 /* debug: print them all before sliding
1616 for (const auto& ivar : *ro->ivars) {
1617 if (!ivar.offset) continue; // anonymous bitfield
1619 _objc_inform("IVARS: %s.%s (offset %u, size %u, align %u)",
1620 ro->name, ivar.name,
1621 *ivar.offset, ivar.size, ivar.alignment());
1626 // Non-fragile ivars - reconcile this class with its superclass
1627 const class_ro_t *super_ro = supercls->data()->ro;
1629 if (DebugNonFragileIvars) {
1630 // Debugging: Force non-fragile ivars to slide.
1631 // Intended to find compiler, runtime, and program bugs.
1632 // If it fails with this and works without, you have a problem.
1634 // Operation: Reset everything to 0 + misalignment.
1635 // Then force the normal sliding logic to push everything back.
1637 // Exceptions: root classes, metaclasses, *NSCF* classes,
1638 // __CF* classes, NSConstantString, NSSimpleCString
1640 // (already know it's not root because supercls != nil)
1641 const char *clsname = cls->mangledName();
1642 if (!strstr(clsname, "NSCF") &&
1643 0 != strncmp(clsname, "__CF", 4) &&
1644 0 != strcmp(clsname, "NSConstantString") &&
1645 0 != strcmp(clsname, "NSSimpleCString"))
1647 uint32_t oldStart = ro->instanceStart;
1648 class_ro_t *ro_w = make_ro_writeable(rw);
1651 // Find max ivar alignment in class.
1652 // default to word size to simplify ivar update
1653 uint32_t alignment = 1<<WORD_SHIFT;
1655 for (const auto& ivar : *ro->ivars) {
1656 if (ivar.alignment() > alignment) {
1657 alignment = ivar.alignment();
1661 uint32_t misalignment = ro->instanceStart % alignment;
1662 uint32_t delta = ro->instanceStart - misalignment;
1663 ro_w->instanceStart = misalignment;
1664 ro_w->instanceSize -= delta;
1667 _objc_inform("IVARS: DEBUG: forcing ivars for class '%s' "
1668 "to slide (instanceStart %zu -> %zu)",
1669 cls->nameForLogging(), (size_t)oldStart,
1670 (size_t)ro->instanceStart);
1674 for (const auto& ivar : *ro->ivars) {
1675 if (!ivar.offset) continue; // anonymous bitfield
1676 *ivar.offset -= delta;
1682 if (ro->instanceStart >= super_ro->instanceSize) {
1683 // Superclass has not overgrown its space. We're done here.
1686 // fixme can optimize for "class has no new ivars", etc
1688 if (ro->instanceStart < super_ro->instanceSize) {
1689 // Superclass has changed size. This class's ivars must move.
1690 // Also slide layout bits in parallel.
1691 // This code is incapable of compacting the subclass to
1692 // compensate for a superclass that shrunk, so don't do that.
1694 _objc_inform("IVARS: sliding ivars for class %s "
1695 "(superclass was %u bytes, now %u)",
1696 cls->nameForLogging(), ro->instanceStart,
1697 super_ro->instanceSize);
1699 class_ro_t *ro_w = make_ro_writeable(rw);
1701 moveIvars(ro_w, super_ro->instanceSize);
1702 gdb_objc_class_changed(cls, OBJC_CLASS_IVARS_CHANGED, ro->name);
1707 /***********************************************************************
1709 * Performs first-time initialization on class cls,
1710 * including allocating its read-write data.
1711 * Returns the real class structure for the class.
1712 * Locking: runtimeLock must be write-locked by the caller
1713 **********************************************************************/
1714 static Class realizeClass(Class cls)
1716 runtimeLock.assertWriting();
1718 const class_ro_t *ro;
1724 if (!cls) return nil;
1725 if (cls->isRealized()) return cls;
1726 assert(cls == remapClass(cls));
1728 // fixme verify class is not in an un-dlopened part of the shared cache?
1730 ro = (const class_ro_t *)cls->data();
1731 if (ro->flags & RO_FUTURE) {
1732 // This was a future class. rw data is already allocated.
1734 ro = cls->data()->ro;
1735 cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
1737 // Normal class. Allocate writeable class data.
1738 rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1);
1740 rw->flags = RW_REALIZED|RW_REALIZING;
1744 isMeta = ro->flags & RO_META;
1746 rw->version = isMeta ? 7 : 0; // old runtime went up to 6
1749 // Choose an index for this class.
1750 // Sets cls->instancesRequireRawIsa if indexes no more indexes are available
1751 cls->chooseClassArrayIndex();
1753 if (PrintConnecting) {
1754 _objc_inform("CLASS: realizing class '%s'%s %p %p #%u",
1755 cls->nameForLogging(), isMeta ? " (meta)" : "",
1756 (void*)cls, ro, cls->classArrayIndex());
1759 // Realize superclass and metaclass, if they aren't already.
1760 // This needs to be done after RW_REALIZED is set above, for root classes.
1761 // This needs to be done after class index is chosen, for root metaclasses.
1762 supercls = realizeClass(remapClass(cls->superclass));
1763 metacls = realizeClass(remapClass(cls->ISA()));
1765 #if SUPPORT_NONPOINTER_ISA
1766 // Disable non-pointer isa for some classes and/or platforms.
1767 // Set instancesRequireRawIsa.
1768 bool instancesRequireRawIsa = cls->instancesRequireRawIsa();
1769 bool rawIsaIsInherited = false;
1770 static bool hackedDispatch = false;
1772 if (DisableNonpointerIsa) {
1773 // Non-pointer isa disabled by environment or app SDK version
1774 instancesRequireRawIsa = true;
1776 else if (!hackedDispatch && !(ro->flags & RO_META) &&
1777 0 == strcmp(ro->name, "OS_object"))
1779 // hack for libdispatch et al - isa also acts as vtable pointer
1780 hackedDispatch = true;
1781 instancesRequireRawIsa = true;
1783 else if (supercls && supercls->superclass &&
1784 supercls->instancesRequireRawIsa())
1786 // This is also propagated by addSubclass()
1787 // but nonpointer isa setup needs it earlier.
1788 // Special case: instancesRequireRawIsa does not propagate
1789 // from root class to root metaclass
1790 instancesRequireRawIsa = true;
1791 rawIsaIsInherited = true;
1794 if (instancesRequireRawIsa) {
1795 cls->setInstancesRequireRawIsa(rawIsaIsInherited);
1797 // SUPPORT_NONPOINTER_ISA
1800 // Update superclass and metaclass in case of remapping
1801 cls->superclass = supercls;
1802 cls->initClassIsa(metacls);
1804 // Reconcile instance variable offsets / layout.
1805 // This may reallocate class_ro_t, updating our ro variable.
1806 if (supercls && !isMeta) reconcileInstanceVariables(cls, supercls, ro);
1808 // Set fastInstanceSize if it wasn't set already.
1809 cls->setInstanceSize(ro->instanceSize);
1811 // Copy some flags from ro to rw
1812 if (ro->flags & RO_HAS_CXX_STRUCTORS) {
1813 cls->setHasCxxDtor();
1814 if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
1815 cls->setHasCxxCtor();
1819 // Connect this class to its superclass's subclass lists
1821 addSubclass(supercls, cls);
1826 // Attach categories
1827 methodizeClass(cls);
1833 /***********************************************************************
1834 * missingWeakSuperclass
1835 * Return YES if some superclass of cls was weak-linked and is missing.
1836 **********************************************************************/
1838 missingWeakSuperclass(Class cls)
1840 assert(!cls->isRealized());
1842 if (!cls->superclass) {
1843 // superclass nil. This is normal for root classes only.
1844 return (!(cls->data()->flags & RO_ROOT));
1846 // superclass not nil. Check if a higher superclass is missing.
1847 Class supercls = remapClass(cls->superclass);
1848 assert(cls != cls->superclass);
1849 assert(cls != supercls);
1850 if (!supercls) return YES;
1851 if (supercls->isRealized()) return NO;
1852 return missingWeakSuperclass(supercls);
1857 /***********************************************************************
1858 * realizeAllClassesInImage
1859 * Non-lazily realizes all unrealized classes in the given image.
1860 * Locking: runtimeLock must be held by the caller.
1861 **********************************************************************/
1862 static void realizeAllClassesInImage(header_info *hi)
1864 runtimeLock.assertWriting();
1867 classref_t *classlist;
1869 if (hi->areAllClassesRealized()) return;
1871 classlist = _getObjc2ClassList(hi, &count);
1873 for (i = 0; i < count; i++) {
1874 realizeClass(remapClass(classlist[i]));
1877 hi->setAllClassesRealized(YES);
1881 /***********************************************************************
1883 * Non-lazily realizes all unrealized classes in all known images.
1884 * Locking: runtimeLock must be held by the caller.
1885 **********************************************************************/
1886 static void realizeAllClasses(void)
1888 runtimeLock.assertWriting();
1891 for (hi = FirstHeader; hi; hi = hi->getNext()) {
1892 realizeAllClassesInImage(hi);
1897 /***********************************************************************
1898 * _objc_allocateFutureClass
1899 * Allocate an unresolved future class for the given class name.
1900 * Returns any existing allocation if one was already made.
1901 * Assumes the named class doesn't exist yet.
1902 * Locking: acquires runtimeLock
1903 **********************************************************************/
1904 Class _objc_allocateFutureClass(const char *name)
1906 rwlock_writer_t lock(runtimeLock);
1909 NXMapTable *map = futureNamedClasses();
1911 if ((cls = (Class)NXMapGet(map, name))) {
1912 // Already have a future class for this name.
1916 cls = _calloc_class(sizeof(objc_class));
1917 addFutureNamedClass(name, cls);
1923 /***********************************************************************
1924 * objc_getFutureClass. Return the id of the named class.
1925 * If the class does not exist, return an uninitialized class
1926 * structure that will be used for the class when and if it
1929 **********************************************************************/
1930 Class objc_getFutureClass(const char *name)
1934 // YES unconnected, NO class handler
1935 // (unconnected is OK because it will someday be the real class)
1936 cls = look_up_class(name, YES, NO);
1939 _objc_inform("FUTURE: found %p already in use for %s",
1946 // No class or future class with that name yet. Make one.
1947 // fixme not thread-safe with respect to
1948 // simultaneous library load or getFutureClass.
1949 return _objc_allocateFutureClass(name);
1953 BOOL _class_isFutureClass(Class cls)
1955 return cls && cls->isFuture();
1959 /***********************************************************************
1960 * _objc_flush_caches
1961 * Flushes all caches.
1962 * (Historical behavior: flush caches for cls, its metaclass,
1963 * and subclasses thereof. Nil flushes all classes.)
1964 * Locking: acquires runtimeLock
1965 **********************************************************************/
1966 static void flushCaches(Class cls)
1968 runtimeLock.assertWriting();
1970 mutex_locker_t lock(cacheUpdateLock);
1973 foreach_realized_class_and_subclass(cls, ^(Class c){
1974 cache_erase_nolock(c);
1978 foreach_realized_class_and_metaclass(^(Class c){
1979 cache_erase_nolock(c);
1985 void _objc_flush_caches(Class cls)
1988 rwlock_writer_t lock(runtimeLock);
1990 if (cls && cls->superclass && cls != cls->getIsa()) {
1991 flushCaches(cls->getIsa());
1993 // cls is a root class or root metaclass. Its metaclass is itself
1994 // or a subclass so the metaclass caches were already flushed.
1999 // collectALot if cls==nil
2000 mutex_locker_t lock(cacheUpdateLock);
2001 cache_collect(true);
2006 /***********************************************************************
2008 * Process the given images which are being mapped in by dyld.
2009 * Calls ABI-agnostic code after taking ABI-specific locks.
2011 * Locking: write-locks runtimeLock
2012 **********************************************************************/
2014 map_images(unsigned count, const char * const paths[],
2015 const struct mach_header * const mhdrs[])
2017 rwlock_writer_t lock(runtimeLock);
2018 return map_images_nolock(count, paths, mhdrs);
2022 /***********************************************************************
2024 * Process +load in the given images which are being mapped in by dyld.
2026 * Locking: write-locks runtimeLock and loadMethodLock
2027 **********************************************************************/
2028 extern bool hasLoadMethods(const headerType *mhdr);
2029 extern void prepare_load_methods(const headerType *mhdr);
2032 load_images(const char *path __unused, const struct mach_header *mh)
2034 // Return without taking locks if there are no +load methods here.
2035 if (!hasLoadMethods((const headerType *)mh)) return;
2037 recursive_mutex_locker_t lock(loadMethodLock);
2039 // Discover load methods
2041 rwlock_writer_t lock2(runtimeLock);
2042 prepare_load_methods((const headerType *)mh);
2045 // Call +load methods (without runtimeLock - re-entrant)
2046 call_load_methods();
2050 /***********************************************************************
2052 * Process the given image which is about to be unmapped by dyld.
2054 * Locking: write-locks runtimeLock and loadMethodLock
2055 **********************************************************************/
2057 unmap_image(const char *path __unused, const struct mach_header *mh)
2059 recursive_mutex_locker_t lock(loadMethodLock);
2060 rwlock_writer_t lock2(runtimeLock);
2061 unmap_image_nolock(mh);
2067 /***********************************************************************
2069 * Preflight check in advance of readClass() from an image.
2070 **********************************************************************/
2071 bool mustReadClasses(header_info *hi)
2075 // If the image is not preoptimized then we must read classes.
2076 if (!hi->isPreoptimized()) {
2077 reason = nil; // Don't log this one because it is noisy.
2081 // If iOS simulator then we must read classes.
2082 #if TARGET_OS_SIMULATOR
2083 reason = "the image is for iOS simulator";
2087 assert(!hi->isBundle()); // no MH_BUNDLE in shared cache
2089 // If the image may have missing weak superclasses then we must read classes
2090 if (!noMissingWeakSuperclasses()) {
2091 reason = "the image may contain classes with missing weak superclasses";
2095 // If there are unresolved future classes then we must read classes.
2096 if (haveFutureNamedClasses()) {
2097 reason = "there are unresolved future classes pending";
2101 // readClass() does not need to do anything.
2105 if (PrintPreopt && reason) {
2106 _objc_inform("PREOPTIMIZATION: reading classes manually from %s "
2107 "because %s", hi->fname(), reason);
2113 /***********************************************************************
2115 * Read a class and metaclass as written by a compiler.
2116 * Returns the new class pointer. This could be:
2118 * - nil (cls has a missing weak-linked superclass)
2119 * - something else (space for this class was reserved by a future class)
2121 * Note that all work performed by this function is preflighted by
2122 * mustReadClasses(). Do not change this function without updating that one.
2124 * Locking: runtimeLock acquired by map_images or objc_readClassPair
2125 **********************************************************************/
2126 Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
2128 const char *mangledName = cls->mangledName();
2130 if (missingWeakSuperclass(cls)) {
2131 // No superclass (probably weak-linked).
2132 // Disavow any knowledge of this subclass.
2133 if (PrintConnecting) {
2134 _objc_inform("CLASS: IGNORING class '%s' with "
2135 "missing weak-linked superclass",
2136 cls->nameForLogging());
2138 addRemappedClass(cls, nil);
2139 cls->superclass = nil;
2143 // Note: Class __ARCLite__'s hack does not go through here.
2144 // Class structure fixups that apply to it also need to be
2145 // performed in non-lazy realization below.
2147 // These fields should be set to zero because of the
2148 // binding of _objc_empty_vtable, but OS X 10.8's dyld
2149 // does not bind shared cache absolute symbols as expected.
2150 // This (and the __ARCLite__ hack below) can be removed
2151 // once the simulator drops 10.8 support.
2152 #if TARGET_OS_SIMULATOR
2153 if (cls->cache._mask) cls->cache._mask = 0;
2154 if (cls->cache._occupied) cls->cache._occupied = 0;
2155 if (cls->ISA()->cache._mask) cls->ISA()->cache._mask = 0;
2156 if (cls->ISA()->cache._occupied) cls->ISA()->cache._occupied = 0;
2159 Class replacing = nil;
2160 if (Class newCls = popFutureNamedClass(mangledName)) {
2161 // This name was previously allocated as a future class.
2162 // Copy objc_class to future class's struct.
2163 // Preserve future's rw data block.
2165 if (newCls->isSwift()) {
2166 _objc_fatal("Can't complete future class request for '%s' "
2167 "because the real class is too big.",
2168 cls->nameForLogging());
2171 class_rw_t *rw = newCls->data();
2172 const class_ro_t *old_ro = rw->ro;
2173 memcpy(newCls, cls, sizeof(objc_class));
2174 rw->ro = (class_ro_t *)newCls->data();
2175 newCls->setData(rw);
2176 freeIfMutable((char *)old_ro->name);
2177 free((void *)old_ro);
2179 addRemappedClass(cls, newCls);
2185 if (headerIsPreoptimized && !replacing) {
2186 // class list built in shared cache
2187 // fixme strict assert doesn't work because of duplicates
2188 // assert(cls == getClass(name));
2189 assert(getClass(mangledName));
2191 addNamedClass(cls, mangledName, replacing);
2194 // for future reference: shared cache never contains MH_BUNDLEs
2195 if (headerIsBundle) {
2196 cls->data()->flags |= RO_FROM_BUNDLE;
2197 cls->ISA()->data()->flags |= RO_FROM_BUNDLE;
2204 /***********************************************************************
2206 * Read a protocol as written by a compiler.
2207 **********************************************************************/
2209 readProtocol(protocol_t *newproto, Class protocol_class,
2210 NXMapTable *protocol_map,
2211 bool headerIsPreoptimized, bool headerIsBundle)
2213 // This is not enough to make protocols in unloaded bundles safe,
2214 // but it does prevent crashes when looking up unrelated protocols.
2215 auto insertFn = headerIsBundle ? NXMapKeyCopyingInsert : NXMapInsert;
2217 protocol_t *oldproto = (protocol_t *)getProtocol(newproto->mangledName);
2220 // Some other definition already won.
2221 if (PrintProtocols) {
2222 _objc_inform("PROTOCOLS: protocol at %p is %s "
2223 "(duplicate of %p)",
2224 newproto, oldproto->nameForLogging(), oldproto);
2227 else if (headerIsPreoptimized) {
2228 // Shared cache initialized the protocol object itself,
2229 // but in order to allow out-of-cache replacement we need
2230 // to add it to the protocol table now.
2232 protocol_t *cacheproto = (protocol_t *)
2233 getPreoptimizedProtocol(newproto->mangledName);
2234 protocol_t *installedproto;
2235 if (cacheproto && cacheproto != newproto) {
2236 // Another definition in the shared cache wins (because
2237 // everything in the cache was fixed up to point to it).
2238 installedproto = cacheproto;
2241 // This definition wins.
2242 installedproto = newproto;
2245 assert(installedproto->getIsa() == protocol_class);
2246 assert(installedproto->size >= sizeof(protocol_t));
2247 insertFn(protocol_map, installedproto->mangledName,
2250 if (PrintProtocols) {
2251 _objc_inform("PROTOCOLS: protocol at %p is %s",
2252 installedproto, installedproto->nameForLogging());
2253 if (newproto != installedproto) {
2254 _objc_inform("PROTOCOLS: protocol at %p is %s "
2255 "(duplicate of %p)",
2256 newproto, installedproto->nameForLogging(),
2261 else if (newproto->size >= sizeof(protocol_t)) {
2262 // New protocol from an un-preoptimized image
2263 // with sufficient storage. Fix it up in place.
2264 // fixme duplicate protocols from unloadable bundle
2265 newproto->initIsa(protocol_class); // fixme pinned
2266 insertFn(protocol_map, newproto->mangledName, newproto);
2267 if (PrintProtocols) {
2268 _objc_inform("PROTOCOLS: protocol at %p is %s",
2269 newproto, newproto->nameForLogging());
2273 // New protocol from an un-preoptimized image
2274 // with insufficient storage. Reallocate it.
2275 // fixme duplicate protocols from unloadable bundle
2276 size_t size = max(sizeof(protocol_t), (size_t)newproto->size);
2277 protocol_t *installedproto = (protocol_t *)calloc(size, 1);
2278 memcpy(installedproto, newproto, newproto->size);
2279 installedproto->size = (typeof(installedproto->size))size;
2281 installedproto->initIsa(protocol_class); // fixme pinned
2282 insertFn(protocol_map, installedproto->mangledName, installedproto);
2283 if (PrintProtocols) {
2284 _objc_inform("PROTOCOLS: protocol at %p is %s ",
2285 installedproto, installedproto->nameForLogging());
2286 _objc_inform("PROTOCOLS: protocol at %p is %s "
2287 "(reallocated to %p)",
2288 newproto, installedproto->nameForLogging(),
2294 /***********************************************************************
2296 * Perform initial processing of the headers in the linked
2297 * list beginning with headerList.
2299 * Called by: map_images_nolock
2301 * Locking: runtimeLock acquired by map_images
2302 **********************************************************************/
2303 void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClasses)
2309 Class *resolvedFutureClasses = nil;
2310 size_t resolvedFutureClassCount = 0;
2311 static bool doneOnce;
2312 TimeLogger ts(PrintImageTimes);
2314 runtimeLock.assertWriting();
2316 #define EACH_HEADER \
2318 hIndex < hCount && (hi = hList[hIndex]); \
2324 #if SUPPORT_NONPOINTER_ISA
2325 // Disable non-pointer isa under some conditions.
2327 # if SUPPORT_INDEXED_ISA
2328 // Disable nonpointer isa if any image contains old Swift code
2330 if (hi->info()->containsSwift() &&
2331 hi->info()->swiftVersion() < objc_image_info::SwiftVersion3)
2333 DisableNonpointerIsa = true;
2335 _objc_inform("RAW ISA: disabling non-pointer isa because "
2336 "the app or a framework contains Swift code "
2337 "older than Swift 3.0");
2345 // Disable non-pointer isa if the app is too old
2346 // (linked before OS X 10.11)
2347 if (dyld_get_program_sdk_version() < DYLD_MACOSX_VERSION_10_11) {
2348 DisableNonpointerIsa = true;
2350 _objc_inform("RAW ISA: disabling non-pointer isa because "
2351 "the app is too old (SDK version " SDK_FORMAT ")",
2352 FORMAT_SDK(dyld_get_program_sdk_version()));
2356 // Disable non-pointer isa if the app has a __DATA,__objc_rawisa section
2357 // New apps that load old extensions may need this.
2359 if (hi->mhdr()->filetype != MH_EXECUTE) continue;
2361 if (getsectiondata(hi->mhdr(), "__DATA", "__objc_rawisa", &size)) {
2362 DisableNonpointerIsa = true;
2364 _objc_inform("RAW ISA: disabling non-pointer isa because "
2365 "the app has a __DATA,__objc_rawisa section");
2368 break; // assume only one MH_EXECUTE image
2374 if (DisableTaggedPointers) {
2375 disableTaggedPointers();
2378 if (PrintConnecting) {
2379 _objc_inform("CLASS: found %d classes during launch", totalClasses);
2383 // Preoptimized classes don't go in this table.
2384 // 4/3 is NXMapTable's load factor
2385 int namedClassesSize =
2386 (isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
2387 gdb_objc_realized_classes =
2388 NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
2390 ts.log("IMAGE TIMES: first time tasks");
2394 // Discover classes. Fix up unresolved future classes. Mark bundle classes.
2397 if (! mustReadClasses(hi)) {
2398 // Image is sufficiently optimized that we need not call readClass()
2402 bool headerIsBundle = hi->isBundle();
2403 bool headerIsPreoptimized = hi->isPreoptimized();
2405 classref_t *classlist = _getObjc2ClassList(hi, &count);
2406 for (i = 0; i < count; i++) {
2407 Class cls = (Class)classlist[i];
2408 Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
2410 if (newCls != cls && newCls) {
2411 // Class was moved but not deleted. Currently this occurs
2412 // only when the new class resolved a future class.
2413 // Non-lazily realize the class below.
2414 resolvedFutureClasses = (Class *)
2415 realloc(resolvedFutureClasses,
2416 (resolvedFutureClassCount+1) * sizeof(Class));
2417 resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
2422 ts.log("IMAGE TIMES: discover classes");
2424 // Fix up remapped classes
2425 // Class list and nonlazy class list remain unremapped.
2426 // Class refs and super refs are remapped for message dispatching.
2428 if (!noClassesRemapped()) {
2430 Class *classrefs = _getObjc2ClassRefs(hi, &count);
2431 for (i = 0; i < count; i++) {
2432 remapClassRef(&classrefs[i]);
2434 // fixme why doesn't test future1 catch the absence of this?
2435 classrefs = _getObjc2SuperRefs(hi, &count);
2436 for (i = 0; i < count; i++) {
2437 remapClassRef(&classrefs[i]);
2442 ts.log("IMAGE TIMES: remap classes");
2444 // Fix up @selector references
2445 static size_t UnfixedSelectors;
2448 if (hi->isPreoptimized()) continue;
2450 bool isBundle = hi->isBundle();
2451 SEL *sels = _getObjc2SelectorRefs(hi, &count);
2452 UnfixedSelectors += count;
2453 for (i = 0; i < count; i++) {
2454 const char *name = sel_cname(sels[i]);
2455 sels[i] = sel_registerNameNoLock(name, isBundle);
2460 ts.log("IMAGE TIMES: fix up selector references");
2463 // Fix up old objc_msgSend_fixup call sites
2465 message_ref_t *refs = _getObjc2MessageRefs(hi, &count);
2466 if (count == 0) continue;
2469 _objc_inform("VTABLES: repairing %zu unsupported vtable dispatch "
2470 "call sites in %s", count, hi->fname());
2472 for (i = 0; i < count; i++) {
2473 fixupMessageRef(refs+i);
2477 ts.log("IMAGE TIMES: fix up objc_msgSend_fixup");
2480 // Discover protocols. Fix up protocol refs.
2482 extern objc_class OBJC_CLASS_$_Protocol;
2483 Class cls = (Class)&OBJC_CLASS_$_Protocol;
2485 NXMapTable *protocol_map = protocols();
2486 bool isPreoptimized = hi->isPreoptimized();
2487 bool isBundle = hi->isBundle();
2489 protocol_t **protolist = _getObjc2ProtocolList(hi, &count);
2490 for (i = 0; i < count; i++) {
2491 readProtocol(protolist[i], cls, protocol_map,
2492 isPreoptimized, isBundle);
2496 ts.log("IMAGE TIMES: discover protocols");
2498 // Fix up @protocol references
2499 // Preoptimized images may have the right
2500 // answer already but we don't know for sure.
2502 protocol_t **protolist = _getObjc2ProtocolRefs(hi, &count);
2503 for (i = 0; i < count; i++) {
2504 remapProtocolRef(&protolist[i]);
2508 ts.log("IMAGE TIMES: fix up @protocol references");
2510 // Realize non-lazy classes (for +load methods and static instances)
2512 classref_t *classlist =
2513 _getObjc2NonlazyClassList(hi, &count);
2514 for (i = 0; i < count; i++) {
2515 Class cls = remapClass(classlist[i]);
2518 // hack for class __ARCLite__, which didn't get this above
2519 #if TARGET_OS_SIMULATOR
2520 if (cls->cache._buckets == (void*)&_objc_empty_cache &&
2521 (cls->cache._mask || cls->cache._occupied))
2523 cls->cache._mask = 0;
2524 cls->cache._occupied = 0;
2526 if (cls->ISA()->cache._buckets == (void*)&_objc_empty_cache &&
2527 (cls->ISA()->cache._mask || cls->ISA()->cache._occupied))
2529 cls->ISA()->cache._mask = 0;
2530 cls->ISA()->cache._occupied = 0;
2538 ts.log("IMAGE TIMES: realize non-lazy classes");
2540 // Realize newly-resolved future classes, in case CF manipulates them
2541 if (resolvedFutureClasses) {
2542 for (i = 0; i < resolvedFutureClassCount; i++) {
2543 realizeClass(resolvedFutureClasses[i]);
2544 resolvedFutureClasses[i]->setInstancesRequireRawIsa(false/*inherited*/);
2546 free(resolvedFutureClasses);
2549 ts.log("IMAGE TIMES: realize future classes");
2551 // Discover categories.
2553 category_t **catlist =
2554 _getObjc2CategoryList(hi, &count);
2555 bool hasClassProperties = hi->info()->hasCategoryClassProperties();
2557 for (i = 0; i < count; i++) {
2558 category_t *cat = catlist[i];
2559 Class cls = remapClass(cat->cls);
2562 // Category's target class is missing (probably weak-linked).
2563 // Disavow any knowledge of this category.
2565 if (PrintConnecting) {
2566 _objc_inform("CLASS: IGNORING category \?\?\?(%s) %p with "
2567 "missing weak-linked target class",
2573 // Process this category.
2574 // First, register the category with its target class.
2575 // Then, rebuild the class's method lists (etc) if
2576 // the class is realized.
2577 bool classExists = NO;
2578 if (cat->instanceMethods || cat->protocols
2579 || cat->instanceProperties)
2581 addUnattachedCategoryForClass(cat, cls, hi);
2582 if (cls->isRealized()) {
2583 remethodizeClass(cls);
2586 if (PrintConnecting) {
2587 _objc_inform("CLASS: found category -%s(%s) %s",
2588 cls->nameForLogging(), cat->name,
2589 classExists ? "on existing class" : "");
2593 if (cat->classMethods || cat->protocols
2594 || (hasClassProperties && cat->_classProperties))
2596 addUnattachedCategoryForClass(cat, cls->ISA(), hi);
2597 if (cls->ISA()->isRealized()) {
2598 remethodizeClass(cls->ISA());
2600 if (PrintConnecting) {
2601 _objc_inform("CLASS: found category +%s(%s)",
2602 cls->nameForLogging(), cat->name);
2608 ts.log("IMAGE TIMES: discover categories");
2610 // Category discovery MUST BE LAST to avoid potential races
2611 // when other threads call the new category code before
2612 // this thread finishes its fixups.
2614 // +load handled by prepare_load_methods()
2616 if (DebugNonFragileIvars) {
2617 realizeAllClasses();
2621 // Print preoptimization statistics
2623 static unsigned int PreoptTotalMethodLists;
2624 static unsigned int PreoptOptimizedMethodLists;
2625 static unsigned int PreoptTotalClasses;
2626 static unsigned int PreoptOptimizedClasses;
2629 if (hi->isPreoptimized()) {
2630 _objc_inform("PREOPTIMIZATION: honoring preoptimized selectors "
2631 "in %s", hi->fname());
2633 else if (hi->info()->optimizedByDyld()) {
2634 _objc_inform("PREOPTIMIZATION: IGNORING preoptimized selectors "
2635 "in %s", hi->fname());
2638 classref_t *classlist = _getObjc2ClassList(hi, &count);
2639 for (i = 0; i < count; i++) {
2640 Class cls = remapClass(classlist[i]);
2643 PreoptTotalClasses++;
2644 if (hi->isPreoptimized()) {
2645 PreoptOptimizedClasses++;
2648 const method_list_t *mlist;
2649 if ((mlist = ((class_ro_t *)cls->data())->baseMethods())) {
2650 PreoptTotalMethodLists++;
2651 if (mlist->isFixedUp()) {
2652 PreoptOptimizedMethodLists++;
2655 if ((mlist=((class_ro_t *)cls->ISA()->data())->baseMethods())) {
2656 PreoptTotalMethodLists++;
2657 if (mlist->isFixedUp()) {
2658 PreoptOptimizedMethodLists++;
2664 _objc_inform("PREOPTIMIZATION: %zu selector references not "
2665 "pre-optimized", UnfixedSelectors);
2666 _objc_inform("PREOPTIMIZATION: %u/%u (%.3g%%) method lists pre-sorted",
2667 PreoptOptimizedMethodLists, PreoptTotalMethodLists,
2668 PreoptTotalMethodLists
2669 ? 100.0*PreoptOptimizedMethodLists/PreoptTotalMethodLists
2671 _objc_inform("PREOPTIMIZATION: %u/%u (%.3g%%) classes pre-registered",
2672 PreoptOptimizedClasses, PreoptTotalClasses,
2674 ? 100.0*PreoptOptimizedClasses/PreoptTotalClasses
2676 _objc_inform("PREOPTIMIZATION: %zu protocol references not "
2677 "pre-optimized", UnfixedProtocolReferences);
2684 /***********************************************************************
2685 * prepare_load_methods
2686 * Schedule +load for classes in this image, any un-+load-ed
2687 * superclasses in other images, and any categories in this image.
2688 **********************************************************************/
2689 // Recursively schedule +load for cls and any un-+load-ed superclasses.
2690 // cls must already be connected.
2691 static void schedule_class_load(Class cls)
2694 assert(cls->isRealized()); // _read_images should realize
2696 if (cls->data()->flags & RW_LOADED) return;
2698 // Ensure superclass-first ordering
2699 schedule_class_load(cls->superclass);
2701 add_class_to_loadable_list(cls);
2702 cls->setInfo(RW_LOADED);
2705 // Quick scan for +load methods that doesn't take a lock.
2706 bool hasLoadMethods(const headerType *mhdr)
2709 if (_getObjc2NonlazyClassList(mhdr, &count) && count > 0) return true;
2710 if (_getObjc2NonlazyCategoryList(mhdr, &count) && count > 0) return true;
2714 void prepare_load_methods(const headerType *mhdr)
2718 runtimeLock.assertWriting();
2720 classref_t *classlist =
2721 _getObjc2NonlazyClassList(mhdr, &count);
2722 for (i = 0; i < count; i++) {
2723 schedule_class_load(remapClass(classlist[i]));
2726 category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);
2727 for (i = 0; i < count; i++) {
2728 category_t *cat = categorylist[i];
2729 Class cls = remapClass(cat->cls);
2730 if (!cls) continue; // category for ignored weak-linked class
2732 assert(cls->ISA()->isRealized());
2733 add_category_to_loadable_list(cat);
2738 /***********************************************************************
2740 * Only handles MH_BUNDLE for now.
2741 * Locking: write-lock and loadMethodLock acquired by unmap_image
2742 **********************************************************************/
2743 void _unload_image(header_info *hi)
2747 loadMethodLock.assertLocked();
2748 runtimeLock.assertWriting();
2750 // Unload unattached categories and categories waiting for +load.
2752 category_t **catlist = _getObjc2CategoryList(hi, &count);
2753 for (i = 0; i < count; i++) {
2754 category_t *cat = catlist[i];
2755 if (!cat) continue; // category for ignored weak-linked class
2756 Class cls = remapClass(cat->cls);
2757 assert(cls); // shouldn't have live category for dead class
2759 // fixme for MH_DYLIB cat's class may have been unloaded already
2762 removeUnattachedCategoryForClass(cat, cls);
2765 remove_category_from_loadable_list(cat);
2770 // Gather classes from both __DATA,__objc_clslist
2771 // and __DATA,__objc_nlclslist. arclite's hack puts a class in the latter
2772 // only, and we need to unload that class if we unload an arclite image.
2774 NXHashTable *classes = NXCreateHashTable(NXPtrPrototype, 0, nil);
2775 classref_t *classlist;
2777 classlist = _getObjc2ClassList(hi, &count);
2778 for (i = 0; i < count; i++) {
2779 Class cls = remapClass(classlist[i]);
2780 if (cls) NXHashInsert(classes, cls);
2783 classlist = _getObjc2NonlazyClassList(hi, &count);
2784 for (i = 0; i < count; i++) {
2785 Class cls = remapClass(classlist[i]);
2786 if (cls) NXHashInsert(classes, cls);
2789 // First detach classes from each other. Then free each class.
2790 // This avoid bugs where this loop unloads a subclass before its superclass
2795 hs = NXInitHashState(classes);
2796 while (NXNextHashState(classes, &hs, (void**)&cls)) {
2797 remove_class_from_loadable_list(cls);
2798 detach_class(cls->ISA(), YES);
2799 detach_class(cls, NO);
2801 hs = NXInitHashState(classes);
2802 while (NXNextHashState(classes, &hs, (void**)&cls)) {
2803 free_class(cls->ISA());
2807 NXFreeHashTable(classes);
2809 // XXX FIXME -- Clean up protocols:
2810 // <rdar://problem/9033191> Support unloading protocols at dylib/image unload time
2812 // fixme DebugUnload
2816 /***********************************************************************
2817 * method_getDescription
2818 * Returns a pointer to this method's objc_method_description.
2820 **********************************************************************/
2821 struct objc_method_description *
2822 method_getDescription(Method m)
2825 return (struct objc_method_description *)m;
2830 method_getImplementation(Method m)
2832 return m ? m->imp : nil;
2836 /***********************************************************************
2838 * Returns this method's selector.
2839 * The method must not be nil.
2840 * The method must already have been fixed-up.
2842 **********************************************************************/
2844 method_getName(Method m)
2848 assert(m->name == sel_registerName(sel_getName(m->name)));
2853 /***********************************************************************
2854 * method_getTypeEncoding
2855 * Returns this method's old-style type encoding string.
2856 * The method must not be nil.
2858 **********************************************************************/
2860 method_getTypeEncoding(Method m)
2867 /***********************************************************************
2868 * method_setImplementation
2869 * Sets this method's implementation to imp.
2870 * The previous implementation is returned.
2871 **********************************************************************/
2873 _method_setImplementation(Class cls, method_t *m, IMP imp)
2875 runtimeLock.assertWriting();
2878 if (!imp) return nil;
2883 // Cache updates are slow if cls is nil (i.e. unknown)
2884 // RR/AWZ updates are slow if cls is nil (i.e. unknown)
2885 // fixme build list of classes whose Methods are known externally?
2889 updateCustomRR_AWZ(cls, m);
2895 method_setImplementation(Method m, IMP imp)
2897 // Don't know the class - will be slow if RR/AWZ are affected
2898 // fixme build list of classes whose Methods are known externally?
2899 rwlock_writer_t lock(runtimeLock);
2900 return _method_setImplementation(Nil, m, imp);
2904 void method_exchangeImplementations(Method m1, Method m2)
2906 if (!m1 || !m2) return;
2908 rwlock_writer_t lock(runtimeLock);
2910 IMP m1_imp = m1->imp;
2915 // RR/AWZ updates are slow because class is unknown
2916 // Cache updates are slow because class is unknown
2917 // fixme build list of classes whose Methods are known externally?
2921 updateCustomRR_AWZ(nil, m1);
2922 updateCustomRR_AWZ(nil, m2);
2926 /***********************************************************************
2930 **********************************************************************/
2932 ivar_getOffset(Ivar ivar)
2934 if (!ivar) return 0;
2935 return *ivar->offset;
2939 /***********************************************************************
2943 **********************************************************************/
2945 ivar_getName(Ivar ivar)
2947 if (!ivar) return nil;
2952 /***********************************************************************
2953 * ivar_getTypeEncoding
2956 **********************************************************************/
2958 ivar_getTypeEncoding(Ivar ivar)
2960 if (!ivar) return nil;
2966 const char *property_getName(objc_property_t prop)
2971 const char *property_getAttributes(objc_property_t prop)
2973 return prop->attributes;
2976 objc_property_attribute_t *property_copyAttributeList(objc_property_t prop,
2977 unsigned int *outCount)
2980 if (outCount) *outCount = 0;
2984 rwlock_reader_t lock(runtimeLock);
2985 return copyPropertyAttributeList(prop->attributes,outCount);
2988 char * property_copyAttributeValue(objc_property_t prop, const char *name)
2990 if (!prop || !name || *name == '\0') return nil;
2992 rwlock_reader_t lock(runtimeLock);
2993 return copyPropertyAttributeValue(prop->attributes, name);
2997 /***********************************************************************
2998 * getExtendedTypesIndexesForMethod
3000 * a is the count of methods in all method lists before m's method list
3001 * b is the index of m in m's method list
3002 * a+b is the index of m's extended types in the extended types array
3003 **********************************************************************/
3004 static void getExtendedTypesIndexesForMethod(protocol_t *proto, const method_t *m, bool isRequiredMethod, bool isInstanceMethod, uint32_t& a, uint32_t &b)
3008 if (proto->instanceMethods) {
3009 if (isRequiredMethod && isInstanceMethod) {
3010 b = proto->instanceMethods->indexOfMethod(m);
3013 a += proto->instanceMethods->count;
3016 if (proto->classMethods) {
3017 if (isRequiredMethod && !isInstanceMethod) {
3018 b = proto->classMethods->indexOfMethod(m);
3021 a += proto->classMethods->count;
3024 if (proto->optionalInstanceMethods) {
3025 if (!isRequiredMethod && isInstanceMethod) {
3026 b = proto->optionalInstanceMethods->indexOfMethod(m);
3029 a += proto->optionalInstanceMethods->count;
3032 if (proto->optionalClassMethods) {
3033 if (!isRequiredMethod && !isInstanceMethod) {
3034 b = proto->optionalClassMethods->indexOfMethod(m);
3037 a += proto->optionalClassMethods->count;
3042 /***********************************************************************
3043 * getExtendedTypesIndexForMethod
3044 * Returns the index of m's extended types in proto's extended types array.
3045 **********************************************************************/
3046 static uint32_t getExtendedTypesIndexForMethod(protocol_t *proto, const method_t *m, bool isRequiredMethod, bool isInstanceMethod)
3050 getExtendedTypesIndexesForMethod(proto, m, isRequiredMethod,
3051 isInstanceMethod, a, b);
3056 /***********************************************************************
3057 * fixupProtocolMethodList
3058 * Fixes up a single method list in a protocol.
3059 **********************************************************************/
3061 fixupProtocolMethodList(protocol_t *proto, method_list_t *mlist,
3062 bool required, bool instance)
3064 runtimeLock.assertWriting();
3067 if (mlist->isFixedUp()) return;
3069 const char **extTypes = proto->extendedMethodTypes();
3070 fixupMethodList(mlist, true/*always copy for simplicity*/,
3071 !extTypes/*sort if no extended method types*/);
3074 // Sort method list and extended method types together.
3075 // fixupMethodList() can't do this.
3077 uint32_t count = mlist->count;
3080 getExtendedTypesIndexesForMethod(proto, &mlist->get(0),
3081 required, instance, prefix, junk);
3082 for (uint32_t i = 0; i < count; i++) {
3083 for (uint32_t j = i+1; j < count; j++) {
3084 method_t& mi = mlist->get(i);
3085 method_t& mj = mlist->get(j);
3086 if (mi.name > mj.name) {
3088 std::swap(extTypes[prefix+i], extTypes[prefix+j]);
3096 /***********************************************************************
3098 * Fixes up all of a protocol's method lists.
3099 **********************************************************************/
3101 fixupProtocol(protocol_t *proto)
3103 runtimeLock.assertWriting();
3105 if (proto->protocols) {
3106 for (uintptr_t i = 0; i < proto->protocols->count; i++) {
3107 protocol_t *sub = remapProtocol(proto->protocols->list[i]);
3108 if (!sub->isFixedUp()) fixupProtocol(sub);
3112 fixupProtocolMethodList(proto, proto->instanceMethods, YES, YES);
3113 fixupProtocolMethodList(proto, proto->classMethods, YES, NO);
3114 fixupProtocolMethodList(proto, proto->optionalInstanceMethods, NO, YES);
3115 fixupProtocolMethodList(proto, proto->optionalClassMethods, NO, NO);
3117 // fixme memory barrier so we can check this with no lock
3118 proto->setFixedUp();
3122 /***********************************************************************
3123 * fixupProtocolIfNeeded
3124 * Fixes up all of a protocol's method lists if they aren't fixed up already.
3125 * Locking: write-locks runtimeLock.
3126 **********************************************************************/
3128 fixupProtocolIfNeeded(protocol_t *proto)
3130 runtimeLock.assertUnlocked();
3133 if (!proto->isFixedUp()) {
3134 rwlock_writer_t lock(runtimeLock);
3135 fixupProtocol(proto);
3140 static method_list_t *
3141 getProtocolMethodList(protocol_t *proto, bool required, bool instance)
3143 method_list_t **mlistp = nil;
3146 mlistp = &proto->instanceMethods;
3148 mlistp = &proto->classMethods;
3152 mlistp = &proto->optionalInstanceMethods;
3154 mlistp = &proto->optionalClassMethods;
3162 /***********************************************************************
3163 * protocol_getMethod_nolock
3164 * Locking: runtimeLock must be held by the caller
3165 **********************************************************************/
3167 protocol_getMethod_nolock(protocol_t *proto, SEL sel,
3168 bool isRequiredMethod, bool isInstanceMethod,
3171 runtimeLock.assertLocked();
3173 if (!proto || !sel) return nil;
3175 assert(proto->isFixedUp());
3177 method_list_t *mlist =
3178 getProtocolMethodList(proto, isRequiredMethod, isInstanceMethod);
3180 method_t *m = search_method_list(mlist, sel);
3184 if (recursive && proto->protocols) {
3186 for (uint32_t i = 0; i < proto->protocols->count; i++) {
3187 protocol_t *realProto = remapProtocol(proto->protocols->list[i]);
3188 m = protocol_getMethod_nolock(realProto, sel,
3189 isRequiredMethod, isInstanceMethod,
3199 /***********************************************************************
3200 * protocol_getMethod
3202 * Locking: acquires runtimeLock
3203 **********************************************************************/
3205 protocol_getMethod(protocol_t *proto, SEL sel, bool isRequiredMethod, bool isInstanceMethod, bool recursive)
3207 if (!proto) return nil;
3208 fixupProtocolIfNeeded(proto);
3210 rwlock_reader_t lock(runtimeLock);
3211 return protocol_getMethod_nolock(proto, sel, isRequiredMethod,
3212 isInstanceMethod, recursive);
3216 /***********************************************************************
3217 * protocol_getMethodTypeEncoding_nolock
3218 * Return the @encode string for the requested protocol method.
3219 * Returns nil if the compiler did not emit any extended @encode data.
3220 * Locking: runtimeLock must be held for writing by the caller
3221 **********************************************************************/
3223 protocol_getMethodTypeEncoding_nolock(protocol_t *proto, SEL sel,
3224 bool isRequiredMethod,
3225 bool isInstanceMethod)
3227 runtimeLock.assertLocked();
3229 if (!proto) return nil;
3230 if (!proto->extendedMethodTypes()) return nil;
3232 assert(proto->isFixedUp());
3235 protocol_getMethod_nolock(proto, sel,
3236 isRequiredMethod, isInstanceMethod, false);
3238 uint32_t i = getExtendedTypesIndexForMethod(proto, m,
3241 return proto->extendedMethodTypes()[i];
3244 // No method with that name. Search incorporated protocols.
3245 if (proto->protocols) {
3246 for (uintptr_t i = 0; i < proto->protocols->count; i++) {
3248 protocol_getMethodTypeEncoding_nolock(remapProtocol(proto->protocols->list[i]), sel, isRequiredMethod, isInstanceMethod);
3249 if (enc) return enc;
3256 /***********************************************************************
3257 * _protocol_getMethodTypeEncoding
3258 * Return the @encode string for the requested protocol method.
3259 * Returns nil if the compiler did not emit any extended @encode data.
3260 * Locking: acquires runtimeLock
3261 **********************************************************************/
3263 _protocol_getMethodTypeEncoding(Protocol *proto_gen, SEL sel,
3264 BOOL isRequiredMethod, BOOL isInstanceMethod)
3266 protocol_t *proto = newprotocol(proto_gen);
3268 if (!proto) return nil;
3269 fixupProtocolIfNeeded(proto);
3271 rwlock_reader_t lock(runtimeLock);
3272 return protocol_getMethodTypeEncoding_nolock(proto, sel,
3278 /***********************************************************************
3279 * protocol_t::demangledName
3280 * Returns the (Swift-demangled) name of the given protocol.
3282 **********************************************************************/
3284 protocol_t::demangledName()
3286 assert(hasDemangledNameField());
3288 if (! _demangledName) {
3289 char *de = copySwiftV1DemangledName(mangledName, true/*isProtocol*/);
3290 if (! OSAtomicCompareAndSwapPtrBarrier(nil, (void*)(de ?: mangledName),
3291 (void**)&_demangledName))
3296 return _demangledName;
3299 /***********************************************************************
3301 * Returns the (Swift-demangled) name of the given protocol.
3302 * Locking: runtimeLock must not be held by the caller
3303 **********************************************************************/
3305 protocol_getName(Protocol *proto)
3307 if (!proto) return "nil";
3308 else return newprotocol(proto)->demangledName();
3312 /***********************************************************************
3313 * protocol_getInstanceMethodDescription
3314 * Returns the description of a named instance method.
3315 * Locking: runtimeLock must not be held by the caller
3316 **********************************************************************/
3317 struct objc_method_description
3318 protocol_getMethodDescription(Protocol *p, SEL aSel,
3319 BOOL isRequiredMethod, BOOL isInstanceMethod)
3322 protocol_getMethod(newprotocol(p), aSel,
3323 isRequiredMethod, isInstanceMethod, true);
3324 if (m) return *method_getDescription(m);
3325 else return (struct objc_method_description){nil, nil};
3329 /***********************************************************************
3330 * protocol_conformsToProtocol_nolock
3331 * Returns YES if self conforms to other.
3332 * Locking: runtimeLock must be held by the caller.
3333 **********************************************************************/
3335 protocol_conformsToProtocol_nolock(protocol_t *self, protocol_t *other)
3337 runtimeLock.assertLocked();
3339 if (!self || !other) {
3343 // protocols need not be fixed up
3345 if (0 == strcmp(self->mangledName, other->mangledName)) {
3349 if (self->protocols) {
3351 for (i = 0; i < self->protocols->count; i++) {
3352 protocol_t *proto = remapProtocol(self->protocols->list[i]);
3353 if (0 == strcmp(other->mangledName, proto->mangledName)) {
3356 if (protocol_conformsToProtocol_nolock(proto, other)) {
3366 /***********************************************************************
3367 * protocol_conformsToProtocol
3368 * Returns YES if self conforms to other.
3369 * Locking: acquires runtimeLock
3370 **********************************************************************/
3371 BOOL protocol_conformsToProtocol(Protocol *self, Protocol *other)
3373 rwlock_reader_t lock(runtimeLock);
3374 return protocol_conformsToProtocol_nolock(newprotocol(self),
3375 newprotocol(other));
3379 /***********************************************************************
3381 * Return YES if two protocols are equal (i.e. conform to each other)
3382 * Locking: acquires runtimeLock
3383 **********************************************************************/
3384 BOOL protocol_isEqual(Protocol *self, Protocol *other)
3386 if (self == other) return YES;
3387 if (!self || !other) return NO;
3389 if (!protocol_conformsToProtocol(self, other)) return NO;
3390 if (!protocol_conformsToProtocol(other, self)) return NO;
3396 /***********************************************************************
3397 * protocol_copyMethodDescriptionList
3398 * Returns descriptions of a protocol's methods.
3399 * Locking: acquires runtimeLock
3400 **********************************************************************/
3401 struct objc_method_description *
3402 protocol_copyMethodDescriptionList(Protocol *p,
3403 BOOL isRequiredMethod,BOOL isInstanceMethod,
3404 unsigned int *outCount)
3406 protocol_t *proto = newprotocol(p);
3407 struct objc_method_description *result = nil;
3408 unsigned int count = 0;
3411 if (outCount) *outCount = 0;
3415 fixupProtocolIfNeeded(proto);
3417 rwlock_reader_t lock(runtimeLock);
3419 method_list_t *mlist =
3420 getProtocolMethodList(proto, isRequiredMethod, isInstanceMethod);
3423 result = (struct objc_method_description *)
3424 calloc(mlist->count + 1, sizeof(struct objc_method_description));
3425 for (const auto& meth : *mlist) {
3426 result[count].name = meth.name;
3427 result[count].types = (char *)meth.types;
3432 if (outCount) *outCount = count;
3437 /***********************************************************************
3438 * protocol_getProperty
3440 * Locking: runtimeLock must be held by the caller
3441 **********************************************************************/
3443 protocol_getProperty_nolock(protocol_t *proto, const char *name,
3444 bool isRequiredProperty, bool isInstanceProperty)
3446 runtimeLock.assertLocked();
3448 if (!isRequiredProperty) {
3449 // Only required properties are currently supported.
3453 property_list_t *plist = isInstanceProperty ?
3454 proto->instanceProperties : proto->classProperties();
3456 for (auto& prop : *plist) {
3457 if (0 == strcmp(name, prop.name)) {
3463 if (proto->protocols) {
3465 for (i = 0; i < proto->protocols->count; i++) {
3466 protocol_t *p = remapProtocol(proto->protocols->list[i]);
3468 protocol_getProperty_nolock(p, name,
3470 isInstanceProperty);
3471 if (prop) return prop;
3478 objc_property_t protocol_getProperty(Protocol *p, const char *name,
3479 BOOL isRequiredProperty, BOOL isInstanceProperty)
3481 if (!p || !name) return nil;
3483 rwlock_reader_t lock(runtimeLock);
3484 return (objc_property_t)
3485 protocol_getProperty_nolock(newprotocol(p), name,
3486 isRequiredProperty, isInstanceProperty);
3490 /***********************************************************************
3491 * protocol_copyPropertyList
3492 * protocol_copyPropertyList2
3494 * Locking: acquires runtimeLock
3495 **********************************************************************/
3496 static property_t **
3497 copyPropertyList(property_list_t *plist, unsigned int *outCount)
3499 property_t **result = nil;
3500 unsigned int count = 0;
3503 count = plist->count;
3507 result = (property_t **)malloc((count+1) * sizeof(property_t *));
3510 for (auto& prop : *plist) {
3511 result[count++] = ∝
3513 result[count] = nil;
3516 if (outCount) *outCount = count;
3521 protocol_copyPropertyList2(Protocol *proto, unsigned int *outCount,
3522 BOOL isRequiredProperty, BOOL isInstanceProperty)
3524 if (!proto || !isRequiredProperty) {
3525 // Optional properties are not currently supported.
3526 if (outCount) *outCount = 0;
3530 rwlock_reader_t lock(runtimeLock);
3532 property_list_t *plist = isInstanceProperty
3533 ? newprotocol(proto)->instanceProperties
3534 : newprotocol(proto)->classProperties();
3535 return (objc_property_t *)copyPropertyList(plist, outCount);
3539 protocol_copyPropertyList(Protocol *proto, unsigned int *outCount)
3541 return protocol_copyPropertyList2(proto, outCount,
3542 YES/*required*/, YES/*instance*/);
3546 /***********************************************************************
3547 * protocol_copyProtocolList
3548 * Copies this protocol's incorporated protocols.
3549 * Does not copy those protocol's incorporated protocols in turn.
3550 * Locking: acquires runtimeLock
3551 **********************************************************************/
3552 Protocol * __unsafe_unretained *
3553 protocol_copyProtocolList(Protocol *p, unsigned int *outCount)
3555 unsigned int count = 0;
3556 Protocol **result = nil;
3557 protocol_t *proto = newprotocol(p);
3560 if (outCount) *outCount = 0;
3564 rwlock_reader_t lock(runtimeLock);
3566 if (proto->protocols) {
3567 count = (unsigned int)proto->protocols->count;
3570 result = (Protocol **)malloc((count+1) * sizeof(Protocol *));
3573 for (i = 0; i < count; i++) {
3574 result[i] = (Protocol *)remapProtocol(proto->protocols->list[i]);
3579 if (outCount) *outCount = count;
3584 /***********************************************************************
3585 * objc_allocateProtocol
3586 * Creates a new protocol. The protocol may not be used until
3587 * objc_registerProtocol() is called.
3588 * Returns nil if a protocol with the same name already exists.
3589 * Locking: acquires runtimeLock
3590 **********************************************************************/
3592 objc_allocateProtocol(const char *name)
3594 rwlock_writer_t lock(runtimeLock);
3596 if (getProtocol(name)) {
3600 protocol_t *result = (protocol_t *)calloc(sizeof(protocol_t), 1);
3602 extern objc_class OBJC_CLASS_$___IncompleteProtocol;
3603 Class cls = (Class)&OBJC_CLASS_$___IncompleteProtocol;
3604 result->initProtocolIsa(cls);
3605 result->size = sizeof(protocol_t);
3606 // fixme mangle the name if it looks swift-y?
3607 result->mangledName = strdupIfMutable(name);
3609 // fixme reserve name without installing
3611 return (Protocol *)result;
3615 /***********************************************************************
3616 * objc_registerProtocol
3617 * Registers a newly-constructed protocol. The protocol is now
3618 * ready for use and immutable.
3619 * Locking: acquires runtimeLock
3620 **********************************************************************/
3621 void objc_registerProtocol(Protocol *proto_gen)
3623 protocol_t *proto = newprotocol(proto_gen);
3625 rwlock_writer_t lock(runtimeLock);
3627 extern objc_class OBJC_CLASS_$___IncompleteProtocol;
3628 Class oldcls = (Class)&OBJC_CLASS_$___IncompleteProtocol;
3629 extern objc_class OBJC_CLASS_$_Protocol;
3630 Class cls = (Class)&OBJC_CLASS_$_Protocol;
3632 if (proto->ISA() == cls) {
3633 _objc_inform("objc_registerProtocol: protocol '%s' was already "
3634 "registered!", proto->nameForLogging());
3637 if (proto->ISA() != oldcls) {
3638 _objc_inform("objc_registerProtocol: protocol '%s' was not allocated "
3639 "with objc_allocateProtocol!", proto->nameForLogging());
3643 // NOT initProtocolIsa(). The protocol object may already
3644 // have been retained and we must preserve that count.
3645 proto->changeIsa(cls);
3647 NXMapKeyCopyingInsert(protocols(), proto->mangledName, proto);
3651 /***********************************************************************
3652 * protocol_addProtocol
3653 * Adds an incorporated protocol to another protocol.
3654 * No method enforcement is performed.
3655 * `proto` must be under construction. `addition` must not.
3656 * Locking: acquires runtimeLock
3657 **********************************************************************/
3659 protocol_addProtocol(Protocol *proto_gen, Protocol *addition_gen)
3661 protocol_t *proto = newprotocol(proto_gen);
3662 protocol_t *addition = newprotocol(addition_gen);
3664 extern objc_class OBJC_CLASS_$___IncompleteProtocol;
3665 Class cls = (Class)&OBJC_CLASS_$___IncompleteProtocol;
3667 if (!proto_gen) return;
3668 if (!addition_gen) return;
3670 rwlock_writer_t lock(runtimeLock);
3672 if (proto->ISA() != cls) {
3673 _objc_inform("protocol_addProtocol: modified protocol '%s' is not "
3674 "under construction!", proto->nameForLogging());
3677 if (addition->ISA() == cls) {
3678 _objc_inform("protocol_addProtocol: added protocol '%s' is still "
3679 "under construction!", addition->nameForLogging());
3683 protocol_list_t *protolist = proto->protocols;
3685 protolist = (protocol_list_t *)
3686 calloc(1, sizeof(protocol_list_t)
3687 + sizeof(protolist->list[0]));
3689 protolist = (protocol_list_t *)
3690 realloc(protolist, protocol_list_size(protolist)
3691 + sizeof(protolist->list[0]));
3694 protolist->list[protolist->count++] = (protocol_ref_t)addition;
3695 proto->protocols = protolist;
3699 /***********************************************************************
3700 * protocol_addMethodDescription
3701 * Adds a method to a protocol. The protocol must be under construction.
3702 * Locking: acquires runtimeLock
3703 **********************************************************************/
3705 protocol_addMethod_nolock(method_list_t*& list, SEL name, const char *types)
3708 list = (method_list_t *)calloc(sizeof(method_list_t), 1);
3709 list->entsizeAndFlags = sizeof(list->first);
3712 size_t size = list->byteSize() + list->entsize();
3713 list = (method_list_t *)realloc(list, size);
3716 method_t& meth = list->get(list->count++);
3718 meth.types = types ? strdupIfMutable(types) : "";
3723 protocol_addMethodDescription(Protocol *proto_gen, SEL name, const char *types,
3724 BOOL isRequiredMethod, BOOL isInstanceMethod)
3726 protocol_t *proto = newprotocol(proto_gen);
3728 extern objc_class OBJC_CLASS_$___IncompleteProtocol;
3729 Class cls = (Class)&OBJC_CLASS_$___IncompleteProtocol;
3731 if (!proto_gen) return;
3733 rwlock_writer_t lock(runtimeLock);
3735 if (proto->ISA() != cls) {
3736 _objc_inform("protocol_addMethodDescription: protocol '%s' is not "
3737 "under construction!", proto->nameForLogging());
3741 if (isRequiredMethod && isInstanceMethod) {
3742 protocol_addMethod_nolock(proto->instanceMethods, name, types);
3743 } else if (isRequiredMethod && !isInstanceMethod) {
3744 protocol_addMethod_nolock(proto->classMethods, name, types);
3745 } else if (!isRequiredMethod && isInstanceMethod) {
3746 protocol_addMethod_nolock(proto->optionalInstanceMethods, name,types);
3747 } else /* !isRequiredMethod && !isInstanceMethod) */ {
3748 protocol_addMethod_nolock(proto->optionalClassMethods, name, types);
3753 /***********************************************************************
3754 * protocol_addProperty
3755 * Adds a property to a protocol. The protocol must be under construction.
3756 * Locking: acquires runtimeLock
3757 **********************************************************************/
3759 protocol_addProperty_nolock(property_list_t *&plist, const char *name,
3760 const objc_property_attribute_t *attrs,
3764 plist = (property_list_t *)calloc(sizeof(property_list_t), 1);
3765 plist->entsizeAndFlags = sizeof(property_t);
3767 plist = (property_list_t *)
3768 realloc(plist, sizeof(property_list_t)
3769 + plist->count * plist->entsize());
3772 property_t& prop = plist->get(plist->count++);
3773 prop.name = strdupIfMutable(name);
3774 prop.attributes = copyPropertyAttributeString(attrs, count);
3778 protocol_addProperty(Protocol *proto_gen, const char *name,
3779 const objc_property_attribute_t *attrs,
3781 BOOL isRequiredProperty, BOOL isInstanceProperty)
3783 protocol_t *proto = newprotocol(proto_gen);
3785 extern objc_class OBJC_CLASS_$___IncompleteProtocol;
3786 Class cls = (Class)&OBJC_CLASS_$___IncompleteProtocol;
3791 rwlock_writer_t lock(runtimeLock);
3793 if (proto->ISA() != cls) {
3794 _objc_inform("protocol_addProperty: protocol '%s' is not "
3795 "under construction!", proto->nameForLogging());
3799 if (isRequiredProperty && isInstanceProperty) {
3800 protocol_addProperty_nolock(proto->instanceProperties, name, attrs, count);
3802 else if (isRequiredProperty && !isInstanceProperty) {
3803 protocol_addProperty_nolock(proto->_classProperties, name, attrs, count);
3805 //else if (!isRequiredProperty && isInstanceProperty) {
3806 // protocol_addProperty_nolock(proto->optionalInstanceProperties, name, attrs, count);
3808 //else /* !isRequiredProperty && !isInstanceProperty) */ {
3809 // protocol_addProperty_nolock(proto->optionalClassProperties, name, attrs, count);
3814 /***********************************************************************
3816 * Returns pointers to all classes.
3817 * This requires all classes be realized, which is regretfully non-lazy.
3818 * Locking: acquires runtimeLock
3819 **********************************************************************/
3821 objc_getClassList(Class *buffer, int bufferLen)
3823 rwlock_writer_t lock(runtimeLock);
3825 realizeAllClasses();
3827 __block int count = 0;
3828 foreach_realized_class_and_metaclass(^(Class cls) {
3829 if (!cls->isMetaClass()) count++;
3834 foreach_realized_class_and_metaclass(^(Class cls) {
3835 if (c < bufferLen && !cls->isMetaClass()) {
3845 /***********************************************************************
3846 * objc_copyClassList
3847 * Returns pointers to all classes.
3848 * This requires all classes be realized, which is regretfully non-lazy.
3850 * outCount may be nil. *outCount is the number of classes returned.
3851 * If the returned array is not nil, it is nil-terminated and must be
3852 * freed with free().
3853 * Locking: write-locks runtimeLock
3854 **********************************************************************/
3856 objc_copyClassList(unsigned int *outCount)
3858 rwlock_writer_t lock(runtimeLock);
3860 realizeAllClasses();
3862 Class *result = nil;
3864 __block unsigned int count = 0;
3865 foreach_realized_class_and_metaclass(^(Class cls) {
3866 if (!cls->isMetaClass()) count++;
3870 result = (Class *)malloc((1+count) * sizeof(Class));
3871 __block unsigned int c = 0;
3872 foreach_realized_class_and_metaclass(^(Class cls) {
3873 if (!cls->isMetaClass()) {
3880 if (outCount) *outCount = count;
3885 /***********************************************************************
3886 * objc_copyProtocolList
3887 * Returns pointers to all protocols.
3888 * Locking: read-locks runtimeLock
3889 **********************************************************************/
3890 Protocol * __unsafe_unretained *
3891 objc_copyProtocolList(unsigned int *outCount)
3893 rwlock_reader_t lock(runtimeLock);
3895 NXMapTable *protocol_map = protocols();
3897 unsigned int count = NXCountMapTable(protocol_map);
3899 if (outCount) *outCount = 0;
3903 Protocol **result = (Protocol **)malloc((count+1) * sizeof(Protocol*));
3908 NXMapState state = NXInitMapState(protocol_map);
3909 while (NXNextMapState(protocol_map, &state,
3910 (const void **)&name, (const void **)&proto))
3912 result[i++] = proto;
3916 assert(i == count+1);
3918 if (outCount) *outCount = count;
3923 /***********************************************************************
3925 * Get a protocol by name, or return nil
3926 * Locking: read-locks runtimeLock
3927 **********************************************************************/
3928 Protocol *objc_getProtocol(const char *name)
3930 rwlock_reader_t lock(runtimeLock);
3931 return getProtocol(name);
3935 /***********************************************************************
3936 * class_copyMethodList
3938 * Locking: read-locks runtimeLock
3939 **********************************************************************/
3941 class_copyMethodList(Class cls, unsigned int *outCount)
3943 unsigned int count = 0;
3944 Method *result = nil;
3947 if (outCount) *outCount = 0;
3951 rwlock_reader_t lock(runtimeLock);
3953 assert(cls->isRealized());
3955 count = cls->data()->methods.count();
3958 result = (Method *)malloc((count + 1) * sizeof(Method));
3961 for (auto& meth : cls->data()->methods) {
3962 result[count++] = &meth;
3964 result[count] = nil;
3967 if (outCount) *outCount = count;
3972 /***********************************************************************
3973 * class_copyIvarList
3975 * Locking: read-locks runtimeLock
3976 **********************************************************************/
3978 class_copyIvarList(Class cls, unsigned int *outCount)
3980 const ivar_list_t *ivars;
3982 unsigned int count = 0;
3985 if (outCount) *outCount = 0;
3989 rwlock_reader_t lock(runtimeLock);
3991 assert(cls->isRealized());
3993 if ((ivars = cls->data()->ro->ivars) && ivars->count) {
3994 result = (Ivar *)malloc((ivars->count+1) * sizeof(Ivar));
3996 for (auto& ivar : *ivars) {
3997 if (!ivar.offset) continue; // anonymous bitfield
3998 result[count++] = &ivar;
4000 result[count] = nil;
4003 if (outCount) *outCount = count;
4008 /***********************************************************************
4009 * class_copyPropertyList. Returns a heap block containing the
4010 * properties declared in the class, or nil if the class
4011 * declares no properties. Caller must free the block.
4012 * Does not copy any superclass's properties.
4013 * Locking: read-locks runtimeLock
4014 **********************************************************************/
4016 class_copyPropertyList(Class cls, unsigned int *outCount)
4019 if (outCount) *outCount = 0;
4023 rwlock_reader_t lock(runtimeLock);
4025 assert(cls->isRealized());
4026 auto rw = cls->data();
4028 property_t **result = nil;
4029 unsigned int count = rw->properties.count();
4031 result = (property_t **)malloc((count + 1) * sizeof(property_t *));
4034 for (auto& prop : rw->properties) {
4035 result[count++] = ∝
4037 result[count] = nil;
4040 if (outCount) *outCount = count;
4041 return (objc_property_t *)result;
4045 /***********************************************************************
4046 * objc_class::getLoadMethod
4048 * Called only from add_class_to_loadable_list.
4049 * Locking: runtimeLock must be read- or write-locked by the caller.
4050 **********************************************************************/
4052 objc_class::getLoadMethod()
4054 runtimeLock.assertLocked();
4056 const method_list_t *mlist;
4058 assert(isRealized());
4059 assert(ISA()->isRealized());
4060 assert(!isMetaClass());
4061 assert(ISA()->isMetaClass());
4063 mlist = ISA()->data()->ro->baseMethods();
4065 for (const auto& meth : *mlist) {
4066 const char *name = sel_cname(meth.name);
4067 if (0 == strcmp(name, "load")) {
4077 /***********************************************************************
4079 * Returns a category's name.
4081 **********************************************************************/
4083 _category_getName(Category cat)
4089 /***********************************************************************
4090 * _category_getClassName
4091 * Returns a category's class's name
4092 * Called only from add_category_to_loadable_list and
4093 * remove_category_from_loadable_list for logging purposes.
4094 * Locking: runtimeLock must be read- or write-locked by the caller
4095 **********************************************************************/
4097 _category_getClassName(Category cat)
4099 runtimeLock.assertLocked();
4100 return remapClass(cat->cls)->nameForLogging();
4104 /***********************************************************************
4105 * _category_getClass
4106 * Returns a category's class
4107 * Called only by call_category_loads.
4108 * Locking: read-locks runtimeLock
4109 **********************************************************************/
4111 _category_getClass(Category cat)
4113 rwlock_reader_t lock(runtimeLock);
4114 Class result = remapClass(cat->cls);
4115 assert(result->isRealized()); // ok for call_category_loads' usage
4120 /***********************************************************************
4121 * _category_getLoadMethod
4123 * Called only from add_category_to_loadable_list
4124 * Locking: runtimeLock must be read- or write-locked by the caller
4125 **********************************************************************/
4127 _category_getLoadMethod(Category cat)
4129 runtimeLock.assertLocked();
4131 const method_list_t *mlist;
4133 mlist = cat->classMethods;
4135 for (const auto& meth : *mlist) {
4136 const char *name = sel_cname(meth.name);
4137 if (0 == strcmp(name, "load")) {
4147 /***********************************************************************
4148 * category_t::propertiesForMeta
4149 * Return a category's instance or class properties.
4150 * hi is the image containing the category.
4151 **********************************************************************/
4153 category_t::propertiesForMeta(bool isMeta, struct header_info *hi)
4155 if (!isMeta) return instanceProperties;
4156 else if (hi->info()->hasCategoryClassProperties()) return _classProperties;
4161 /***********************************************************************
4162 * class_copyProtocolList
4164 * Locking: read-locks runtimeLock
4165 **********************************************************************/
4166 Protocol * __unsafe_unretained *
4167 class_copyProtocolList(Class cls, unsigned int *outCount)
4169 unsigned int count = 0;
4170 Protocol **result = nil;
4173 if (outCount) *outCount = 0;
4177 rwlock_reader_t lock(runtimeLock);
4179 assert(cls->isRealized());
4181 count = cls->data()->protocols.count();
4184 result = (Protocol **)malloc((count+1) * sizeof(Protocol *));
4187 for (const auto& proto : cls->data()->protocols) {
4188 result[count++] = (Protocol *)remapProtocol(proto);
4190 result[count] = nil;
4193 if (outCount) *outCount = count;
4198 /***********************************************************************
4199 * _objc_copyClassNamesForImage
4201 * Locking: write-locks runtimeLock
4202 **********************************************************************/
4204 _objc_copyClassNamesForImage(header_info *hi, unsigned int *outCount)
4206 size_t count, i, shift;
4207 classref_t *classlist;
4210 // Need to write-lock in case demangledName() needs to realize a class.
4211 rwlock_writer_t lock(runtimeLock);
4213 classlist = _getObjc2ClassList(hi, &count);
4214 names = (const char **)malloc((count+1) * sizeof(const char *));
4217 for (i = 0; i < count; i++) {
4218 Class cls = remapClass(classlist[i]);
4220 names[i-shift] = cls->demangledName(true/*realize*/);
4222 shift++; // ignored weak-linked class
4228 if (outCount) *outCount = (unsigned int)count;
4233 /***********************************************************************
4234 * saveTemporaryString
4235 * Save a string in a thread-local FIFO buffer.
4236 * This is suitable for temporary strings generated for logging purposes.
4237 **********************************************************************/
4239 saveTemporaryString(char *str)
4241 // Fixed-size FIFO. We free the first string, shift
4242 // the rest, and add the new string to the end.
4243 _objc_pthread_data *data = _objc_fetch_pthread_data(true);
4244 if (data->printableNames[0]) {
4245 free(data->printableNames[0]);
4247 int last = countof(data->printableNames) - 1;
4248 for (int i = 0; i < last; i++) {
4249 data->printableNames[i] = data->printableNames[i+1];
4251 data->printableNames[last] = str;
4255 /***********************************************************************
4256 * objc_class::nameForLogging
4257 * Returns the class's name, suitable for display.
4258 * The returned memory is TEMPORARY. Print it or copy it immediately.
4260 **********************************************************************/
4262 objc_class::nameForLogging()
4264 // Handle the easy case directly.
4265 if (isRealized() || isFuture()) {
4266 if (data()->demangledName) return data()->demangledName;
4271 const char *name = mangledName();
4272 char *de = copySwiftV1DemangledName(name);
4273 if (de) result = de;
4274 else result = strdup(name);
4276 saveTemporaryString(result);
4281 /***********************************************************************
4282 * objc_class::demangledName
4283 * If realize=false, the class must already be realized or future.
4284 * Locking: If realize=true, runtimeLock must be held for writing by the caller.
4285 **********************************************************************/
4286 mutex_t DemangleCacheLock;
4287 static NXHashTable *DemangleCache;
4289 objc_class::demangledName(bool realize)
4291 // Return previously demangled name if available.
4292 if (isRealized() || isFuture()) {
4293 if (data()->demangledName) return data()->demangledName;
4296 // Try demangling the mangled name.
4297 const char *mangled = mangledName();
4298 char *de = copySwiftV1DemangledName(mangled);
4299 if (isRealized() || isFuture()) {
4300 // Class is already realized or future.
4301 // Save demangling result in rw data.
4302 // We may not own rwlock for writing so use an atomic operation instead.
4303 if (! OSAtomicCompareAndSwapPtrBarrier(nil, (void*)(de ?: mangled),
4304 (void**)&data()->demangledName))
4308 return data()->demangledName;
4311 // Class is not yet realized.
4313 // Name is not mangled. Return it without caching.
4317 // Class is not yet realized and name is mangled. Realize the class.
4318 // Only objc_copyClassNamesForImage() should get here.
4320 // fixme lldb's calls to class_getName() can also get here when
4321 // interrogating the dyld shared cache. (rdar://27258517)
4322 // fixme runtimeLock.assertWriting();
4323 // fixme assert(realize);
4326 runtimeLock.assertWriting();
4327 realizeClass((Class)this);
4328 data()->demangledName = de;
4332 // Save the string to avoid leaks.
4335 mutex_locker_t lock(DemangleCacheLock);
4336 if (!DemangleCache) {
4337 DemangleCache = NXCreateHashTable(NXStrPrototype, 0, nil);
4339 cached = (char *)NXHashInsertIfAbsent(DemangleCache, de);
4341 if (cached != de) free(de);
4347 /***********************************************************************
4350 * Locking: acquires runtimeLock
4351 **********************************************************************/
4352 const char *class_getName(Class cls)
4354 if (!cls) return "nil";
4355 // fixme lldb calls class_getName() on unrealized classes (rdar://27258517)
4356 // assert(cls->isRealized() || cls->isFuture());
4357 return cls->demangledName();
4361 /***********************************************************************
4365 **********************************************************************/
4367 class_getVersion(Class cls)
4370 assert(cls->isRealized());
4371 return cls->data()->version;
4375 /***********************************************************************
4379 **********************************************************************/
4381 class_setVersion(Class cls, int version)
4384 assert(cls->isRealized());
4385 cls->data()->version = version;
4389 static method_t *findMethodInSortedMethodList(SEL key, const method_list_t *list)
4393 const method_t * const first = &list->first;
4394 const method_t *base = first;
4395 const method_t *probe;
4396 uintptr_t keyValue = (uintptr_t)key;
4399 for (count = list->count; count != 0; count >>= 1) {
4400 probe = base + (count >> 1);
4402 uintptr_t probeValue = (uintptr_t)probe->name;
4404 if (keyValue == probeValue) {
4405 // `probe` is a match.
4406 // Rewind looking for the *first* occurrence of this value.
4407 // This is required for correct category overrides.
4408 while (probe > first && keyValue == (uintptr_t)probe[-1].name) {
4411 return (method_t *)probe;
4414 if (keyValue > probeValue) {
4423 /***********************************************************************
4424 * getMethodNoSuper_nolock
4426 * Locking: runtimeLock must be read- or write-locked by the caller
4427 **********************************************************************/
4428 static method_t *search_method_list(const method_list_t *mlist, SEL sel)
4430 int methodListIsFixedUp = mlist->isFixedUp();
4431 int methodListHasExpectedSize = mlist->entsize() == sizeof(method_t);
4433 if (__builtin_expect(methodListIsFixedUp && methodListHasExpectedSize, 1)) {
4434 return findMethodInSortedMethodList(sel, mlist);
4436 // Linear search of unsorted method list
4437 for (auto& meth : *mlist) {
4438 if (meth.name == sel) return &meth;
4443 // sanity-check negative results
4444 if (mlist->isFixedUp()) {
4445 for (auto& meth : *mlist) {
4446 if (meth.name == sel) {
4447 _objc_fatal("linear search worked when binary search did not");
4457 getMethodNoSuper_nolock(Class cls, SEL sel)
4459 runtimeLock.assertLocked();
4461 assert(cls->isRealized());
4465 for (auto mlists = cls->data()->methods.beginLists(),
4466 end = cls->data()->methods.endLists();
4470 method_t *m = search_method_list(*mlists, sel);
4478 /***********************************************************************
4481 * Locking: runtimeLock must be read- or write-locked by the caller
4482 **********************************************************************/
4484 getMethod_nolock(Class cls, SEL sel)
4488 runtimeLock.assertLocked();
4493 assert(cls->isRealized());
4495 while (cls && ((m = getMethodNoSuper_nolock(cls, sel))) == nil) {
4496 cls = cls->superclass;
4503 /***********************************************************************
4506 * Locking: read-locks runtimeLock
4507 **********************************************************************/
4508 static Method _class_getMethod(Class cls, SEL sel)
4510 rwlock_reader_t lock(runtimeLock);
4511 return getMethod_nolock(cls, sel);
4515 /***********************************************************************
4516 * class_getInstanceMethod. Return the instance method for the
4517 * specified class and selector.
4518 **********************************************************************/
4519 Method class_getInstanceMethod(Class cls, SEL sel)
4521 if (!cls || !sel) return nil;
4523 // This deliberately avoids +initialize because it historically did so.
4525 // This implementation is a bit weird because it's the only place that
4526 // wants a Method instead of an IMP.
4528 #warning fixme build and search caches
4530 // Search method lists, try method resolver, etc.
4531 lookUpImpOrNil(cls, sel, nil,
4532 NO/*initialize*/, NO/*cache*/, YES/*resolver*/);
4534 #warning fixme build and search caches
4536 return _class_getMethod(cls, sel);
4540 /***********************************************************************
4541 * log_and_fill_cache
4542 * Log this method call. If the logger permits it, fill the method cache.
4543 * cls is the method whose cache should be filled.
4544 * implementer is the class that owns the implementation in question.
4545 **********************************************************************/
4547 log_and_fill_cache(Class cls, IMP imp, SEL sel, id receiver, Class implementer)
4549 #if SUPPORT_MESSAGE_LOGGING
4550 if (objcMsgLogEnabled) {
4551 bool cacheIt = logMessageSend(implementer->isMetaClass(),
4552 cls->nameForLogging(),
4553 implementer->nameForLogging(),
4555 if (!cacheIt) return;
4558 cache_fill (cls, sel, imp, receiver);
4562 /***********************************************************************
4563 * _class_lookupMethodAndLoadCache.
4564 * Method lookup for dispatchers ONLY. OTHER CODE SHOULD USE lookUpImp().
4565 * This lookup avoids optimistic cache scan because the dispatcher
4566 * already tried that.
4567 **********************************************************************/
4568 IMP _class_lookupMethodAndLoadCache3(id obj, SEL sel, Class cls)
4570 return lookUpImpOrForward(cls, sel, obj,
4571 YES/*initialize*/, NO/*cache*/, YES/*resolver*/);
4575 /***********************************************************************
4576 * lookUpImpOrForward.
4577 * The standard IMP lookup.
4578 * initialize==NO tries to avoid +initialize (but sometimes fails)
4579 * cache==NO skips optimistic unlocked lookup (but uses cache elsewhere)
4580 * Most callers should use initialize==YES and cache==YES.
4581 * inst is an instance of cls or a subclass thereof, or nil if none is known.
4582 * If cls is an un-initialized metaclass then a non-nil inst is faster.
4583 * May return _objc_msgForward_impcache. IMPs destined for external use
4584 * must be converted to _objc_msgForward or _objc_msgForward_stret.
4585 * If you don't want forwarding at all, use lookUpImpOrNil() instead.
4586 **********************************************************************/
4587 IMP lookUpImpOrForward(Class cls, SEL sel, id inst,
4588 bool initialize, bool cache, bool resolver)
4591 bool triedResolver = NO;
4593 runtimeLock.assertUnlocked();
4595 // Optimistic cache lookup
4597 imp = cache_getImp(cls, sel);
4598 if (imp) return imp;
4601 // runtimeLock is held during isRealized and isInitialized checking
4602 // to prevent races against concurrent realization.
4604 // runtimeLock is held during method search to make
4605 // method-lookup + cache-fill atomic with respect to method addition.
4606 // Otherwise, a category could be added but ignored indefinitely because
4607 // the cache was re-filled with the old value after the cache flush on
4608 // behalf of the category.
4612 if (!cls->isRealized()) {
4613 // Drop the read-lock and acquire the write-lock.
4614 // realizeClass() checks isRealized() again to prevent
4615 // a race while the lock is down.
4616 runtimeLock.unlockRead();
4617 runtimeLock.write();
4621 runtimeLock.unlockWrite();
4625 if (initialize && !cls->isInitialized()) {
4626 runtimeLock.unlockRead();
4627 _class_initialize (_class_getNonMetaClass(cls, inst));
4629 // If sel == initialize, _class_initialize will send +initialize and
4630 // then the messenger will send +initialize again after this
4631 // procedure finishes. Of course, if this is not being called
4632 // from the messenger then it won't happen. 2778172
4637 runtimeLock.assertReading();
4639 // Try this class's cache.
4641 imp = cache_getImp(cls, sel);
4644 // Try this class's method lists.
4646 Method meth = getMethodNoSuper_nolock(cls, sel);
4648 log_and_fill_cache(cls, meth->imp, sel, inst, cls);
4654 // Try superclass caches and method lists.
4656 unsigned attempts = unreasonableClassCount();
4657 for (Class curClass = cls;
4659 curClass = curClass->superclass)
4661 // Halt if there is a cycle in the superclass chain.
4662 if (--attempts == 0) {
4663 _objc_fatal("Memory corruption in class list.");
4666 // Superclass cache.
4667 imp = cache_getImp(curClass, sel);
4669 if (imp != (IMP)_objc_msgForward_impcache) {
4670 // Found the method in a superclass. Cache it in this class.
4671 log_and_fill_cache(cls, imp, sel, inst, curClass);
4675 // Found a forward:: entry in a superclass.
4676 // Stop searching, but don't cache yet; call method
4677 // resolver for this class first.
4682 // Superclass method list.
4683 Method meth = getMethodNoSuper_nolock(curClass, sel);
4685 log_and_fill_cache(cls, meth->imp, sel, inst, curClass);
4692 // No implementation found. Try method resolver once.
4694 if (resolver && !triedResolver) {
4695 runtimeLock.unlockRead();
4696 _class_resolveMethod(cls, sel, inst);
4698 // Don't cache the result; we don't hold the lock so it may have
4699 // changed already. Re-do the search from scratch instead.
4700 triedResolver = YES;
4704 // No implementation found, and method resolver didn't help.
4707 imp = (IMP)_objc_msgForward_impcache;
4708 cache_fill(cls, sel, imp, inst);
4711 runtimeLock.unlockRead();
4717 /***********************************************************************
4719 * Like lookUpImpOrForward, but returns nil instead of _objc_msgForward_impcache
4720 **********************************************************************/
4721 IMP lookUpImpOrNil(Class cls, SEL sel, id inst,
4722 bool initialize, bool cache, bool resolver)
4724 IMP imp = lookUpImpOrForward(cls, sel, inst, initialize, cache, resolver);
4725 if (imp == _objc_msgForward_impcache) return nil;
4730 /***********************************************************************
4731 * lookupMethodInClassAndLoadCache.
4732 * Like _class_lookupMethodAndLoadCache, but does not search superclasses.
4733 * Caches and returns objc_msgForward if the method is not found in the class.
4734 **********************************************************************/
4735 IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel)
4740 // fixme this is incomplete - no resolver, +initialize -
4741 // but it's only used for .cxx_construct/destruct so we don't care
4742 assert(sel == SEL_cxx_construct || sel == SEL_cxx_destruct);
4744 // Search cache first.
4745 imp = cache_getImp(cls, sel);
4746 if (imp) return imp;
4748 // Cache miss. Search method list.
4750 rwlock_reader_t lock(runtimeLock);
4752 meth = getMethodNoSuper_nolock(cls, sel);
4755 // Hit in method list. Cache it.
4756 cache_fill(cls, sel, meth->imp, nil);
4759 // Miss in method list. Cache objc_msgForward.
4760 cache_fill(cls, sel, _objc_msgForward_impcache, nil);
4761 return _objc_msgForward_impcache;
4766 /***********************************************************************
4769 * Locking: read-locks runtimeLock
4770 **********************************************************************/
4771 objc_property_t class_getProperty(Class cls, const char *name)
4773 if (!cls || !name) return nil;
4775 rwlock_reader_t lock(runtimeLock);
4777 assert(cls->isRealized());
4779 for ( ; cls; cls = cls->superclass) {
4780 for (auto& prop : cls->data()->properties) {
4781 if (0 == strcmp(name, prop.name)) {
4782 return (objc_property_t)∝
4791 /***********************************************************************
4793 **********************************************************************/
4795 Class gdb_class_getClass(Class cls)
4797 const char *className = cls->mangledName();
4798 if(!className || !strlen(className)) return Nil;
4799 Class rCls = look_up_class(className, NO, NO);
4803 Class gdb_object_getClass(id obj)
4805 if (!obj) return nil;
4806 return gdb_class_getClass(obj->getIsa());
4810 /***********************************************************************
4811 * Locking: write-locks runtimeLock
4812 **********************************************************************/
4814 objc_class::setInitialized()
4819 assert(!isMetaClass());
4822 metacls = cls->ISA();
4824 rwlock_reader_t lock(runtimeLock);
4826 // Scan metaclass for custom AWZ.
4827 // Scan metaclass for custom RR.
4828 // Scan class for custom RR.
4829 // Also print custom RR/AWZ because we probably haven't done it yet.
4832 // NSObject AWZ class methods are default.
4833 // NSObject RR instance methods are default.
4834 // updateCustomRR_AWZ() also knows these special cases.
4835 // attachMethodLists() also knows these special cases.
4838 bool metaCustomAWZ = NO;
4839 if (MetaclassNSObjectAWZSwizzled) {
4840 // Somebody already swizzled NSObject's methods
4841 metaCustomAWZ = YES;
4844 else if (metacls == classNSObject()->ISA()) {
4845 // NSObject's metaclass AWZ is default, but we still need to check cats
4846 auto& methods = metacls->data()->methods;
4847 for (auto mlists = methods.beginCategoryMethodLists(),
4848 end = methods.endCategoryMethodLists(metacls);
4852 if (methodListImplementsAWZ(*mlists)) {
4853 metaCustomAWZ = YES;
4859 else if (metacls->superclass->hasCustomAWZ()) {
4860 // Superclass is custom AWZ, therefore we are too.
4861 metaCustomAWZ = YES;
4865 // Not metaclass NSObject.
4866 auto& methods = metacls->data()->methods;
4867 for (auto mlists = methods.beginLists(),
4868 end = methods.endLists();
4872 if (methodListImplementsAWZ(*mlists)) {
4873 metaCustomAWZ = YES;
4879 if (!metaCustomAWZ) metacls->setHasDefaultAWZ();
4881 if (PrintCustomAWZ && metaCustomAWZ) metacls->printCustomAWZ(inherited);
4882 // metacls->printCustomRR();
4885 bool clsCustomRR = NO;
4886 if (ClassNSObjectRRSwizzled) {
4887 // Somebody already swizzled NSObject's methods
4891 if (cls == classNSObject()) {
4892 // NSObject's RR is default, but we still need to check categories
4893 auto& methods = cls->data()->methods;
4894 for (auto mlists = methods.beginCategoryMethodLists(),
4895 end = methods.endCategoryMethodLists(cls);
4899 if (methodListImplementsRR(*mlists)) {
4906 else if (!cls->superclass) {
4907 // Custom root class
4911 else if (cls->superclass->hasCustomRR()) {
4912 // Superclass is custom RR, therefore we are too.
4917 // Not class NSObject.
4918 auto& methods = cls->data()->methods;
4919 for (auto mlists = methods.beginLists(),
4920 end = methods.endLists();
4924 if (methodListImplementsRR(*mlists)) {
4931 if (!clsCustomRR) cls->setHasDefaultRR();
4933 // cls->printCustomAWZ();
4934 if (PrintCustomRR && clsCustomRR) cls->printCustomRR(inherited);
4936 // Update the +initialize flags.
4938 metacls->changeInfo(RW_INITIALIZED, RW_INITIALIZING);
4942 /***********************************************************************
4943 * Return YES if sel is used by retain/release implementors
4944 **********************************************************************/
4946 isRRSelector(SEL sel)
4948 return (sel == SEL_retain || sel == SEL_release ||
4949 sel == SEL_autorelease || sel == SEL_retainCount ||
4950 sel == SEL_tryRetain || sel == SEL_retainWeakReference ||
4951 sel == SEL_isDeallocating || sel == SEL_allowsWeakReference);
4955 /***********************************************************************
4956 * Return YES if mlist implements one of the isRRSelector() methods
4957 **********************************************************************/
4959 methodListImplementsRR(const method_list_t *mlist)
4961 return (search_method_list(mlist, SEL_retain) ||
4962 search_method_list(mlist, SEL_release) ||
4963 search_method_list(mlist, SEL_autorelease) ||
4964 search_method_list(mlist, SEL_retainCount) ||
4965 search_method_list(mlist, SEL_tryRetain) ||
4966 search_method_list(mlist, SEL_isDeallocating) ||
4967 search_method_list(mlist, SEL_retainWeakReference) ||
4968 search_method_list(mlist, SEL_allowsWeakReference));
4972 /***********************************************************************
4973 * Return YES if sel is used by alloc or allocWithZone implementors
4974 **********************************************************************/
4976 isAWZSelector(SEL sel)
4978 return (sel == SEL_allocWithZone || sel == SEL_alloc);
4982 /***********************************************************************
4983 * Return YES if mlist implements one of the isAWZSelector() methods
4984 **********************************************************************/
4986 methodListImplementsAWZ(const method_list_t *mlist)
4988 return (search_method_list(mlist, SEL_allocWithZone) ||
4989 search_method_list(mlist, SEL_alloc));
4994 objc_class::printCustomRR(bool inherited)
4996 assert(PrintCustomRR);
4997 assert(hasCustomRR());
4998 _objc_inform("CUSTOM RR: %s%s%s", nameForLogging(),
4999 isMetaClass() ? " (meta)" : "",
5000 inherited ? " (inherited)" : "");
5004 objc_class::printCustomAWZ(bool inherited)
5006 assert(PrintCustomAWZ);
5007 assert(hasCustomAWZ());
5008 _objc_inform("CUSTOM AWZ: %s%s%s", nameForLogging(),
5009 isMetaClass() ? " (meta)" : "",
5010 inherited ? " (inherited)" : "");
5014 objc_class::printInstancesRequireRawIsa(bool inherited)
5016 assert(PrintRawIsa);
5017 assert(instancesRequireRawIsa());
5018 _objc_inform("RAW ISA: %s%s%s", nameForLogging(),
5019 isMetaClass() ? " (meta)" : "",
5020 inherited ? " (inherited)" : "");
5024 /***********************************************************************
5025 * Mark this class and all of its subclasses as implementors or
5026 * inheritors of custom RR (retain/release/autorelease/retainCount)
5027 **********************************************************************/
5028 void objc_class::setHasCustomRR(bool inherited)
5030 Class cls = (Class)this;
5031 runtimeLock.assertWriting();
5033 if (hasCustomRR()) return;
5035 foreach_realized_class_and_subclass(cls, ^(Class c){
5036 if (c != cls && !c->isInitialized()) {
5037 // Subclass not yet initialized. Wait for setInitialized() to do it
5038 // fixme short circuit recursion?
5041 if (c->hasCustomRR()) {
5042 // fixme short circuit recursion?
5046 c->bits.setHasCustomRR();
5048 if (PrintCustomRR) c->printCustomRR(inherited || c != cls);
5052 /***********************************************************************
5053 * Mark this class and all of its subclasses as implementors or
5054 * inheritors of custom alloc/allocWithZone:
5055 **********************************************************************/
5056 void objc_class::setHasCustomAWZ(bool inherited)
5058 Class cls = (Class)this;
5059 runtimeLock.assertWriting();
5061 if (hasCustomAWZ()) return;
5063 foreach_realized_class_and_subclass(cls, ^(Class c){
5064 if (c != cls && !c->isInitialized()) {
5065 // Subclass not yet initialized. Wait for setInitialized() to do it
5066 // fixme short circuit recursion?
5069 if (c->hasCustomAWZ()) {
5070 // fixme short circuit recursion?
5074 c->bits.setHasCustomAWZ();
5076 if (PrintCustomAWZ) c->printCustomAWZ(inherited || c != cls);
5081 /***********************************************************************
5082 * Mark this class and all of its subclasses as requiring raw isa pointers
5083 **********************************************************************/
5084 void objc_class::setInstancesRequireRawIsa(bool inherited)
5086 Class cls = (Class)this;
5087 runtimeLock.assertWriting();
5089 if (instancesRequireRawIsa()) return;
5091 foreach_realized_class_and_subclass(cls, ^(Class c){
5092 if (c->instancesRequireRawIsa()) {
5093 // fixme short circuit recursion?
5097 c->bits.setInstancesRequireRawIsa();
5099 if (PrintRawIsa) c->printInstancesRequireRawIsa(inherited || c != cls);
5104 /***********************************************************************
5105 * Choose a class index.
5106 * Set instancesRequireRawIsa if no more class indexes are available.
5107 **********************************************************************/
5108 void objc_class::chooseClassArrayIndex()
5110 #if SUPPORT_INDEXED_ISA
5111 Class cls = (Class)this;
5112 runtimeLock.assertWriting();
5114 if (objc_indexed_classes_count >= ISA_INDEX_COUNT) {
5115 // No more indexes available.
5116 assert(cls->classArrayIndex() == 0);
5117 cls->setInstancesRequireRawIsa(false/*not inherited*/);
5121 unsigned index = objc_indexed_classes_count++;
5122 if (index == 0) index = objc_indexed_classes_count++; // index 0 is unused
5123 classForIndex(index) = cls;
5124 cls->setClassArrayIndex(index);
5129 /***********************************************************************
5130 * Update custom RR and AWZ when a method changes its IMP
5131 **********************************************************************/
5133 updateCustomRR_AWZ(Class cls, method_t *meth)
5135 // In almost all cases, IMP swizzling does not affect custom RR/AWZ bits.
5136 // Custom RR/AWZ search will already find the method whether or not
5137 // it is swizzled, so it does not transition from non-custom to custom.
5139 // The only cases where IMP swizzling can affect the RR/AWZ bits is
5140 // if the swizzled method is one of the methods that is assumed to be
5141 // non-custom. These special cases are listed in setInitialized().
5142 // We look for such cases here.
5144 if (isRRSelector(meth->name)) {
5146 if ((classNSObject()->isInitialized() &&
5147 classNSObject()->hasCustomRR())
5149 ClassNSObjectRRSwizzled)
5151 // already custom, nothing would change
5155 bool swizzlingNSObject = NO;
5156 if (cls == classNSObject()) {
5157 swizzlingNSObject = YES;
5159 // Don't know the class.
5160 // The only special case is class NSObject.
5161 for (const auto& meth2 : classNSObject()->data()->methods) {
5162 if (meth == &meth2) {
5163 swizzlingNSObject = YES;
5168 if (swizzlingNSObject) {
5169 if (classNSObject()->isInitialized()) {
5170 classNSObject()->setHasCustomRR();
5172 // NSObject not yet +initialized, so custom RR has not yet
5173 // been checked, and setInitialized() will not notice the
5175 ClassNSObjectRRSwizzled = YES;
5179 else if (isAWZSelector(meth->name)) {
5180 Class metaclassNSObject = classNSObject()->ISA();
5182 if ((metaclassNSObject->isInitialized() &&
5183 metaclassNSObject->hasCustomAWZ())
5185 MetaclassNSObjectAWZSwizzled)
5187 // already custom, nothing would change
5191 bool swizzlingNSObject = NO;
5192 if (cls == metaclassNSObject) {
5193 swizzlingNSObject = YES;
5195 // Don't know the class.
5196 // The only special case is metaclass NSObject.
5197 for (const auto& meth2 : metaclassNSObject->data()->methods) {
5198 if (meth == &meth2) {
5199 swizzlingNSObject = YES;
5204 if (swizzlingNSObject) {
5205 if (metaclassNSObject->isInitialized()) {
5206 metaclassNSObject->setHasCustomAWZ();
5208 // NSObject not yet +initialized, so custom RR has not yet
5209 // been checked, and setInitialized() will not notice the
5211 MetaclassNSObjectAWZSwizzled = YES;
5218 /***********************************************************************
5219 * class_getIvarLayout
5220 * Called by the garbage collector.
5221 * The class must be nil or already realized.
5223 **********************************************************************/
5225 class_getIvarLayout(Class cls)
5227 if (cls) return cls->data()->ro->ivarLayout;
5232 /***********************************************************************
5233 * class_getWeakIvarLayout
5234 * Called by the garbage collector.
5235 * The class must be nil or already realized.
5237 **********************************************************************/
5239 class_getWeakIvarLayout(Class cls)
5241 if (cls) return cls->data()->ro->weakIvarLayout;
5246 /***********************************************************************
5247 * class_setIvarLayout
5248 * Changes the class's ivar layout.
5249 * nil layout means no unscanned ivars
5250 * The class must be under construction.
5251 * fixme: sanity-check layout vs instance size?
5252 * fixme: sanity-check layout vs superclass?
5253 * Locking: acquires runtimeLock
5254 **********************************************************************/
5256 class_setIvarLayout(Class cls, const uint8_t *layout)
5260 rwlock_writer_t lock(runtimeLock);
5262 // Can only change layout of in-construction classes.
5263 // note: if modifications to post-construction classes were
5264 // allowed, there would be a race below (us vs. concurrent object_setIvar)
5265 if (!(cls->data()->flags & RW_CONSTRUCTING)) {
5266 _objc_inform("*** Can't set ivar layout for already-registered "
5267 "class '%s'", cls->nameForLogging());
5271 class_ro_t *ro_w = make_ro_writeable(cls->data());
5273 try_free(ro_w->ivarLayout);
5274 ro_w->ivarLayout = ustrdupMaybeNil(layout);
5277 // SPI: Instance-specific object layout.
5280 _class_setIvarLayoutAccessor(Class cls, const uint8_t* (*accessor) (id object)) {
5283 rwlock_writer_t lock(runtimeLock);
5285 class_ro_t *ro_w = make_ro_writeable(cls->data());
5287 // FIXME: this really isn't safe to free if there are instances of this class already.
5288 if (!(cls->data()->flags & RW_HAS_INSTANCE_SPECIFIC_LAYOUT)) try_free(ro_w->ivarLayout);
5289 ro_w->ivarLayout = (uint8_t *)accessor;
5290 cls->setInfo(RW_HAS_INSTANCE_SPECIFIC_LAYOUT);
5294 _object_getIvarLayout(Class cls, id object)
5297 const uint8_t* layout = cls->data()->ro->ivarLayout;
5298 if (cls->data()->flags & RW_HAS_INSTANCE_SPECIFIC_LAYOUT) {
5299 const uint8_t* (*accessor) (id object) = (const uint8_t* (*)(id))layout;
5300 layout = accessor(object);
5307 /***********************************************************************
5308 * class_setWeakIvarLayout
5309 * Changes the class's weak ivar layout.
5310 * nil layout means no weak ivars
5311 * The class must be under construction.
5312 * fixme: sanity-check layout vs instance size?
5313 * fixme: sanity-check layout vs superclass?
5314 * Locking: acquires runtimeLock
5315 **********************************************************************/
5317 class_setWeakIvarLayout(Class cls, const uint8_t *layout)
5321 rwlock_writer_t lock(runtimeLock);
5323 // Can only change layout of in-construction classes.
5324 // note: if modifications to post-construction classes were
5325 // allowed, there would be a race below (us vs. concurrent object_setIvar)
5326 if (!(cls->data()->flags & RW_CONSTRUCTING)) {
5327 _objc_inform("*** Can't set weak ivar layout for already-registered "
5328 "class '%s'", cls->nameForLogging());
5332 class_ro_t *ro_w = make_ro_writeable(cls->data());
5334 try_free(ro_w->weakIvarLayout);
5335 ro_w->weakIvarLayout = ustrdupMaybeNil(layout);
5339 /***********************************************************************
5341 * Look up an ivar by name.
5342 * Locking: runtimeLock must be read- or write-locked by the caller.
5343 **********************************************************************/
5344 static ivar_t *getIvar(Class cls, const char *name)
5346 runtimeLock.assertLocked();
5348 const ivar_list_t *ivars;
5349 assert(cls->isRealized());
5350 if ((ivars = cls->data()->ro->ivars)) {
5351 for (auto& ivar : *ivars) {
5352 if (!ivar.offset) continue; // anonymous bitfield
5354 // ivar.name may be nil for anonymous bitfields etc.
5355 if (ivar.name && 0 == strcmp(name, ivar.name)) {
5365 /***********************************************************************
5366 * _class_getClassForIvar
5367 * Given a class and an ivar that is in it or one of its superclasses,
5368 * find the actual class that defined the ivar.
5369 **********************************************************************/
5370 Class _class_getClassForIvar(Class cls, Ivar ivar)
5372 rwlock_reader_t lock(runtimeLock);
5374 for ( ; cls; cls = cls->superclass) {
5375 if (auto ivars = cls->data()->ro->ivars) {
5376 if (ivars->containsIvar(ivar)) {
5386 /***********************************************************************
5387 * _class_getVariable
5389 * Locking: read-locks runtimeLock
5390 **********************************************************************/
5392 _class_getVariable(Class cls, const char *name)
5394 rwlock_reader_t lock(runtimeLock);
5396 for ( ; cls; cls = cls->superclass) {
5397 ivar_t *ivar = getIvar(cls, name);
5407 /***********************************************************************
5408 * class_conformsToProtocol
5410 * Locking: read-locks runtimeLock
5411 **********************************************************************/
5412 BOOL class_conformsToProtocol(Class cls, Protocol *proto_gen)
5414 protocol_t *proto = newprotocol(proto_gen);
5416 if (!cls) return NO;
5417 if (!proto_gen) return NO;
5419 rwlock_reader_t lock(runtimeLock);
5421 assert(cls->isRealized());
5423 for (const auto& proto_ref : cls->data()->protocols) {
5424 protocol_t *p = remapProtocol(proto_ref);
5425 if (p == proto || protocol_conformsToProtocol_nolock(p, proto)) {
5434 /**********************************************************************
5437 * Locking: runtimeLock must be held by the caller
5438 **********************************************************************/
5440 addMethod(Class cls, SEL name, IMP imp, const char *types, bool replace)
5444 runtimeLock.assertWriting();
5447 assert(cls->isRealized());
5450 if ((m = getMethodNoSuper_nolock(cls, name))) {
5455 result = _method_setImplementation(cls, m, imp);
5459 method_list_t *newlist;
5460 newlist = (method_list_t *)calloc(sizeof(*newlist), 1);
5461 newlist->entsizeAndFlags =
5462 (uint32_t)sizeof(method_t) | fixed_up_method_list;
5464 newlist->first.name = name;
5465 newlist->first.types = strdupIfMutable(types);
5466 newlist->first.imp = imp;
5468 prepareMethodLists(cls, &newlist, 1, NO, NO);
5469 cls->data()->methods.attachLists(&newlist, 1);
5480 class_addMethod(Class cls, SEL name, IMP imp, const char *types)
5482 if (!cls) return NO;
5484 rwlock_writer_t lock(runtimeLock);
5485 return ! addMethod(cls, name, imp, types ?: "", NO);
5490 class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
5492 if (!cls) return nil;
5494 rwlock_writer_t lock(runtimeLock);
5495 return addMethod(cls, name, imp, types ?: "", YES);
5499 /***********************************************************************
5501 * Adds an ivar to a class.
5502 * Locking: acquires runtimeLock
5503 **********************************************************************/
5505 class_addIvar(Class cls, const char *name, size_t size,
5506 uint8_t alignment, const char *type)
5508 if (!cls) return NO;
5510 if (!type) type = "";
5511 if (name && 0 == strcmp(name, "")) name = nil;
5513 rwlock_writer_t lock(runtimeLock);
5515 assert(cls->isRealized());
5517 // No class variables
5518 if (cls->isMetaClass()) {
5522 // Can only add ivars to in-construction classes.
5523 if (!(cls->data()->flags & RW_CONSTRUCTING)) {
5527 // Check for existing ivar with this name, unless it's anonymous.
5528 // Check for too-big ivar.
5529 // fixme check for superclass ivar too?
5530 if ((name && getIvar(cls, name)) || size > UINT32_MAX) {
5534 class_ro_t *ro_w = make_ro_writeable(cls->data());
5536 // fixme allocate less memory here
5538 ivar_list_t *oldlist, *newlist;
5539 if ((oldlist = (ivar_list_t *)cls->data()->ro->ivars)) {
5540 size_t oldsize = oldlist->byteSize();
5541 newlist = (ivar_list_t *)calloc(oldsize + oldlist->entsize(), 1);
5542 memcpy(newlist, oldlist, oldsize);
5545 newlist = (ivar_list_t *)calloc(sizeof(ivar_list_t), 1);
5546 newlist->entsizeAndFlags = (uint32_t)sizeof(ivar_t);
5549 uint32_t offset = cls->unalignedInstanceSize();
5550 uint32_t alignMask = (1<<alignment)-1;
5551 offset = (offset + alignMask) & ~alignMask;
5553 ivar_t& ivar = newlist->get(newlist->count++);
5555 // Deliberately over-allocate the ivar offset variable.
5556 // Use calloc() to clear all 64 bits. See the note in struct ivar_t.
5557 ivar.offset = (int32_t *)(int64_t *)calloc(sizeof(int64_t), 1);
5559 ivar.offset = (int32_t *)malloc(sizeof(int32_t));
5561 *ivar.offset = offset;
5562 ivar.name = name ? strdupIfMutable(name) : nil;
5563 ivar.type = strdupIfMutable(type);
5564 ivar.alignment_raw = alignment;
5565 ivar.size = (uint32_t)size;
5567 ro_w->ivars = newlist;
5568 cls->setInstanceSize((uint32_t)(offset + size));
5570 // Ivar layout updated in registerClass.
5576 /***********************************************************************
5578 * Adds a protocol to a class.
5579 * Locking: acquires runtimeLock
5580 **********************************************************************/
5581 BOOL class_addProtocol(Class cls, Protocol *protocol_gen)
5583 protocol_t *protocol = newprotocol(protocol_gen);
5585 if (!cls) return NO;
5586 if (class_conformsToProtocol(cls, protocol_gen)) return NO;
5588 rwlock_writer_t lock(runtimeLock);
5590 assert(cls->isRealized());
5593 protocol_list_t *protolist = (protocol_list_t *)
5594 malloc(sizeof(protocol_list_t) + sizeof(protocol_t *));
5595 protolist->count = 1;
5596 protolist->list[0] = (protocol_ref_t)protocol;
5598 cls->data()->protocols.attachLists(&protolist, 1);
5606 /***********************************************************************
5608 * Adds a property to a class.
5609 * Locking: acquires runtimeLock
5610 **********************************************************************/
5612 _class_addProperty(Class cls, const char *name,
5613 const objc_property_attribute_t *attrs, unsigned int count,
5616 if (!cls) return NO;
5617 if (!name) return NO;
5619 property_t *prop = class_getProperty(cls, name);
5620 if (prop && !replace) {
5621 // already exists, refuse to replace
5626 rwlock_writer_t lock(runtimeLock);
5627 try_free(prop->attributes);
5628 prop->attributes = copyPropertyAttributeString(attrs, count);
5632 rwlock_writer_t lock(runtimeLock);
5634 assert(cls->isRealized());
5636 property_list_t *proplist = (property_list_t *)
5637 malloc(sizeof(*proplist));
5638 proplist->count = 1;
5639 proplist->entsizeAndFlags = sizeof(proplist->first);
5640 proplist->first.name = strdupIfMutable(name);
5641 proplist->first.attributes = copyPropertyAttributeString(attrs, count);
5643 cls->data()->properties.attachLists(&proplist, 1);
5650 class_addProperty(Class cls, const char *name,
5651 const objc_property_attribute_t *attrs, unsigned int n)
5653 return _class_addProperty(cls, name, attrs, n, NO);
5657 class_replaceProperty(Class cls, const char *name,
5658 const objc_property_attribute_t *attrs, unsigned int n)
5660 _class_addProperty(cls, name, attrs, n, YES);
5664 /***********************************************************************
5666 * Look up a class by name, and realize it.
5667 * Locking: acquires runtimeLock
5668 **********************************************************************/
5670 look_up_class(const char *name,
5671 bool includeUnconnected __attribute__((unused)),
5672 bool includeClassHandler __attribute__((unused)))
5674 if (!name) return nil;
5679 rwlock_reader_t lock(runtimeLock);
5680 result = getClass(name);
5681 unrealized = result && !result->isRealized();
5684 rwlock_writer_t lock(runtimeLock);
5685 realizeClass(result);
5691 /***********************************************************************
5692 * objc_duplicateClass
5694 * Locking: acquires runtimeLock
5695 **********************************************************************/
5697 objc_duplicateClass(Class original, const char *name,
5702 rwlock_writer_t lock(runtimeLock);
5704 assert(original->isRealized());
5705 assert(!original->isMetaClass());
5707 duplicate = alloc_class_for_subclass(original, extraBytes);
5709 duplicate->initClassIsa(original->ISA());
5710 duplicate->superclass = original->superclass;
5712 duplicate->cache.initializeToEmpty();
5714 class_rw_t *rw = (class_rw_t *)calloc(sizeof(*original->data()), 1);
5715 rw->flags = (original->data()->flags | RW_COPIED_RO | RW_REALIZING);
5716 rw->version = original->data()->version;
5717 rw->firstSubclass = nil;
5718 rw->nextSiblingClass = nil;
5720 duplicate->bits = original->bits;
5721 duplicate->setData(rw);
5723 rw->ro = (class_ro_t *)
5724 memdup(original->data()->ro, sizeof(*original->data()->ro));
5725 *(char **)&rw->ro->name = strdupIfMutable(name);
5727 rw->methods = original->data()->methods.duplicate();
5729 // fixme dies when categories are added to the base
5730 rw->properties = original->data()->properties;
5731 rw->protocols = original->data()->protocols;
5733 duplicate->chooseClassArrayIndex();
5735 if (duplicate->superclass) {
5736 addSubclass(duplicate->superclass, duplicate);
5737 // duplicate->isa == original->isa so don't addSubclass() for it
5739 addRootClass(duplicate);
5742 // Don't methodize class - construction above is correct
5744 addNamedClass(duplicate, duplicate->data()->ro->name);
5746 if (PrintConnecting) {
5747 _objc_inform("CLASS: realizing class '%s' (duplicate of %s) %p %p",
5748 name, original->nameForLogging(),
5749 (void*)duplicate, duplicate->data()->ro);
5752 duplicate->clearInfo(RW_REALIZING);
5757 /***********************************************************************
5758 * objc_initializeClassPair
5759 * Locking: runtimeLock must be write-locked by the caller
5760 **********************************************************************/
5762 // &UnsetLayout is the default ivar layout during class construction
5763 static const uint8_t UnsetLayout = 0;
5765 static void objc_initializeClassPair_internal(Class superclass, const char *name, Class cls, Class meta)
5767 runtimeLock.assertWriting();
5769 class_ro_t *cls_ro_w, *meta_ro_w;
5771 cls->setData((class_rw_t *)calloc(sizeof(class_rw_t), 1));
5772 meta->setData((class_rw_t *)calloc(sizeof(class_rw_t), 1));
5773 cls_ro_w = (class_ro_t *)calloc(sizeof(class_ro_t), 1);
5774 meta_ro_w = (class_ro_t *)calloc(sizeof(class_ro_t), 1);
5775 cls->data()->ro = cls_ro_w;
5776 meta->data()->ro = meta_ro_w;
5780 cls->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED | RW_REALIZING;
5781 meta->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED | RW_REALIZING;
5782 cls->data()->version = 0;
5783 meta->data()->version = 7;
5785 cls_ro_w->flags = 0;
5786 meta_ro_w->flags = RO_META;
5788 cls_ro_w->flags |= RO_ROOT;
5789 meta_ro_w->flags |= RO_ROOT;
5792 cls_ro_w->instanceStart = superclass->unalignedInstanceSize();
5793 meta_ro_w->instanceStart = superclass->ISA()->unalignedInstanceSize();
5794 cls->setInstanceSize(cls_ro_w->instanceStart);
5795 meta->setInstanceSize(meta_ro_w->instanceStart);
5797 cls_ro_w->instanceStart = 0;
5798 meta_ro_w->instanceStart = (uint32_t)sizeof(objc_class);
5799 cls->setInstanceSize((uint32_t)sizeof(id)); // just an isa
5800 meta->setInstanceSize(meta_ro_w->instanceStart);
5803 cls_ro_w->name = strdupIfMutable(name);
5804 meta_ro_w->name = strdupIfMutable(name);
5806 cls_ro_w->ivarLayout = &UnsetLayout;
5807 cls_ro_w->weakIvarLayout = &UnsetLayout;
5809 meta->chooseClassArrayIndex();
5810 cls->chooseClassArrayIndex();
5812 // Connect to superclasses and metaclasses
5813 cls->initClassIsa(meta);
5815 meta->initClassIsa(superclass->ISA()->ISA());
5816 cls->superclass = superclass;
5817 meta->superclass = superclass->ISA();
5818 addSubclass(superclass, cls);
5819 addSubclass(superclass->ISA(), meta);
5821 meta->initClassIsa(meta);
5822 cls->superclass = Nil;
5823 meta->superclass = cls;
5825 addSubclass(cls, meta);
5828 cls->cache.initializeToEmpty();
5829 meta->cache.initializeToEmpty();
5833 /***********************************************************************
5835 * Sanity-check the superclass provided to
5836 * objc_allocateClassPair, objc_initializeClassPair, or objc_readClassPair.
5837 **********************************************************************/
5839 verifySuperclass(Class superclass, bool rootOK)
5842 // Superclass does not exist.
5843 // If subclass may be a root class, this is OK.
5844 // If subclass must not be a root class, this is bad.
5848 // Superclass must be realized.
5849 if (! superclass->isRealized()) return false;
5851 // Superclass must not be under construction.
5852 if (superclass->data()->flags & RW_CONSTRUCTING) return false;
5858 /***********************************************************************
5859 * objc_initializeClassPair
5860 **********************************************************************/
5861 Class objc_initializeClassPair(Class superclass, const char *name, Class cls, Class meta)
5863 rwlock_writer_t lock(runtimeLock);
5865 // Fail if the class name is in use.
5866 // Fail if the superclass isn't kosher.
5867 if (getClass(name) || !verifySuperclass(superclass, true/*rootOK*/)) {
5871 objc_initializeClassPair_internal(superclass, name, cls, meta);
5877 /***********************************************************************
5878 * objc_allocateClassPair
5880 * Locking: acquires runtimeLock
5881 **********************************************************************/
5882 Class objc_allocateClassPair(Class superclass, const char *name,
5887 rwlock_writer_t lock(runtimeLock);
5889 // Fail if the class name is in use.
5890 // Fail if the superclass isn't kosher.
5891 if (getClass(name) || !verifySuperclass(superclass, true/*rootOK*/)) {
5895 // Allocate new classes.
5896 cls = alloc_class_for_subclass(superclass, extraBytes);
5897 meta = alloc_class_for_subclass(superclass, extraBytes);
5899 // fixme mangle the name if it looks swift-y?
5900 objc_initializeClassPair_internal(superclass, name, cls, meta);
5906 /***********************************************************************
5907 * objc_registerClassPair
5909 * Locking: acquires runtimeLock
5910 **********************************************************************/
5911 void objc_registerClassPair(Class cls)
5913 rwlock_writer_t lock(runtimeLock);
5915 if ((cls->data()->flags & RW_CONSTRUCTED) ||
5916 (cls->ISA()->data()->flags & RW_CONSTRUCTED))
5918 _objc_inform("objc_registerClassPair: class '%s' was already "
5919 "registered!", cls->data()->ro->name);
5923 if (!(cls->data()->flags & RW_CONSTRUCTING) ||
5924 !(cls->ISA()->data()->flags & RW_CONSTRUCTING))
5926 _objc_inform("objc_registerClassPair: class '%s' was not "
5927 "allocated with objc_allocateClassPair!",
5928 cls->data()->ro->name);
5932 // Clear "under construction" bit, set "done constructing" bit
5933 cls->ISA()->changeInfo(RW_CONSTRUCTED, RW_CONSTRUCTING | RW_REALIZING);
5934 cls->changeInfo(RW_CONSTRUCTED, RW_CONSTRUCTING | RW_REALIZING);
5936 // Add to named class table.
5937 addNamedClass(cls, cls->data()->ro->name);
5941 /***********************************************************************
5942 * objc_readClassPair()
5943 * Read a class and metaclass as written by a compiler.
5944 * Assumes the class and metaclass are not referenced by other things
5945 * that might need to be fixed up (such as categories and subclasses).
5946 * Does not call +load.
5947 * Returns the class pointer, or nil.
5949 * Locking: runtimeLock acquired by map_images
5950 **********************************************************************/
5951 Class objc_readClassPair(Class bits, const struct objc_image_info *info)
5953 rwlock_writer_t lock(runtimeLock);
5955 // No info bits are significant yet.
5958 // Fail if the class name is in use.
5959 // Fail if the superclass isn't kosher.
5960 const char *name = bits->mangledName();
5961 bool rootOK = bits->data()->flags & RO_ROOT;
5962 if (getClass(name) || !verifySuperclass(bits->superclass, rootOK)){
5966 Class cls = readClass(bits, false/*bundle*/, false/*shared cache*/);
5968 // This function isn't allowed to remap anything.
5969 _objc_fatal("objc_readClassPair for class %s changed %p to %p",
5970 cls->nameForLogging(), bits, cls);
5978 /***********************************************************************
5980 * Disconnect a class from other data structures.
5981 * Exception: does not remove the class from the +load list
5982 * Call this before free_class.
5983 * Locking: runtimeLock must be held by the caller.
5984 **********************************************************************/
5985 static void detach_class(Class cls, bool isMeta)
5987 runtimeLock.assertWriting();
5989 // categories not yet attached to this class
5990 removeAllUnattachedCategoriesForClass(cls);
5992 // superclass's subclass list
5993 if (cls->isRealized()) {
5994 Class supercls = cls->superclass;
5996 removeSubclass(supercls, cls);
5998 removeRootClass(cls);
6002 // class tables and +load queue
6004 removeNamedClass(cls, cls->mangledName());
6009 /***********************************************************************
6011 * Frees a class's data structures.
6012 * Call this after detach_class.
6013 * Locking: runtimeLock must be held by the caller
6014 **********************************************************************/
6015 static void free_class(Class cls)
6017 runtimeLock.assertWriting();
6019 if (! cls->isRealized()) return;
6021 auto rw = cls->data();
6026 for (auto& meth : rw->methods) {
6027 try_free(meth.types);
6029 rw->methods.tryFree();
6031 const ivar_list_t *ivars = ro->ivars;
6033 for (auto& ivar : *ivars) {
6034 try_free(ivar.offset);
6035 try_free(ivar.name);
6036 try_free(ivar.type);
6041 for (auto& prop : rw->properties) {
6042 try_free(prop.name);
6043 try_free(prop.attributes);
6045 rw->properties.tryFree();
6047 rw->protocols.tryFree();
6049 try_free(ro->ivarLayout);
6050 try_free(ro->weakIvarLayout);
6058 void objc_disposeClassPair(Class cls)
6060 rwlock_writer_t lock(runtimeLock);
6062 if (!(cls->data()->flags & (RW_CONSTRUCTED|RW_CONSTRUCTING)) ||
6063 !(cls->ISA()->data()->flags & (RW_CONSTRUCTED|RW_CONSTRUCTING)))
6065 // class not allocated with objc_allocateClassPair
6066 // disposing still-unregistered class is OK!
6067 _objc_inform("objc_disposeClassPair: class '%s' was not "
6068 "allocated with objc_allocateClassPair!",
6069 cls->data()->ro->name);
6073 if (cls->isMetaClass()) {
6074 _objc_inform("objc_disposeClassPair: class '%s' is a metaclass, "
6075 "not a class!", cls->data()->ro->name);
6079 // Shouldn't have any live subclasses.
6080 if (cls->data()->firstSubclass) {
6081 _objc_inform("objc_disposeClassPair: class '%s' still has subclasses, "
6082 "including '%s'!", cls->data()->ro->name,
6083 cls->data()->firstSubclass->nameForLogging());
6085 if (cls->ISA()->data()->firstSubclass) {
6086 _objc_inform("objc_disposeClassPair: class '%s' still has subclasses, "
6087 "including '%s'!", cls->data()->ro->name,
6088 cls->ISA()->data()->firstSubclass->nameForLogging());
6091 // don't remove_class_from_loadable_list()
6092 // - it's not there and we don't have the lock
6093 detach_class(cls->ISA(), YES);
6094 detach_class(cls, NO);
6095 free_class(cls->ISA());
6100 /***********************************************************************
6101 * objc_constructInstance
6102 * Creates an instance of `cls` at the location pointed to by `bytes`.
6103 * `bytes` must point to at least class_getInstanceSize(cls) bytes of
6104 * well-aligned zero-filled memory.
6105 * The new object's isa is set. Any C++ constructors are called.
6106 * Returns `bytes` if successful. Returns nil if `cls` or `bytes` is
6107 * nil, or if C++ constructors fail.
6108 * Note: class_createInstance() and class_createInstances() preflight this.
6109 **********************************************************************/
6111 objc_constructInstance(Class cls, void *bytes)
6113 if (!cls || !bytes) return nil;
6117 // Read class's info bits all at once for performance
6118 bool hasCxxCtor = cls->hasCxxCtor();
6119 bool hasCxxDtor = cls->hasCxxDtor();
6120 bool fast = cls->canAllocNonpointer();
6123 obj->initInstanceIsa(cls, hasCxxDtor);
6129 return object_cxxConstructFromClass(obj, cls);
6136 /***********************************************************************
6137 * class_createInstance
6140 **********************************************************************/
6142 static __attribute__((always_inline))
6144 _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
6145 bool cxxConstruct = true,
6146 size_t *outAllocatedSize = nil)
6148 if (!cls) return nil;
6150 assert(cls->isRealized());
6152 // Read class's info bits all at once for performance
6153 bool hasCxxCtor = cls->hasCxxCtor();
6154 bool hasCxxDtor = cls->hasCxxDtor();
6155 bool fast = cls->canAllocNonpointer();
6157 size_t size = cls->instanceSize(extraBytes);
6158 if (outAllocatedSize) *outAllocatedSize = size;
6161 if (!zone && fast) {
6162 obj = (id)calloc(1, size);
6163 if (!obj) return nil;
6164 obj->initInstanceIsa(cls, hasCxxDtor);
6168 obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
6170 obj = (id)calloc(1, size);
6172 if (!obj) return nil;
6174 // Use raw pointer isa on the assumption that they might be
6175 // doing something weird with the zone or RR.
6179 if (cxxConstruct && hasCxxCtor) {
6180 obj = _objc_constructOrFree(obj, cls);
6188 class_createInstance(Class cls, size_t extraBytes)
6190 return _class_createInstanceFromZone(cls, extraBytes, nil);
6194 /***********************************************************************
6195 * class_createInstances
6198 **********************************************************************/
6199 #if SUPPORT_NONPOINTER_ISA
6200 #warning fixme optimize class_createInstances
6203 class_createInstances(Class cls, size_t extraBytes,
6204 id *results, unsigned num_requested)
6206 return _class_createInstancesFromZone(cls, extraBytes, nil,
6207 results, num_requested);
6210 /***********************************************************************
6211 * object_copyFromZone
6214 **********************************************************************/
6216 _object_copyFromZone(id oldObj, size_t extraBytes, void *zone)
6218 if (!oldObj) return nil;
6219 if (oldObj->isTaggedPointer()) return oldObj;
6221 // fixme this doesn't handle C++ ivars correctly (#4619414)
6223 Class cls = oldObj->ISA();
6225 id obj = _class_createInstanceFromZone(cls, extraBytes, zone, false, &size);
6226 if (!obj) return nil;
6228 // Copy everything except the isa, which was already set above.
6229 uint8_t *copyDst = (uint8_t *)obj + sizeof(Class);
6230 uint8_t *copySrc = (uint8_t *)oldObj + sizeof(Class);
6231 size_t copySize = size - sizeof(Class);
6232 memmove(copyDst, copySrc, copySize);
6234 fixupCopiedIvars(obj, oldObj);
6240 /***********************************************************************
6244 **********************************************************************/
6246 object_copy(id oldObj, size_t extraBytes)
6248 return _object_copyFromZone(oldObj, extraBytes, malloc_default_zone());
6252 #if !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)
6254 /***********************************************************************
6255 * class_createInstanceFromZone
6258 **********************************************************************/
6260 class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone)
6262 return _class_createInstanceFromZone(cls, extraBytes, zone);
6265 /***********************************************************************
6266 * object_copyFromZone
6269 **********************************************************************/
6271 object_copyFromZone(id oldObj, size_t extraBytes, void *zone)
6273 return _object_copyFromZone(oldObj, extraBytes, zone);
6279 /***********************************************************************
6280 * objc_destructInstance
6281 * Destroys an instance without freeing memory.
6282 * Calls C++ destructors.
6283 * Calls ARC ivar cleanup.
6284 * Removes associative references.
6285 * Returns `obj`. Does nothing if `obj` is nil.
6286 **********************************************************************/
6287 void *objc_destructInstance(id obj)
6290 // Read all of the flags at once for performance.
6291 bool cxx = obj->hasCxxDtor();
6292 bool assoc = obj->hasAssociatedObjects();
6294 // This order is important.
6295 if (cxx) object_cxxDestruct(obj);
6296 if (assoc) _object_remove_assocations(obj);
6297 obj->clearDeallocating();
6304 /***********************************************************************
6308 **********************************************************************/
6310 object_dispose(id obj)
6312 if (!obj) return nil;
6314 objc_destructInstance(obj);
6321 /***********************************************************************
6322 * _objc_getFreedObjectClass
6325 **********************************************************************/
6326 Class _objc_getFreedObjectClass (void)
6333 /***********************************************************************
6334 * Tagged pointer objects.
6336 * Tagged pointer objects store the class and the object value in the
6337 * object pointer; the "pointer" does not actually point to anything.
6339 * Tagged pointer objects currently use this representation:
6341 * 1 bit set if tagged, clear if ordinary object pointer
6345 * The tag index defines the object's class.
6346 * The payload format is defined by the object's class.
6348 * If the tag index is 0b111, the tagged pointer object uses an
6349 * "extended" representation, allowing more classes but with smaller payloads:
6351 * 1 bit set if tagged, clear if ordinary object pointer
6353 * 8 bits extended tag index
6357 * Some architectures reverse the MSB and LSB in these representations.
6359 * This representation is subject to change. Representation-agnostic SPI is:
6360 * objc-internal.h for class implementers.
6361 * objc-gdb.h for debuggers.
6362 **********************************************************************/
6363 #if !SUPPORT_TAGGED_POINTERS
6365 // These variables are always provided for debuggers.
6366 uintptr_t objc_debug_taggedpointer_mask = 0;
6367 unsigned objc_debug_taggedpointer_slot_shift = 0;
6368 uintptr_t objc_debug_taggedpointer_slot_mask = 0;
6369 unsigned objc_debug_taggedpointer_payload_lshift = 0;
6370 unsigned objc_debug_taggedpointer_payload_rshift = 0;
6371 Class objc_debug_taggedpointer_classes[1] = { nil };
6373 uintptr_t objc_debug_taggedpointer_ext_mask = 0;
6374 unsigned objc_debug_taggedpointer_ext_slot_shift = 0;
6375 uintptr_t objc_debug_taggedpointer_ext_slot_mask = 0;
6376 unsigned objc_debug_taggedpointer_ext_payload_lshift = 0;
6377 unsigned objc_debug_taggedpointer_ext_payload_rshift = 0;
6378 Class objc_debug_taggedpointer_ext_classes[1] = { nil };
6381 disableTaggedPointers() { }
6385 // The "slot" used in the class table and given to the debugger
6386 // includes the is-tagged bit. This makes objc_msgSend faster.
6387 // The "ext" representation doesn't do that.
6389 uintptr_t objc_debug_taggedpointer_mask = _OBJC_TAG_MASK;
6390 unsigned objc_debug_taggedpointer_slot_shift = _OBJC_TAG_SLOT_SHIFT;
6391 uintptr_t objc_debug_taggedpointer_slot_mask = _OBJC_TAG_SLOT_MASK;
6392 unsigned objc_debug_taggedpointer_payload_lshift = _OBJC_TAG_PAYLOAD_LSHIFT;
6393 unsigned objc_debug_taggedpointer_payload_rshift = _OBJC_TAG_PAYLOAD_RSHIFT;
6394 // objc_debug_taggedpointer_classes is defined in objc-msg-*.s
6396 uintptr_t objc_debug_taggedpointer_ext_mask = _OBJC_TAG_EXT_MASK;
6397 unsigned objc_debug_taggedpointer_ext_slot_shift = _OBJC_TAG_EXT_SLOT_SHIFT;
6398 uintptr_t objc_debug_taggedpointer_ext_slot_mask = _OBJC_TAG_EXT_SLOT_MASK;
6399 unsigned objc_debug_taggedpointer_ext_payload_lshift = _OBJC_TAG_EXT_PAYLOAD_LSHIFT;
6400 unsigned objc_debug_taggedpointer_ext_payload_rshift = _OBJC_TAG_EXT_PAYLOAD_RSHIFT;
6401 // objc_debug_taggedpointer_ext_classes is defined in objc-msg-*.s
6404 disableTaggedPointers()
6406 objc_debug_taggedpointer_mask = 0;
6407 objc_debug_taggedpointer_slot_shift = 0;
6408 objc_debug_taggedpointer_slot_mask = 0;
6409 objc_debug_taggedpointer_payload_lshift = 0;
6410 objc_debug_taggedpointer_payload_rshift = 0;
6412 objc_debug_taggedpointer_ext_mask = 0;
6413 objc_debug_taggedpointer_ext_slot_shift = 0;
6414 objc_debug_taggedpointer_ext_slot_mask = 0;
6415 objc_debug_taggedpointer_ext_payload_lshift = 0;
6416 objc_debug_taggedpointer_ext_payload_rshift = 0;
6420 // Returns a pointer to the class's storage in the tagged class arrays.
6421 // Assumes the tag is a valid basic tag.
6423 classSlotForBasicTagIndex(objc_tag_index_t tag)
6425 // Array index in objc_tag_classes includes the tagged bit itself
6426 #if SUPPORT_MSB_TAGGED_POINTERS
6427 return &objc_tag_classes[0x8 | tag];
6429 return &objc_tag_classes[(tag << 1) | 1];
6434 // Returns a pointer to the class's storage in the tagged class arrays,
6435 // or nil if the tag is out of range.
6437 classSlotForTagIndex(objc_tag_index_t tag)
6439 if (tag >= OBJC_TAG_First60BitPayload && tag <= OBJC_TAG_Last60BitPayload) {
6440 return classSlotForBasicTagIndex(tag);
6443 if (tag >= OBJC_TAG_First52BitPayload && tag <= OBJC_TAG_Last52BitPayload) {
6444 return &objc_tag_ext_classes[tag - OBJC_TAG_First52BitPayload];
6451 /***********************************************************************
6452 * _objc_registerTaggedPointerClass
6453 * Set the class to use for the given tagged pointer index.
6454 * Aborts if the tag is out of range, or if the tag is already
6455 * used by some other class.
6456 **********************************************************************/
6458 _objc_registerTaggedPointerClass(objc_tag_index_t tag, Class cls)
6460 if (objc_debug_taggedpointer_mask == 0) {
6461 _objc_fatal("tagged pointers are disabled");
6464 Class *slot = classSlotForTagIndex(tag);
6466 _objc_fatal("tag index %u is invalid", (unsigned int)tag);
6469 Class oldCls = *slot;
6471 if (cls && oldCls && cls != oldCls) {
6472 _objc_fatal("tag index %u used for two different classes "
6473 "(was %p %s, now %p %s)", tag,
6474 oldCls, oldCls->nameForLogging(),
6475 cls, cls->nameForLogging());
6480 // Store a placeholder class in the basic tag slot that is
6481 // reserved for the extended tag space, if it isn't set already.
6482 // Do this lazily when the first extended tag is registered so
6483 // that old debuggers characterize bogus pointers correctly more often.
6484 if (tag < OBJC_TAG_First60BitPayload || tag > OBJC_TAG_Last60BitPayload) {
6485 Class *extSlot = classSlotForBasicTagIndex(OBJC_TAG_RESERVED_7);
6486 if (*extSlot == nil) {
6487 extern objc_class OBJC_CLASS_$___NSUnrecognizedTaggedPointer;
6488 *extSlot = (Class)&OBJC_CLASS_$___NSUnrecognizedTaggedPointer;
6494 /***********************************************************************
6495 * _objc_getClassForTag
6496 * Returns the class that is using the given tagged pointer tag.
6497 * Returns nil if no class is using that tag or the tag is out of range.
6498 **********************************************************************/
6500 _objc_getClassForTag(objc_tag_index_t tag)
6502 Class *slot = classSlotForTagIndex(tag);
6503 if (slot) return *slot;
6512 OBJC_EXTERN void objc_msgSend_fixup(void);
6513 OBJC_EXTERN void objc_msgSendSuper2_fixup(void);
6514 OBJC_EXTERN void objc_msgSend_stret_fixup(void);
6515 OBJC_EXTERN void objc_msgSendSuper2_stret_fixup(void);
6516 #if defined(__i386__) || defined(__x86_64__)
6517 OBJC_EXTERN void objc_msgSend_fpret_fixup(void);
6519 #if defined(__x86_64__)
6520 OBJC_EXTERN void objc_msgSend_fp2ret_fixup(void);
6523 OBJC_EXTERN void objc_msgSend_fixedup(void);
6524 OBJC_EXTERN void objc_msgSendSuper2_fixedup(void);
6525 OBJC_EXTERN void objc_msgSend_stret_fixedup(void);
6526 OBJC_EXTERN void objc_msgSendSuper2_stret_fixedup(void);
6527 #if defined(__i386__) || defined(__x86_64__)
6528 OBJC_EXTERN void objc_msgSend_fpret_fixedup(void);
6530 #if defined(__x86_64__)
6531 OBJC_EXTERN void objc_msgSend_fp2ret_fixedup(void);
6534 /***********************************************************************
6536 * Repairs an old vtable dispatch call site.
6537 * vtable dispatch itself is not supported.
6538 **********************************************************************/
6540 fixupMessageRef(message_ref_t *msg)
6542 msg->sel = sel_registerName((const char *)msg->sel);
6544 if (msg->imp == &objc_msgSend_fixup) {
6545 if (msg->sel == SEL_alloc) {
6546 msg->imp = (IMP)&objc_alloc;
6547 } else if (msg->sel == SEL_allocWithZone) {
6548 msg->imp = (IMP)&objc_allocWithZone;
6549 } else if (msg->sel == SEL_retain) {
6550 msg->imp = (IMP)&objc_retain;
6551 } else if (msg->sel == SEL_release) {
6552 msg->imp = (IMP)&objc_release;
6553 } else if (msg->sel == SEL_autorelease) {
6554 msg->imp = (IMP)&objc_autorelease;
6556 msg->imp = &objc_msgSend_fixedup;
6559 else if (msg->imp == &objc_msgSendSuper2_fixup) {
6560 msg->imp = &objc_msgSendSuper2_fixedup;
6562 else if (msg->imp == &objc_msgSend_stret_fixup) {
6563 msg->imp = &objc_msgSend_stret_fixedup;
6565 else if (msg->imp == &objc_msgSendSuper2_stret_fixup) {
6566 msg->imp = &objc_msgSendSuper2_stret_fixedup;
6568 #if defined(__i386__) || defined(__x86_64__)
6569 else if (msg->imp == &objc_msgSend_fpret_fixup) {
6570 msg->imp = &objc_msgSend_fpret_fixedup;
6573 #if defined(__x86_64__)
6574 else if (msg->imp == &objc_msgSend_fp2ret_fixup) {
6575 msg->imp = &objc_msgSend_fp2ret_fixedup;
6585 static Class setSuperclass(Class cls, Class newSuper)
6589 runtimeLock.assertWriting();
6591 assert(cls->isRealized());
6592 assert(newSuper->isRealized());
6594 oldSuper = cls->superclass;
6595 removeSubclass(oldSuper, cls);
6596 removeSubclass(oldSuper->ISA(), cls->ISA());
6598 cls->superclass = newSuper;
6599 cls->ISA()->superclass = newSuper->ISA();
6600 addSubclass(newSuper, cls);
6601 addSubclass(newSuper->ISA(), cls->ISA());
6603 // Flush subclass's method caches.
6605 flushCaches(cls->ISA());
6611 Class class_setSuperclass(Class cls, Class newSuper)
6613 rwlock_writer_t lock(runtimeLock);
6614 return setSuperclass(cls, newSuper);