]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-runtime-new.mm
objc4-756.2.tar.gz
[apple/objc4.git] / runtime / objc-runtime-new.mm
1 /*
2 * Copyright (c) 2005-2009 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /***********************************************************************
25 * objc-runtime-new.m
26 * Support for new-ABI classes and images.
27 **********************************************************************/
28
29 #if __OBJC2__
30
31 #include "objc-private.h"
32 #include "objc-runtime-new.h"
33 #include "objc-file.h"
34 #include "objc-cache.h"
35 #include <Block.h>
36 #include <objc/message.h>
37 #include <mach/shared_region.h>
38
39 #define newprotocol(p) ((protocol_t *)p)
40
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 method_t *getMethodNoSuper_nolock(Class cls, SEL sel);
46 static method_t *getMethod_nolock(Class cls, SEL sel);
47 static IMP addMethod(Class cls, SEL name, IMP imp, const char *types, bool replace);
48 static bool isRRSelector(SEL sel);
49 static bool isAWZSelector(SEL sel);
50 static bool methodListImplementsRR(const method_list_t *mlist);
51 static bool methodListImplementsAWZ(const method_list_t *mlist);
52 static void updateCustomRR_AWZ(Class cls, method_t *meth);
53 static method_t *search_method_list(const method_list_t *mlist, SEL sel);
54 static void flushCaches(Class cls);
55 static void initializeTaggedPointerObfuscator(void);
56 #if SUPPORT_FIXUP
57 static void fixupMessageRef(message_ref_t *msg);
58 #endif
59 static Class realizeClassMaybeSwiftAndUnlock(Class cls, mutex_t& lock);
60 static Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized);
61
62 static bool MetaclassNSObjectAWZSwizzled;
63 static bool ClassNSObjectRRSwizzled;
64
65
66 /***********************************************************************
67 * Lock management
68 **********************************************************************/
69 mutex_t runtimeLock;
70 mutex_t selLock;
71 mutex_t cacheUpdateLock;
72 recursive_mutex_t loadMethodLock;
73
74 void lock_init(void)
75 {
76 }
77
78
79 /***********************************************************************
80 * Class structure decoding
81 **********************************************************************/
82
83 const uintptr_t objc_debug_class_rw_data_mask = FAST_DATA_MASK;
84
85
86 /***********************************************************************
87 * Non-pointer isa decoding
88 **********************************************************************/
89 #if SUPPORT_INDEXED_ISA
90
91 // Indexed non-pointer isa.
92
93 // These are used to mask the ISA and see if its got an index or not.
94 const uintptr_t objc_debug_indexed_isa_magic_mask = ISA_INDEX_MAGIC_MASK;
95 const uintptr_t objc_debug_indexed_isa_magic_value = ISA_INDEX_MAGIC_VALUE;
96
97 // die if masks overlap
98 STATIC_ASSERT((ISA_INDEX_MASK & ISA_INDEX_MAGIC_MASK) == 0);
99
100 // die if magic is wrong
101 STATIC_ASSERT((~ISA_INDEX_MAGIC_MASK & ISA_INDEX_MAGIC_VALUE) == 0);
102
103 // Then these are used to extract the index from the ISA.
104 const uintptr_t objc_debug_indexed_isa_index_mask = ISA_INDEX_MASK;
105 const uintptr_t objc_debug_indexed_isa_index_shift = ISA_INDEX_SHIFT;
106
107 asm("\n .globl _objc_absolute_indexed_isa_magic_mask" \
108 "\n _objc_absolute_indexed_isa_magic_mask = " STRINGIFY2(ISA_INDEX_MAGIC_MASK));
109 asm("\n .globl _objc_absolute_indexed_isa_magic_value" \
110 "\n _objc_absolute_indexed_isa_magic_value = " STRINGIFY2(ISA_INDEX_MAGIC_VALUE));
111 asm("\n .globl _objc_absolute_indexed_isa_index_mask" \
112 "\n _objc_absolute_indexed_isa_index_mask = " STRINGIFY2(ISA_INDEX_MASK));
113 asm("\n .globl _objc_absolute_indexed_isa_index_shift" \
114 "\n _objc_absolute_indexed_isa_index_shift = " STRINGIFY2(ISA_INDEX_SHIFT));
115
116
117 // And then we can use that index to get the class from this array. Note
118 // the size is provided so that clients can ensure the index they get is in
119 // bounds and not read off the end of the array.
120 // Defined in the objc-msg-*.s files
121 // const Class objc_indexed_classes[]
122
123 // When we don't have enough bits to store a class*, we can instead store an
124 // index in to this array. Classes are added here when they are realized.
125 // Note, an index of 0 is illegal.
126 uintptr_t objc_indexed_classes_count = 0;
127
128 // SUPPORT_INDEXED_ISA
129 #else
130 // not SUPPORT_INDEXED_ISA
131
132 // These variables exist but are all set to 0 so that they are ignored.
133 const uintptr_t objc_debug_indexed_isa_magic_mask = 0;
134 const uintptr_t objc_debug_indexed_isa_magic_value = 0;
135 const uintptr_t objc_debug_indexed_isa_index_mask = 0;
136 const uintptr_t objc_debug_indexed_isa_index_shift = 0;
137 Class objc_indexed_classes[1] = { nil };
138 uintptr_t objc_indexed_classes_count = 0;
139
140 // not SUPPORT_INDEXED_ISA
141 #endif
142
143
144 #if SUPPORT_PACKED_ISA
145
146 // Packed non-pointer isa.
147
148 asm("\n .globl _objc_absolute_packed_isa_class_mask" \
149 "\n _objc_absolute_packed_isa_class_mask = " STRINGIFY2(ISA_MASK));
150
151 const uintptr_t objc_debug_isa_class_mask = ISA_MASK;
152 const uintptr_t objc_debug_isa_magic_mask = ISA_MAGIC_MASK;
153 const uintptr_t objc_debug_isa_magic_value = ISA_MAGIC_VALUE;
154
155 // die if masks overlap
156 STATIC_ASSERT((ISA_MASK & ISA_MAGIC_MASK) == 0);
157
158 // die if magic is wrong
159 STATIC_ASSERT((~ISA_MAGIC_MASK & ISA_MAGIC_VALUE) == 0);
160
161 // die if virtual address space bound goes up
162 STATIC_ASSERT((~ISA_MASK & MACH_VM_MAX_ADDRESS) == 0 ||
163 ISA_MASK + sizeof(void*) == MACH_VM_MAX_ADDRESS);
164
165 // SUPPORT_PACKED_ISA
166 #else
167 // not SUPPORT_PACKED_ISA
168
169 // These variables exist but enforce pointer alignment only.
170 const uintptr_t objc_debug_isa_class_mask = (~WORD_MASK);
171 const uintptr_t objc_debug_isa_magic_mask = WORD_MASK;
172 const uintptr_t objc_debug_isa_magic_value = 0;
173
174 // not SUPPORT_PACKED_ISA
175 #endif
176
177
178 /***********************************************************************
179 * Swift marker bits
180 **********************************************************************/
181 const uintptr_t objc_debug_swift_stable_abi_bit = FAST_IS_SWIFT_STABLE;
182
183
184 /***********************************************************************
185 * allocatedClasses
186 * A table of all classes (and metaclasses) which have been allocated
187 * with objc_allocateClassPair.
188 **********************************************************************/
189 static NXHashTable *allocatedClasses = nil;
190
191
192 typedef locstamped_category_list_t category_list;
193
194
195 /*
196 Low two bits of mlist->entsize is used as the fixed-up marker.
197 PREOPTIMIZED VERSION:
198 Method lists from shared cache are 1 (uniqued) or 3 (uniqued and sorted).
199 (Protocol method lists are not sorted because of their extra parallel data)
200 Runtime fixed-up method lists get 3.
201 UN-PREOPTIMIZED VERSION:
202 Method lists from shared cache are 1 (uniqued) or 3 (uniqued and sorted)
203 Shared cache's sorting and uniquing are not trusted, but do affect the
204 location of the selector name string.
205 Runtime fixed-up method lists get 2.
206
207 High two bits of protocol->flags is used as the fixed-up marker.
208 PREOPTIMIZED VERSION:
209 Protocols from shared cache are 1<<30.
210 Runtime fixed-up protocols get 1<<30.
211 UN-PREOPTIMIZED VERSION:
212 Protocols from shared cache are 1<<30.
213 Shared cache's fixups are not trusted.
214 Runtime fixed-up protocols get 3<<30.
215 */
216
217 static uint32_t fixed_up_method_list = 3;
218 static uint32_t fixed_up_protocol = PROTOCOL_FIXED_UP_1;
219
220 void
221 disableSharedCacheOptimizations(void)
222 {
223 fixed_up_method_list = 2;
224 fixed_up_protocol = PROTOCOL_FIXED_UP_1 | PROTOCOL_FIXED_UP_2;
225 }
226
227 bool method_list_t::isFixedUp() const {
228 return flags() == fixed_up_method_list;
229 }
230
231 void method_list_t::setFixedUp() {
232 runtimeLock.assertLocked();
233 assert(!isFixedUp());
234 entsizeAndFlags = entsize() | fixed_up_method_list;
235 }
236
237 bool protocol_t::isFixedUp() const {
238 return (flags & PROTOCOL_FIXED_UP_MASK) == fixed_up_protocol;
239 }
240
241 void protocol_t::setFixedUp() {
242 runtimeLock.assertLocked();
243 assert(!isFixedUp());
244 flags = (flags & ~PROTOCOL_FIXED_UP_MASK) | fixed_up_protocol;
245 }
246
247
248 method_list_t **method_array_t::endCategoryMethodLists(Class cls)
249 {
250 method_list_t **mlists = beginLists();
251 method_list_t **mlistsEnd = endLists();
252
253 if (mlists == mlistsEnd || !cls->data()->ro->baseMethods())
254 {
255 // No methods, or no base methods.
256 // Everything here is a category method.
257 return mlistsEnd;
258 }
259
260 // Have base methods. Category methods are
261 // everything except the last method list.
262 return mlistsEnd - 1;
263 }
264
265 static const char *sel_cname(SEL sel)
266 {
267 return (const char *)(void *)sel;
268 }
269
270
271 static size_t protocol_list_size(const protocol_list_t *plist)
272 {
273 return sizeof(protocol_list_t) + plist->count * sizeof(protocol_t *);
274 }
275
276
277 static void try_free(const void *p)
278 {
279 if (p && malloc_size(p)) free((void *)p);
280 }
281
282
283 static void (*classCopyFixupHandler)(Class _Nonnull oldClass,
284 Class _Nonnull newClass);
285
286 void _objc_setClassCopyFixupHandler(void (* _Nonnull newFixupHandler)
287 (Class _Nonnull oldClass, Class _Nonnull newClass)) {
288 classCopyFixupHandler = newFixupHandler;
289 }
290
291 static Class
292 alloc_class_for_subclass(Class supercls, size_t extraBytes)
293 {
294 if (!supercls || !supercls->isAnySwift()) {
295 return _calloc_class(sizeof(objc_class) + extraBytes);
296 }
297
298 // Superclass is a Swift class. New subclass must duplicate its extra bits.
299
300 // Allocate the new class, with space for super's prefix and suffix
301 // and self's extraBytes.
302 swift_class_t *swiftSupercls = (swift_class_t *)supercls;
303 size_t superSize = swiftSupercls->classSize;
304 void *superBits = swiftSupercls->baseAddress();
305 void *bits = malloc(superSize + extraBytes);
306
307 // Copy all of the superclass's data to the new class.
308 memcpy(bits, superBits, superSize);
309
310 // Erase the objc data and the Swift description in the new class.
311 swift_class_t *swcls = (swift_class_t *)
312 ((uint8_t *)bits + swiftSupercls->classAddressOffset);
313 bzero(swcls, sizeof(objc_class));
314 swcls->description = nil;
315
316 if (classCopyFixupHandler) {
317 classCopyFixupHandler(supercls, (Class)swcls);
318 }
319
320 // Mark this class as Swift-enhanced.
321 if (supercls->isSwiftStable()) {
322 swcls->bits.setIsSwiftStable();
323 }
324 if (supercls->isSwiftLegacy()) {
325 swcls->bits.setIsSwiftLegacy();
326 }
327
328 return (Class)swcls;
329 }
330
331
332 /***********************************************************************
333 * object_getIndexedIvars.
334 **********************************************************************/
335 void *object_getIndexedIvars(id obj)
336 {
337 uint8_t *base = (uint8_t *)obj;
338
339 if (!obj) return nil;
340 if (obj->isTaggedPointer()) return nil;
341
342 if (!obj->isClass()) return base + obj->ISA()->alignedInstanceSize();
343
344 Class cls = (Class)obj;
345 if (!cls->isAnySwift()) return base + sizeof(objc_class);
346
347 swift_class_t *swcls = (swift_class_t *)cls;
348 return base - swcls->classAddressOffset + word_align(swcls->classSize);
349 }
350
351
352 /***********************************************************************
353 * make_ro_writeable
354 * Reallocates rw->ro if necessary to make it writeable.
355 * Locking: runtimeLock must be held by the caller.
356 **********************************************************************/
357 static class_ro_t *make_ro_writeable(class_rw_t *rw)
358 {
359 runtimeLock.assertLocked();
360
361 if (rw->flags & RW_COPIED_RO) {
362 // already writeable, do nothing
363 } else {
364 rw->ro = rw->ro->duplicate();
365 rw->flags |= RW_COPIED_RO;
366 }
367 return (class_ro_t *)rw->ro;
368 }
369
370
371 /***********************************************************************
372 * unattachedCategories
373 * Returns the class => categories map of unattached categories.
374 * Locking: runtimeLock must be held by the caller.
375 **********************************************************************/
376 static NXMapTable *unattachedCategories(void)
377 {
378 runtimeLock.assertLocked();
379
380 static NXMapTable *category_map = nil;
381
382 if (category_map) return category_map;
383
384 // fixme initial map size
385 category_map = NXCreateMapTable(NXPtrValueMapPrototype, 16);
386
387 return category_map;
388 }
389
390
391 /***********************************************************************
392 * dataSegmentsContain
393 * Returns true if the given address lies within a data segment in any
394 * loaded image.
395 *
396 * This is optimized for use where the return value is expected to be
397 * true. A call where the return value is false always results in a
398 * slow linear search of all loaded images. A call where the return
399 * value is fast will often be fast due to caching.
400 **********************************************************************/
401 static bool dataSegmentsContain(const void *ptr) {
402 struct Range {
403 uintptr_t start, end;
404 bool contains(uintptr_t ptr) {
405 return start <= ptr && ptr <= end;
406 }
407 };
408
409 // This is a really simple linear searched cache. On a cache hit,
410 // the hit entry is moved to the front of the array. On a cache
411 // miss where a range is successfully found on the slow path, the
412 // found range is inserted at the beginning of the cache. This gives
413 // us fast access to the most recently used elements, and LRU
414 // eviction.
415 enum { cacheCount = 16 };
416 static Range cache[cacheCount];
417
418 uintptr_t addr = (uintptr_t)ptr;
419
420 // Special case a hit on the first entry of the cache. No
421 // bookkeeping is required at all in this case.
422 if (cache[0].contains(addr)) {
423 return true;
424 }
425
426 // Search the rest of the cache.
427 for (unsigned i = 1; i < cacheCount; i++) {
428 if (cache[i].contains(addr)) {
429 // Cache hit. Move all preceding entries down one element,
430 // then place this entry at the front.
431 Range r = cache[i];
432 memmove(&cache[1], &cache[0], i * sizeof(cache[0]));
433 cache[0] = r;
434 return true;
435 }
436 }
437
438 // Cache miss. Find the image header containing the given address.
439 // If there isn't one, then we're definitely not in any image,
440 // so return false.
441 Range found = { 0, 0 };
442 auto *h = (headerType *)dyld_image_header_containing_address(ptr);
443 if (h == nullptr)
444 return false;
445
446 // Iterate over the data segments in the found image. If the address
447 // lies within one, note the data segment range in `found`.
448 // TODO: this is more work than we'd like to do. All we really need
449 // is the full range of the image. Addresses within the TEXT segment
450 // would also be acceptable for our use case. If possible, we should
451 // change this to work with the full address range of the found
452 // image header. Another possibility would be to use the range
453 // from `h` to the end of the page containing `addr`.
454 foreach_data_segment(h, [&](const segmentType *seg, intptr_t slide) {
455 Range r;
456 r.start = seg->vmaddr + slide;
457 r.end = r.start + seg->vmsize;
458 if (r.contains(addr))
459 found = r;
460 });
461
462 if (found.start != 0) {
463 memmove(&cache[1], &cache[0], (cacheCount - 1) * sizeof(cache[0]));
464 cache[0] = found;
465 return true;
466 }
467
468 return false;
469 }
470
471
472 /***********************************************************************
473 * isKnownClass
474 * Return true if the class is known to the runtime (located within the
475 * shared cache, within the data segment of a loaded image, or has been
476 * allocated with obj_allocateClassPair).
477 **********************************************************************/
478 static bool isKnownClass(Class cls) {
479 // The order of conditionals here is important for speed. We want to
480 // put the most common cases first, but also the fastest cases
481 // first. Checking the shared region is both fast and common.
482 // Checking allocatedClasses is fast, but may not be common,
483 // depending on what the program is doing. Checking if data segments
484 // contain the address is slow, so do it last.
485 return (sharedRegionContains(cls) ||
486 NXHashMember(allocatedClasses, cls) ||
487 dataSegmentsContain(cls));
488 }
489
490
491 /***********************************************************************
492 * addClassTableEntry
493 * Add a class to the table of all classes. If addMeta is true,
494 * automatically adds the metaclass of the class as well.
495 * Locking: runtimeLock must be held by the caller.
496 **********************************************************************/
497 static void addClassTableEntry(Class cls, bool addMeta = true) {
498 runtimeLock.assertLocked();
499
500 // This class is allowed to be a known class via the shared cache or via
501 // data segments, but it is not allowed to be in the dynamic table already.
502 assert(!NXHashMember(allocatedClasses, cls));
503
504 if (!isKnownClass(cls))
505 NXHashInsert(allocatedClasses, cls);
506 if (addMeta)
507 addClassTableEntry(cls->ISA(), false);
508 }
509
510
511 /***********************************************************************
512 * checkIsKnownClass
513 * Checks the given class against the list of all known classes. Dies
514 * with a fatal error if the class is not known.
515 * Locking: runtimeLock must be held by the caller.
516 **********************************************************************/
517 static void checkIsKnownClass(Class cls)
518 {
519 if (!isKnownClass(cls))
520 _objc_fatal("Attempt to use unknown class %p.", cls);
521 }
522
523
524 /***********************************************************************
525 * addUnattachedCategoryForClass
526 * Records an unattached category.
527 * Locking: runtimeLock must be held by the caller.
528 **********************************************************************/
529 static void addUnattachedCategoryForClass(category_t *cat, Class cls,
530 header_info *catHeader)
531 {
532 runtimeLock.assertLocked();
533
534 // DO NOT use cat->cls! cls may be cat->cls->isa instead
535 NXMapTable *cats = unattachedCategories();
536 category_list *list;
537
538 list = (category_list *)NXMapGet(cats, cls);
539 if (!list) {
540 list = (category_list *)
541 calloc(sizeof(*list) + sizeof(list->list[0]), 1);
542 } else {
543 list = (category_list *)
544 realloc(list, sizeof(*list) + sizeof(list->list[0]) * (list->count + 1));
545 }
546 list->list[list->count++] = (locstamped_category_t){cat, catHeader};
547 NXMapInsert(cats, cls, list);
548 }
549
550
551 /***********************************************************************
552 * removeUnattachedCategoryForClass
553 * Removes an unattached category.
554 * Locking: runtimeLock must be held by the caller.
555 **********************************************************************/
556 static void removeUnattachedCategoryForClass(category_t *cat, Class cls)
557 {
558 runtimeLock.assertLocked();
559
560 // DO NOT use cat->cls! cls may be cat->cls->isa instead
561 NXMapTable *cats = unattachedCategories();
562 category_list *list;
563
564 list = (category_list *)NXMapGet(cats, cls);
565 if (!list) return;
566
567 uint32_t i;
568 for (i = 0; i < list->count; i++) {
569 if (list->list[i].cat == cat) {
570 // shift entries to preserve list order
571 memmove(&list->list[i], &list->list[i+1],
572 (list->count-i-1) * sizeof(list->list[i]));
573 list->count--;
574 return;
575 }
576 }
577 }
578
579
580 /***********************************************************************
581 * unattachedCategoriesForClass
582 * Returns the list of unattached categories for a class, and
583 * deletes them from the list.
584 * The result must be freed by the caller.
585 * Locking: runtimeLock must be held by the caller.
586 **********************************************************************/
587 static category_list *
588 unattachedCategoriesForClass(Class cls, bool realizing)
589 {
590 runtimeLock.assertLocked();
591 return (category_list *)NXMapRemove(unattachedCategories(), cls);
592 }
593
594
595 /***********************************************************************
596 * removeAllUnattachedCategoriesForClass
597 * Deletes all unattached categories (loaded or not) for a class.
598 * Locking: runtimeLock must be held by the caller.
599 **********************************************************************/
600 static void removeAllUnattachedCategoriesForClass(Class cls)
601 {
602 runtimeLock.assertLocked();
603
604 void *list = NXMapRemove(unattachedCategories(), cls);
605 if (list) free(list);
606 }
607
608
609 /***********************************************************************
610 * classNSObject
611 * Returns class NSObject.
612 * Locking: none
613 **********************************************************************/
614 static Class classNSObject(void)
615 {
616 extern objc_class OBJC_CLASS_$_NSObject;
617 return (Class)&OBJC_CLASS_$_NSObject;
618 }
619
620
621 /***********************************************************************
622 * printReplacements
623 * Implementation of PrintReplacedMethods / OBJC_PRINT_REPLACED_METHODS.
624 * Warn about methods from cats that override other methods in cats or cls.
625 * Assumes no methods from cats have been added to cls yet.
626 **********************************************************************/
627 static void printReplacements(Class cls, category_list *cats)
628 {
629 uint32_t c;
630 bool isMeta = cls->isMetaClass();
631
632 if (!cats) return;
633
634 // Newest categories are LAST in cats
635 // Later categories override earlier ones.
636 for (c = 0; c < cats->count; c++) {
637 category_t *cat = cats->list[c].cat;
638
639 method_list_t *mlist = cat->methodsForMeta(isMeta);
640 if (!mlist) continue;
641
642 for (const auto& meth : *mlist) {
643 SEL s = sel_registerName(sel_cname(meth.name));
644
645 // Search for replaced methods in method lookup order.
646 // Complain about the first duplicate only.
647
648 // Look for method in earlier categories
649 for (uint32_t c2 = 0; c2 < c; c2++) {
650 category_t *cat2 = cats->list[c2].cat;
651
652 const method_list_t *mlist2 = cat2->methodsForMeta(isMeta);
653 if (!mlist2) continue;
654
655 for (const auto& meth2 : *mlist2) {
656 SEL s2 = sel_registerName(sel_cname(meth2.name));
657 if (s == s2) {
658 logReplacedMethod(cls->nameForLogging(), s,
659 cls->isMetaClass(), cat->name,
660 meth2.imp, meth.imp);
661 goto complained;
662 }
663 }
664 }
665
666 // Look for method in cls
667 for (const auto& meth2 : cls->data()->methods) {
668 SEL s2 = sel_registerName(sel_cname(meth2.name));
669 if (s == s2) {
670 logReplacedMethod(cls->nameForLogging(), s,
671 cls->isMetaClass(), cat->name,
672 meth2.imp, meth.imp);
673 goto complained;
674 }
675 }
676
677 complained:
678 ;
679 }
680 }
681 }
682
683
684 static bool isBundleClass(Class cls)
685 {
686 return cls->data()->ro->flags & RO_FROM_BUNDLE;
687 }
688
689
690 static void
691 fixupMethodList(method_list_t *mlist, bool bundleCopy, bool sort)
692 {
693 runtimeLock.assertLocked();
694 assert(!mlist->isFixedUp());
695
696 // fixme lock less in attachMethodLists ?
697 {
698 mutex_locker_t lock(selLock);
699
700 // Unique selectors in list.
701 for (auto& meth : *mlist) {
702 const char *name = sel_cname(meth.name);
703 meth.name = sel_registerNameNoLock(name, bundleCopy);
704 }
705 }
706
707 // Sort by selector address.
708 if (sort) {
709 method_t::SortBySELAddress sorter;
710 std::stable_sort(mlist->begin(), mlist->end(), sorter);
711 }
712
713 // Mark method list as uniqued and sorted
714 mlist->setFixedUp();
715 }
716
717
718 static void
719 prepareMethodLists(Class cls, method_list_t **addedLists, int addedCount,
720 bool baseMethods, bool methodsFromBundle)
721 {
722 runtimeLock.assertLocked();
723
724 if (addedCount == 0) return;
725
726 // Don't scan redundantly
727 bool scanForCustomRR = !cls->hasCustomRR();
728 bool scanForCustomAWZ = !cls->hasCustomAWZ();
729
730 // There exist RR/AWZ special cases for some class's base methods.
731 // But this code should never need to scan base methods for RR/AWZ:
732 // default RR/AWZ cannot be set before setInitialized().
733 // Therefore we need not handle any special cases here.
734 if (baseMethods) {
735 assert(!scanForCustomRR && !scanForCustomAWZ);
736 }
737
738 // Add method lists to array.
739 // Reallocate un-fixed method lists.
740 // The new methods are PREPENDED to the method list array.
741
742 for (int i = 0; i < addedCount; i++) {
743 method_list_t *mlist = addedLists[i];
744 assert(mlist);
745
746 // Fixup selectors if necessary
747 if (!mlist->isFixedUp()) {
748 fixupMethodList(mlist, methodsFromBundle, true/*sort*/);
749 }
750
751 // Scan for method implementations tracked by the class's flags
752 if (scanForCustomRR && methodListImplementsRR(mlist)) {
753 cls->setHasCustomRR();
754 scanForCustomRR = false;
755 }
756 if (scanForCustomAWZ && methodListImplementsAWZ(mlist)) {
757 cls->setHasCustomAWZ();
758 scanForCustomAWZ = false;
759 }
760 }
761 }
762
763
764 // Attach method lists and properties and protocols from categories to a class.
765 // Assumes the categories in cats are all loaded and sorted by load order,
766 // oldest categories first.
767 static void
768 attachCategories(Class cls, category_list *cats, bool flush_caches)
769 {
770 if (!cats) return;
771 if (PrintReplacedMethods) printReplacements(cls, cats);
772
773 bool isMeta = cls->isMetaClass();
774
775 // fixme rearrange to remove these intermediate allocations
776 method_list_t **mlists = (method_list_t **)
777 malloc(cats->count * sizeof(*mlists));
778 property_list_t **proplists = (property_list_t **)
779 malloc(cats->count * sizeof(*proplists));
780 protocol_list_t **protolists = (protocol_list_t **)
781 malloc(cats->count * sizeof(*protolists));
782
783 // Count backwards through cats to get newest categories first
784 int mcount = 0;
785 int propcount = 0;
786 int protocount = 0;
787 int i = cats->count;
788 bool fromBundle = NO;
789 while (i--) {
790 auto& entry = cats->list[i];
791
792 method_list_t *mlist = entry.cat->methodsForMeta(isMeta);
793 if (mlist) {
794 mlists[mcount++] = mlist;
795 fromBundle |= entry.hi->isBundle();
796 }
797
798 property_list_t *proplist =
799 entry.cat->propertiesForMeta(isMeta, entry.hi);
800 if (proplist) {
801 proplists[propcount++] = proplist;
802 }
803
804 protocol_list_t *protolist = entry.cat->protocols;
805 if (protolist) {
806 protolists[protocount++] = protolist;
807 }
808 }
809
810 auto rw = cls->data();
811
812 prepareMethodLists(cls, mlists, mcount, NO, fromBundle);
813 rw->methods.attachLists(mlists, mcount);
814 free(mlists);
815 if (flush_caches && mcount > 0) flushCaches(cls);
816
817 rw->properties.attachLists(proplists, propcount);
818 free(proplists);
819
820 rw->protocols.attachLists(protolists, protocount);
821 free(protolists);
822 }
823
824
825 /***********************************************************************
826 * methodizeClass
827 * Fixes up cls's method list, protocol list, and property list.
828 * Attaches any outstanding categories.
829 * Locking: runtimeLock must be held by the caller
830 **********************************************************************/
831 static void methodizeClass(Class cls)
832 {
833 runtimeLock.assertLocked();
834
835 bool isMeta = cls->isMetaClass();
836 auto rw = cls->data();
837 auto ro = rw->ro;
838
839 // Methodizing for the first time
840 if (PrintConnecting) {
841 _objc_inform("CLASS: methodizing class '%s' %s",
842 cls->nameForLogging(), isMeta ? "(meta)" : "");
843 }
844
845 // Install methods and properties that the class implements itself.
846 method_list_t *list = ro->baseMethods();
847 if (list) {
848 prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));
849 rw->methods.attachLists(&list, 1);
850 }
851
852 property_list_t *proplist = ro->baseProperties;
853 if (proplist) {
854 rw->properties.attachLists(&proplist, 1);
855 }
856
857 protocol_list_t *protolist = ro->baseProtocols;
858 if (protolist) {
859 rw->protocols.attachLists(&protolist, 1);
860 }
861
862 // Root classes get bonus method implementations if they don't have
863 // them already. These apply before category replacements.
864 if (cls->isRootMetaclass()) {
865 // root metaclass
866 addMethod(cls, SEL_initialize, (IMP)&objc_noop_imp, "", NO);
867 }
868
869 // Attach categories.
870 category_list *cats = unattachedCategoriesForClass(cls, true /*realizing*/);
871 attachCategories(cls, cats, false /*don't flush caches*/);
872
873 if (PrintConnecting) {
874 if (cats) {
875 for (uint32_t i = 0; i < cats->count; i++) {
876 _objc_inform("CLASS: attached category %c%s(%s)",
877 isMeta ? '+' : '-',
878 cls->nameForLogging(), cats->list[i].cat->name);
879 }
880 }
881 }
882
883 if (cats) free(cats);
884
885 #if DEBUG
886 // Debug: sanity-check all SELs; log method list contents
887 for (const auto& meth : rw->methods) {
888 if (PrintConnecting) {
889 _objc_inform("METHOD %c[%s %s]", isMeta ? '+' : '-',
890 cls->nameForLogging(), sel_getName(meth.name));
891 }
892 assert(sel_registerName(sel_getName(meth.name)) == meth.name);
893 }
894 #endif
895 }
896
897
898 /***********************************************************************
899 * remethodizeClass
900 * Attach outstanding categories to an existing class.
901 * Fixes up cls's method list, protocol list, and property list.
902 * Updates method caches for cls and its subclasses.
903 * Locking: runtimeLock must be held by the caller
904 **********************************************************************/
905 static void remethodizeClass(Class cls)
906 {
907 category_list *cats;
908 bool isMeta;
909
910 runtimeLock.assertLocked();
911
912 isMeta = cls->isMetaClass();
913
914 // Re-methodizing: check for more categories
915 if ((cats = unattachedCategoriesForClass(cls, false/*not realizing*/))) {
916 if (PrintConnecting) {
917 _objc_inform("CLASS: attaching categories to class '%s' %s",
918 cls->nameForLogging(), isMeta ? "(meta)" : "");
919 }
920
921 attachCategories(cls, cats, true /*flush caches*/);
922 free(cats);
923 }
924 }
925
926
927 /***********************************************************************
928 * nonMetaClasses
929 * Returns the secondary metaclass => class map
930 * Used for some cases of +initialize and +resolveClassMethod:.
931 * This map does not contain all class and metaclass pairs. It only
932 * contains metaclasses whose classes would be in the runtime-allocated
933 * named-class table, but are not because some other class with the same name
934 * is in that table.
935 * Classes with no duplicates are not included.
936 * Classes in the preoptimized named-class table are not included.
937 * Classes whose duplicates are in the preoptimized table are not included.
938 * Most code should use getMaybeUnrealizedNonMetaClass()
939 * instead of reading this table.
940 * Locking: runtimeLock must be read- or write-locked by the caller
941 **********************************************************************/
942 static NXMapTable *nonmeta_class_map = nil;
943 static NXMapTable *nonMetaClasses(void)
944 {
945 runtimeLock.assertLocked();
946
947 if (nonmeta_class_map) return nonmeta_class_map;
948
949 // nonmeta_class_map is typically small
950 INIT_ONCE_PTR(nonmeta_class_map,
951 NXCreateMapTable(NXPtrValueMapPrototype, 32),
952 NXFreeMapTable(v));
953
954 return nonmeta_class_map;
955 }
956
957
958 /***********************************************************************
959 * addNonMetaClass
960 * Adds metacls => cls to the secondary metaclass map
961 * Locking: runtimeLock must be held by the caller
962 **********************************************************************/
963 static void addNonMetaClass(Class cls)
964 {
965 runtimeLock.assertLocked();
966 void *old;
967 old = NXMapInsert(nonMetaClasses(), cls->ISA(), cls);
968
969 assert(!cls->isMetaClassMaybeUnrealized());
970 assert(cls->ISA()->isMetaClassMaybeUnrealized());
971 assert(!old);
972 }
973
974
975 static void removeNonMetaClass(Class cls)
976 {
977 runtimeLock.assertLocked();
978 NXMapRemove(nonMetaClasses(), cls->ISA());
979 }
980
981
982 static bool scanMangledField(const char *&string, const char *end,
983 const char *&field, int& length)
984 {
985 // Leading zero not allowed.
986 if (*string == '0') return false;
987
988 length = 0;
989 field = string;
990 while (field < end) {
991 char c = *field;
992 if (!isdigit(c)) break;
993 field++;
994 if (__builtin_smul_overflow(length, 10, &length)) return false;
995 if (__builtin_sadd_overflow(length, c - '0', &length)) return false;
996 }
997
998 string = field + length;
999 return length > 0 && string <= end;
1000 }
1001
1002
1003 /***********************************************************************
1004 * copySwiftV1DemangledName
1005 * Returns the pretty form of the given Swift-v1-mangled class or protocol name.
1006 * Returns nil if the string doesn't look like a mangled Swift v1 name.
1007 * The result must be freed with free().
1008 **********************************************************************/
1009 static char *copySwiftV1DemangledName(const char *string, bool isProtocol = false)
1010 {
1011 if (!string) return nil;
1012
1013 // Swift mangling prefix.
1014 if (strncmp(string, isProtocol ? "_TtP" : "_TtC", 4) != 0) return nil;
1015 string += 4;
1016
1017 const char *end = string + strlen(string);
1018
1019 // Module name.
1020 const char *prefix;
1021 int prefixLength;
1022 if (string[0] == 's') {
1023 // "s" is the Swift module.
1024 prefix = "Swift";
1025 prefixLength = 5;
1026 string += 1;
1027 } else {
1028 if (! scanMangledField(string, end, prefix, prefixLength)) return nil;
1029 }
1030
1031 // Class or protocol name.
1032 const char *suffix;
1033 int suffixLength;
1034 if (! scanMangledField(string, end, suffix, suffixLength)) return nil;
1035
1036 if (isProtocol) {
1037 // Remainder must be "_".
1038 if (strcmp(string, "_") != 0) return nil;
1039 } else {
1040 // Remainder must be empty.
1041 if (string != end) return nil;
1042 }
1043
1044 char *result;
1045 asprintf(&result, "%.*s.%.*s", prefixLength,prefix, suffixLength,suffix);
1046 return result;
1047 }
1048
1049
1050 /***********************************************************************
1051 * copySwiftV1MangledName
1052 * Returns the Swift 1.0 mangled form of the given class or protocol name.
1053 * Returns nil if the string doesn't look like an unmangled Swift name.
1054 * The result must be freed with free().
1055 **********************************************************************/
1056 static char *copySwiftV1MangledName(const char *string, bool isProtocol = false)
1057 {
1058 if (!string) return nil;
1059
1060 size_t dotCount = 0;
1061 size_t dotIndex;
1062 const char *s;
1063 for (s = string; *s; s++) {
1064 if (*s == '.') {
1065 dotCount++;
1066 dotIndex = s - string;
1067 }
1068 }
1069 size_t stringLength = s - string;
1070
1071 if (dotCount != 1 || dotIndex == 0 || dotIndex >= stringLength-1) {
1072 return nil;
1073 }
1074
1075 const char *prefix = string;
1076 size_t prefixLength = dotIndex;
1077 const char *suffix = string + dotIndex + 1;
1078 size_t suffixLength = stringLength - (dotIndex + 1);
1079
1080 char *name;
1081
1082 if (prefixLength == 5 && memcmp(prefix, "Swift", 5) == 0) {
1083 asprintf(&name, "_Tt%cs%zu%.*s%s",
1084 isProtocol ? 'P' : 'C',
1085 suffixLength, (int)suffixLength, suffix,
1086 isProtocol ? "_" : "");
1087 } else {
1088 asprintf(&name, "_Tt%c%zu%.*s%zu%.*s%s",
1089 isProtocol ? 'P' : 'C',
1090 prefixLength, (int)prefixLength, prefix,
1091 suffixLength, (int)suffixLength, suffix,
1092 isProtocol ? "_" : "");
1093 }
1094 return name;
1095 }
1096
1097
1098 /***********************************************************************
1099 * getClassExceptSomeSwift
1100 * Looks up a class by name. The class MIGHT NOT be realized.
1101 * Demangled Swift names are recognized.
1102 * Classes known to the Swift runtime but not yet used are NOT recognized.
1103 * (such as subclasses of un-instantiated generics)
1104 * Use look_up_class() to find them as well.
1105 * Locking: runtimeLock must be read- or write-locked by the caller.
1106 **********************************************************************/
1107
1108 // This is a misnomer: gdb_objc_realized_classes is actually a list of
1109 // named classes not in the dyld shared cache, whether realized or not.
1110 NXMapTable *gdb_objc_realized_classes; // exported for debuggers in objc-gdb.h
1111
1112 static Class getClass_impl(const char *name)
1113 {
1114 runtimeLock.assertLocked();
1115
1116 // allocated in _read_images
1117 assert(gdb_objc_realized_classes);
1118
1119 // Try runtime-allocated table
1120 Class result = (Class)NXMapGet(gdb_objc_realized_classes, name);
1121 if (result) return result;
1122
1123 // Try table from dyld shared cache
1124 return getPreoptimizedClass(name);
1125 }
1126
1127 static Class getClassExceptSomeSwift(const char *name)
1128 {
1129 runtimeLock.assertLocked();
1130
1131 // Try name as-is
1132 Class result = getClass_impl(name);
1133 if (result) return result;
1134
1135 // Try Swift-mangled equivalent of the given name.
1136 if (char *swName = copySwiftV1MangledName(name)) {
1137 result = getClass_impl(swName);
1138 free(swName);
1139 return result;
1140 }
1141
1142 return nil;
1143 }
1144
1145
1146 /***********************************************************************
1147 * addNamedClass
1148 * Adds name => cls to the named non-meta class map.
1149 * Warns about duplicate class names and keeps the old mapping.
1150 * Locking: runtimeLock must be held by the caller
1151 **********************************************************************/
1152 static void addNamedClass(Class cls, const char *name, Class replacing = nil)
1153 {
1154 runtimeLock.assertLocked();
1155 Class old;
1156 if ((old = getClassExceptSomeSwift(name)) && old != replacing) {
1157 inform_duplicate(name, old, cls);
1158
1159 // getMaybeUnrealizedNonMetaClass uses name lookups.
1160 // Classes not found by name lookup must be in the
1161 // secondary meta->nonmeta table.
1162 addNonMetaClass(cls);
1163 } else {
1164 NXMapInsert(gdb_objc_realized_classes, name, cls);
1165 }
1166 assert(!(cls->data()->flags & RO_META));
1167
1168 // wrong: constructed classes are already realized when they get here
1169 // assert(!cls->isRealized());
1170 }
1171
1172
1173 /***********************************************************************
1174 * removeNamedClass
1175 * Removes cls from the name => cls map.
1176 * Locking: runtimeLock must be held by the caller
1177 **********************************************************************/
1178 static void removeNamedClass(Class cls, const char *name)
1179 {
1180 runtimeLock.assertLocked();
1181 assert(!(cls->data()->flags & RO_META));
1182 if (cls == NXMapGet(gdb_objc_realized_classes, name)) {
1183 NXMapRemove(gdb_objc_realized_classes, name);
1184 } else {
1185 // cls has a name collision with another class - don't remove the other
1186 // but do remove cls from the secondary metaclass->class map.
1187 removeNonMetaClass(cls);
1188 }
1189 }
1190
1191
1192 /***********************************************************************
1193 * unreasonableClassCount
1194 * Provides an upper bound for any iteration of classes,
1195 * to prevent spins when runtime metadata is corrupted.
1196 **********************************************************************/
1197 unsigned unreasonableClassCount()
1198 {
1199 runtimeLock.assertLocked();
1200
1201 int base = NXCountMapTable(gdb_objc_realized_classes) +
1202 getPreoptimizedClassUnreasonableCount();
1203
1204 // Provide lots of slack here. Some iterations touch metaclasses too.
1205 // Some iterations backtrack (like realized class iteration).
1206 // We don't need an efficient bound, merely one that prevents spins.
1207 return (base + 1) * 16;
1208 }
1209
1210
1211 /***********************************************************************
1212 * futureNamedClasses
1213 * Returns the classname => future class map for unrealized future classes.
1214 * Locking: runtimeLock must be held by the caller
1215 **********************************************************************/
1216 static NXMapTable *future_named_class_map = nil;
1217 static NXMapTable *futureNamedClasses()
1218 {
1219 runtimeLock.assertLocked();
1220
1221 if (future_named_class_map) return future_named_class_map;
1222
1223 // future_named_class_map is big enough for CF's classes and a few others
1224 future_named_class_map =
1225 NXCreateMapTable(NXStrValueMapPrototype, 32);
1226
1227 return future_named_class_map;
1228 }
1229
1230
1231 static bool haveFutureNamedClasses() {
1232 return future_named_class_map && NXCountMapTable(future_named_class_map);
1233 }
1234
1235
1236 /***********************************************************************
1237 * addFutureNamedClass
1238 * Installs cls as the class structure to use for the named class if it appears.
1239 * Locking: runtimeLock must be held by the caller
1240 **********************************************************************/
1241 static void addFutureNamedClass(const char *name, Class cls)
1242 {
1243 void *old;
1244
1245 runtimeLock.assertLocked();
1246
1247 if (PrintFuture) {
1248 _objc_inform("FUTURE: reserving %p for %s", (void*)cls, name);
1249 }
1250
1251 class_rw_t *rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1);
1252 class_ro_t *ro = (class_ro_t *)calloc(sizeof(class_ro_t), 1);
1253 ro->name = strdupIfMutable(name);
1254 rw->ro = ro;
1255 cls->setData(rw);
1256 cls->data()->flags = RO_FUTURE;
1257
1258 old = NXMapKeyCopyingInsert(futureNamedClasses(), name, cls);
1259 assert(!old);
1260 }
1261
1262
1263 /***********************************************************************
1264 * popFutureNamedClass
1265 * Removes the named class from the unrealized future class list,
1266 * because it has been realized.
1267 * Returns nil if the name is not used by a future class.
1268 * Locking: runtimeLock must be held by the caller
1269 **********************************************************************/
1270 static Class popFutureNamedClass(const char *name)
1271 {
1272 runtimeLock.assertLocked();
1273
1274 Class cls = nil;
1275
1276 if (future_named_class_map) {
1277 cls = (Class)NXMapKeyFreeingRemove(future_named_class_map, name);
1278 if (cls && NXCountMapTable(future_named_class_map) == 0) {
1279 NXFreeMapTable(future_named_class_map);
1280 future_named_class_map = nil;
1281 }
1282 }
1283
1284 return cls;
1285 }
1286
1287
1288 /***********************************************************************
1289 * remappedClasses
1290 * Returns the oldClass => newClass map for realized future classes.
1291 * Returns the oldClass => nil map for ignored weak-linked classes.
1292 * Locking: runtimeLock must be read- or write-locked by the caller
1293 **********************************************************************/
1294 static NXMapTable *remappedClasses(bool create)
1295 {
1296 static NXMapTable *remapped_class_map = nil;
1297
1298 runtimeLock.assertLocked();
1299
1300 if (remapped_class_map) return remapped_class_map;
1301 if (!create) return nil;
1302
1303 // remapped_class_map is big enough to hold CF's classes and a few others
1304 INIT_ONCE_PTR(remapped_class_map,
1305 NXCreateMapTable(NXPtrValueMapPrototype, 32),
1306 NXFreeMapTable(v));
1307
1308 return remapped_class_map;
1309 }
1310
1311
1312 /***********************************************************************
1313 * noClassesRemapped
1314 * Returns YES if no classes have been remapped
1315 * Locking: runtimeLock must be read- or write-locked by the caller
1316 **********************************************************************/
1317 static bool noClassesRemapped(void)
1318 {
1319 runtimeLock.assertLocked();
1320
1321 bool result = (remappedClasses(NO) == nil);
1322 #if DEBUG
1323 // Catch construction of an empty table, which defeats optimization.
1324 NXMapTable *map = remappedClasses(NO);
1325 if (map) assert(NXCountMapTable(map) > 0);
1326 #endif
1327 return result;
1328 }
1329
1330
1331 /***********************************************************************
1332 * addRemappedClass
1333 * newcls is a realized future class, replacing oldcls.
1334 * OR newcls is nil, replacing ignored weak-linked class oldcls.
1335 * Locking: runtimeLock must be write-locked by the caller
1336 **********************************************************************/
1337 static void addRemappedClass(Class oldcls, Class newcls)
1338 {
1339 runtimeLock.assertLocked();
1340
1341 if (PrintFuture) {
1342 _objc_inform("FUTURE: using %p instead of %p for %s",
1343 (void*)newcls, (void*)oldcls, oldcls->nameForLogging());
1344 }
1345
1346 void *old;
1347 old = NXMapInsert(remappedClasses(YES), oldcls, newcls);
1348 assert(!old);
1349 }
1350
1351
1352 /***********************************************************************
1353 * remapClass
1354 * Returns the live class pointer for cls, which may be pointing to
1355 * a class struct that has been reallocated.
1356 * Returns nil if cls is ignored because of weak linking.
1357 * Locking: runtimeLock must be read- or write-locked by the caller
1358 **********************************************************************/
1359 static Class remapClass(Class cls)
1360 {
1361 runtimeLock.assertLocked();
1362
1363 Class c2;
1364
1365 if (!cls) return nil;
1366
1367 NXMapTable *map = remappedClasses(NO);
1368 if (!map || NXMapMember(map, cls, (void**)&c2) == NX_MAPNOTAKEY) {
1369 return cls;
1370 } else {
1371 return c2;
1372 }
1373 }
1374
1375 static Class remapClass(classref_t cls)
1376 {
1377 return remapClass((Class)cls);
1378 }
1379
1380 Class _class_remap(Class cls)
1381 {
1382 mutex_locker_t lock(runtimeLock);
1383 return remapClass(cls);
1384 }
1385
1386 /***********************************************************************
1387 * remapClassRef
1388 * Fix up a class ref, in case the class referenced has been reallocated
1389 * or is an ignored weak-linked class.
1390 * Locking: runtimeLock must be read- or write-locked by the caller
1391 **********************************************************************/
1392 static void remapClassRef(Class *clsref)
1393 {
1394 runtimeLock.assertLocked();
1395
1396 Class newcls = remapClass(*clsref);
1397 if (*clsref != newcls) *clsref = newcls;
1398 }
1399
1400
1401 /***********************************************************************
1402 * getMaybeUnrealizedNonMetaClass
1403 * Return the ordinary class for this class or metaclass.
1404 * `inst` is an instance of `cls` or a subclass thereof, or nil.
1405 * Non-nil inst is faster.
1406 * The result may be unrealized.
1407 * Used by +initialize.
1408 * Locking: runtimeLock must be read- or write-locked by the caller
1409 **********************************************************************/
1410 static Class getMaybeUnrealizedNonMetaClass(Class metacls, id inst)
1411 {
1412 static int total, named, secondary, sharedcache;
1413 runtimeLock.assertLocked();
1414 assert(metacls->isRealized());
1415
1416 total++;
1417
1418 // return cls itself if it's already a non-meta class
1419 if (!metacls->isMetaClass()) return metacls;
1420
1421 // metacls really is a metaclass
1422 // which means inst (if any) is a class
1423
1424 // special case for root metaclass
1425 // where inst == inst->ISA() == metacls is possible
1426 if (metacls->ISA() == metacls) {
1427 Class cls = metacls->superclass;
1428 assert(cls->isRealized());
1429 assert(!cls->isMetaClass());
1430 assert(cls->ISA() == metacls);
1431 if (cls->ISA() == metacls) return cls;
1432 }
1433
1434 // use inst if available
1435 if (inst) {
1436 Class cls = remapClass((Class)inst);
1437 // cls may be a subclass - find the real class for metacls
1438 // fixme this probably stops working once Swift starts
1439 // reallocating classes if cls is unrealized.
1440 while (cls) {
1441 if (cls->ISA() == metacls) {
1442 assert(!cls->isMetaClassMaybeUnrealized());
1443 return cls;
1444 }
1445 cls = cls->superclass;
1446 }
1447 #if DEBUG
1448 _objc_fatal("cls is not an instance of metacls");
1449 #else
1450 // release build: be forgiving and fall through to slow lookups
1451 #endif
1452 }
1453
1454 // try name lookup
1455 {
1456 Class cls = getClassExceptSomeSwift(metacls->mangledName());
1457 if (cls->ISA() == metacls) {
1458 named++;
1459 if (PrintInitializing) {
1460 _objc_inform("INITIALIZE: %d/%d (%g%%) "
1461 "successful by-name metaclass lookups",
1462 named, total, named*100.0/total);
1463 }
1464 return cls;
1465 }
1466 }
1467
1468 // try secondary table
1469 {
1470 Class cls = (Class)NXMapGet(nonMetaClasses(), metacls);
1471 if (cls) {
1472 secondary++;
1473 if (PrintInitializing) {
1474 _objc_inform("INITIALIZE: %d/%d (%g%%) "
1475 "successful secondary metaclass lookups",
1476 secondary, total, secondary*100.0/total);
1477 }
1478
1479 assert(cls->ISA() == metacls);
1480 return cls;
1481 }
1482 }
1483
1484 // try any duplicates in the dyld shared cache
1485 {
1486 Class cls = nil;
1487
1488 int count;
1489 Class *classes = copyPreoptimizedClasses(metacls->mangledName(),&count);
1490 if (classes) {
1491 for (int i = 0; i < count; i++) {
1492 if (classes[i]->ISA() == metacls) {
1493 cls = classes[i];
1494 break;
1495 }
1496 }
1497 free(classes);
1498 }
1499
1500 if (cls) {
1501 sharedcache++;
1502 if (PrintInitializing) {
1503 _objc_inform("INITIALIZE: %d/%d (%g%%) "
1504 "successful shared cache metaclass lookups",
1505 sharedcache, total, sharedcache*100.0/total);
1506 }
1507
1508 return cls;
1509 }
1510 }
1511
1512 _objc_fatal("no class for metaclass %p", (void*)metacls);
1513 }
1514
1515
1516 /***********************************************************************
1517 * class_initialize. Send the '+initialize' message on demand to any
1518 * uninitialized class. Force initialization of superclasses first.
1519 * inst is an instance of cls, or nil. Non-nil is better for performance.
1520 * Returns the class pointer. If the class was unrealized then
1521 * it may be reallocated.
1522 * Locking:
1523 * runtimeLock must be held by the caller
1524 * This function may drop the lock.
1525 * On exit the lock is re-acquired or dropped as requested by leaveLocked.
1526 **********************************************************************/
1527 static Class initializeAndMaybeRelock(Class cls, id inst,
1528 mutex_t& lock, bool leaveLocked)
1529 {
1530 lock.assertLocked();
1531 assert(cls->isRealized());
1532
1533 if (cls->isInitialized()) {
1534 if (!leaveLocked) lock.unlock();
1535 return cls;
1536 }
1537
1538 // Find the non-meta class for cls, if it is not already one.
1539 // The +initialize message is sent to the non-meta class object.
1540 Class nonmeta = getMaybeUnrealizedNonMetaClass(cls, inst);
1541
1542 // Realize the non-meta class if necessary.
1543 if (nonmeta->isRealized()) {
1544 // nonmeta is cls, which was already realized
1545 // OR nonmeta is distinct, but is already realized
1546 // - nothing else to do
1547 lock.unlock();
1548 } else {
1549 nonmeta = realizeClassMaybeSwiftAndUnlock(nonmeta, lock);
1550 // runtimeLock is now unlocked
1551 // fixme Swift can't relocate the class today,
1552 // but someday it will:
1553 cls = object_getClass(nonmeta);
1554 }
1555
1556 // runtimeLock is now unlocked, for +initialize dispatch
1557 assert(nonmeta->isRealized());
1558 initializeNonMetaClass(nonmeta);
1559
1560 if (leaveLocked) runtimeLock.lock();
1561 return cls;
1562 }
1563
1564 // Locking: acquires runtimeLock
1565 Class class_initialize(Class cls, id obj)
1566 {
1567 runtimeLock.lock();
1568 return initializeAndMaybeRelock(cls, obj, runtimeLock, false);
1569 }
1570
1571 // Locking: caller must hold runtimeLock; this may drop and re-acquire it
1572 static Class initializeAndLeaveLocked(Class cls, id obj, mutex_t& lock)
1573 {
1574 return initializeAndMaybeRelock(cls, obj, lock, true);
1575 }
1576
1577
1578 /***********************************************************************
1579 * addRootClass
1580 * Adds cls as a new realized root class.
1581 * Locking: runtimeLock must be held by the caller.
1582 **********************************************************************/
1583 static Class _firstRealizedClass = nil;
1584 Class firstRealizedClass()
1585 {
1586 runtimeLock.assertLocked();
1587 return _firstRealizedClass;
1588 }
1589
1590 static void addRootClass(Class cls)
1591 {
1592 runtimeLock.assertLocked();
1593
1594 assert(cls->isRealized());
1595 cls->data()->nextSiblingClass = _firstRealizedClass;
1596 _firstRealizedClass = cls;
1597 }
1598
1599 static void removeRootClass(Class cls)
1600 {
1601 runtimeLock.assertLocked();
1602
1603 Class *classp;
1604 for (classp = &_firstRealizedClass;
1605 *classp != cls;
1606 classp = &(*classp)->data()->nextSiblingClass)
1607 { }
1608
1609 *classp = (*classp)->data()->nextSiblingClass;
1610 }
1611
1612
1613 /***********************************************************************
1614 * addSubclass
1615 * Adds subcls as a subclass of supercls.
1616 * Locking: runtimeLock must be held by the caller.
1617 **********************************************************************/
1618 static void addSubclass(Class supercls, Class subcls)
1619 {
1620 runtimeLock.assertLocked();
1621
1622 if (supercls && subcls) {
1623 assert(supercls->isRealized());
1624 assert(subcls->isRealized());
1625 subcls->data()->nextSiblingClass = supercls->data()->firstSubclass;
1626 supercls->data()->firstSubclass = subcls;
1627
1628 if (supercls->hasCxxCtor()) {
1629 subcls->setHasCxxCtor();
1630 }
1631
1632 if (supercls->hasCxxDtor()) {
1633 subcls->setHasCxxDtor();
1634 }
1635
1636 if (supercls->hasCustomRR()) {
1637 subcls->setHasCustomRR(true);
1638 }
1639
1640 if (supercls->hasCustomAWZ()) {
1641 subcls->setHasCustomAWZ(true);
1642 }
1643
1644 // Special case: instancesRequireRawIsa does not propagate
1645 // from root class to root metaclass
1646 if (supercls->instancesRequireRawIsa() && supercls->superclass) {
1647 subcls->setInstancesRequireRawIsa(true);
1648 }
1649 }
1650 }
1651
1652
1653 /***********************************************************************
1654 * removeSubclass
1655 * Removes subcls as a subclass of supercls.
1656 * Locking: runtimeLock must be held by the caller.
1657 **********************************************************************/
1658 static void removeSubclass(Class supercls, Class subcls)
1659 {
1660 runtimeLock.assertLocked();
1661 assert(supercls->isRealized());
1662 assert(subcls->isRealized());
1663 assert(subcls->superclass == supercls);
1664
1665 Class *cp;
1666 for (cp = &supercls->data()->firstSubclass;
1667 *cp && *cp != subcls;
1668 cp = &(*cp)->data()->nextSiblingClass)
1669 ;
1670 assert(*cp == subcls);
1671 *cp = subcls->data()->nextSiblingClass;
1672 }
1673
1674
1675
1676 /***********************************************************************
1677 * protocols
1678 * Returns the protocol name => protocol map for protocols.
1679 * Locking: runtimeLock must read- or write-locked by the caller
1680 **********************************************************************/
1681 static NXMapTable *protocols(void)
1682 {
1683 static NXMapTable *protocol_map = nil;
1684
1685 runtimeLock.assertLocked();
1686
1687 INIT_ONCE_PTR(protocol_map,
1688 NXCreateMapTable(NXStrValueMapPrototype, 16),
1689 NXFreeMapTable(v) );
1690
1691 return protocol_map;
1692 }
1693
1694
1695 /***********************************************************************
1696 * getProtocol
1697 * Looks up a protocol by name. Demangled Swift names are recognized.
1698 * Locking: runtimeLock must be read- or write-locked by the caller.
1699 **********************************************************************/
1700 static Protocol *getProtocol(const char *name)
1701 {
1702 runtimeLock.assertLocked();
1703
1704 // Try name as-is.
1705 Protocol *result = (Protocol *)NXMapGet(protocols(), name);
1706 if (result) return result;
1707
1708 // Try Swift-mangled equivalent of the given name.
1709 if (char *swName = copySwiftV1MangledName(name, true/*isProtocol*/)) {
1710 result = (Protocol *)NXMapGet(protocols(), swName);
1711 free(swName);
1712 return result;
1713 }
1714
1715 return nil;
1716 }
1717
1718
1719 /***********************************************************************
1720 * remapProtocol
1721 * Returns the live protocol pointer for proto, which may be pointing to
1722 * a protocol struct that has been reallocated.
1723 * Locking: runtimeLock must be read- or write-locked by the caller
1724 **********************************************************************/
1725 static protocol_t *remapProtocol(protocol_ref_t proto)
1726 {
1727 runtimeLock.assertLocked();
1728
1729 protocol_t *newproto = (protocol_t *)
1730 getProtocol(((protocol_t *)proto)->mangledName);
1731 return newproto ? newproto : (protocol_t *)proto;
1732 }
1733
1734
1735 /***********************************************************************
1736 * remapProtocolRef
1737 * Fix up a protocol ref, in case the protocol referenced has been reallocated.
1738 * Locking: runtimeLock must be read- or write-locked by the caller
1739 **********************************************************************/
1740 static size_t UnfixedProtocolReferences;
1741 static void remapProtocolRef(protocol_t **protoref)
1742 {
1743 runtimeLock.assertLocked();
1744
1745 protocol_t *newproto = remapProtocol((protocol_ref_t)*protoref);
1746 if (*protoref != newproto) {
1747 *protoref = newproto;
1748 UnfixedProtocolReferences++;
1749 }
1750 }
1751
1752
1753 /***********************************************************************
1754 * moveIvars
1755 * Slides a class's ivars to accommodate the given superclass size.
1756 * Ivars are NOT compacted to compensate for a superclass that shrunk.
1757 * Locking: runtimeLock must be held by the caller.
1758 **********************************************************************/
1759 static void moveIvars(class_ro_t *ro, uint32_t superSize)
1760 {
1761 runtimeLock.assertLocked();
1762
1763 uint32_t diff;
1764
1765 assert(superSize > ro->instanceStart);
1766 diff = superSize - ro->instanceStart;
1767
1768 if (ro->ivars) {
1769 // Find maximum alignment in this class's ivars
1770 uint32_t maxAlignment = 1;
1771 for (const auto& ivar : *ro->ivars) {
1772 if (!ivar.offset) continue; // anonymous bitfield
1773
1774 uint32_t alignment = ivar.alignment();
1775 if (alignment > maxAlignment) maxAlignment = alignment;
1776 }
1777
1778 // Compute a slide value that preserves that alignment
1779 uint32_t alignMask = maxAlignment - 1;
1780 diff = (diff + alignMask) & ~alignMask;
1781
1782 // Slide all of this class's ivars en masse
1783 for (const auto& ivar : *ro->ivars) {
1784 if (!ivar.offset) continue; // anonymous bitfield
1785
1786 uint32_t oldOffset = (uint32_t)*ivar.offset;
1787 uint32_t newOffset = oldOffset + diff;
1788 *ivar.offset = newOffset;
1789
1790 if (PrintIvars) {
1791 _objc_inform("IVARS: offset %u -> %u for %s "
1792 "(size %u, align %u)",
1793 oldOffset, newOffset, ivar.name,
1794 ivar.size, ivar.alignment());
1795 }
1796 }
1797 }
1798
1799 *(uint32_t *)&ro->instanceStart += diff;
1800 *(uint32_t *)&ro->instanceSize += diff;
1801 }
1802
1803
1804 static void reconcileInstanceVariables(Class cls, Class supercls, const class_ro_t*& ro)
1805 {
1806 class_rw_t *rw = cls->data();
1807
1808 assert(supercls);
1809 assert(!cls->isMetaClass());
1810
1811 /* debug: print them all before sliding
1812 if (ro->ivars) {
1813 for (const auto& ivar : *ro->ivars) {
1814 if (!ivar.offset) continue; // anonymous bitfield
1815
1816 _objc_inform("IVARS: %s.%s (offset %u, size %u, align %u)",
1817 ro->name, ivar.name,
1818 *ivar.offset, ivar.size, ivar.alignment());
1819 }
1820 }
1821 */
1822
1823 // Non-fragile ivars - reconcile this class with its superclass
1824 const class_ro_t *super_ro = supercls->data()->ro;
1825
1826 if (DebugNonFragileIvars) {
1827 // Debugging: Force non-fragile ivars to slide.
1828 // Intended to find compiler, runtime, and program bugs.
1829 // If it fails with this and works without, you have a problem.
1830
1831 // Operation: Reset everything to 0 + misalignment.
1832 // Then force the normal sliding logic to push everything back.
1833
1834 // Exceptions: root classes, metaclasses, *NSCF* classes,
1835 // __CF* classes, NSConstantString, NSSimpleCString
1836
1837 // (already know it's not root because supercls != nil)
1838 const char *clsname = cls->mangledName();
1839 if (!strstr(clsname, "NSCF") &&
1840 0 != strncmp(clsname, "__CF", 4) &&
1841 0 != strcmp(clsname, "NSConstantString") &&
1842 0 != strcmp(clsname, "NSSimpleCString"))
1843 {
1844 uint32_t oldStart = ro->instanceStart;
1845 class_ro_t *ro_w = make_ro_writeable(rw);
1846 ro = rw->ro;
1847
1848 // Find max ivar alignment in class.
1849 // default to word size to simplify ivar update
1850 uint32_t alignment = 1<<WORD_SHIFT;
1851 if (ro->ivars) {
1852 for (const auto& ivar : *ro->ivars) {
1853 if (ivar.alignment() > alignment) {
1854 alignment = ivar.alignment();
1855 }
1856 }
1857 }
1858 uint32_t misalignment = ro->instanceStart % alignment;
1859 uint32_t delta = ro->instanceStart - misalignment;
1860 ro_w->instanceStart = misalignment;
1861 ro_w->instanceSize -= delta;
1862
1863 if (PrintIvars) {
1864 _objc_inform("IVARS: DEBUG: forcing ivars for class '%s' "
1865 "to slide (instanceStart %zu -> %zu)",
1866 cls->nameForLogging(), (size_t)oldStart,
1867 (size_t)ro->instanceStart);
1868 }
1869
1870 if (ro->ivars) {
1871 for (const auto& ivar : *ro->ivars) {
1872 if (!ivar.offset) continue; // anonymous bitfield
1873 *ivar.offset -= delta;
1874 }
1875 }
1876 }
1877 }
1878
1879 if (ro->instanceStart >= super_ro->instanceSize) {
1880 // Superclass has not overgrown its space. We're done here.
1881 return;
1882 }
1883 // fixme can optimize for "class has no new ivars", etc
1884
1885 if (ro->instanceStart < super_ro->instanceSize) {
1886 // Superclass has changed size. This class's ivars must move.
1887 // Also slide layout bits in parallel.
1888 // This code is incapable of compacting the subclass to
1889 // compensate for a superclass that shrunk, so don't do that.
1890 if (PrintIvars) {
1891 _objc_inform("IVARS: sliding ivars for class %s "
1892 "(superclass was %u bytes, now %u)",
1893 cls->nameForLogging(), ro->instanceStart,
1894 super_ro->instanceSize);
1895 }
1896 class_ro_t *ro_w = make_ro_writeable(rw);
1897 ro = rw->ro;
1898 moveIvars(ro_w, super_ro->instanceSize);
1899 gdb_objc_class_changed(cls, OBJC_CLASS_IVARS_CHANGED, ro->name);
1900 }
1901 }
1902
1903
1904 /***********************************************************************
1905 * realizeClassWithoutSwift
1906 * Performs first-time initialization on class cls,
1907 * including allocating its read-write data.
1908 * Does not perform any Swift-side initialization.
1909 * Returns the real class structure for the class.
1910 * Locking: runtimeLock must be write-locked by the caller
1911 **********************************************************************/
1912 static Class realizeClassWithoutSwift(Class cls)
1913 {
1914 runtimeLock.assertLocked();
1915
1916 const class_ro_t *ro;
1917 class_rw_t *rw;
1918 Class supercls;
1919 Class metacls;
1920 bool isMeta;
1921
1922 if (!cls) return nil;
1923 if (cls->isRealized()) return cls;
1924 assert(cls == remapClass(cls));
1925
1926 // fixme verify class is not in an un-dlopened part of the shared cache?
1927
1928 ro = (const class_ro_t *)cls->data();
1929 if (ro->flags & RO_FUTURE) {
1930 // This was a future class. rw data is already allocated.
1931 rw = cls->data();
1932 ro = cls->data()->ro;
1933 cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
1934 } else {
1935 // Normal class. Allocate writeable class data.
1936 rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1);
1937 rw->ro = ro;
1938 rw->flags = RW_REALIZED|RW_REALIZING;
1939 cls->setData(rw);
1940 }
1941
1942 isMeta = ro->flags & RO_META;
1943
1944 rw->version = isMeta ? 7 : 0; // old runtime went up to 6
1945
1946
1947 // Choose an index for this class.
1948 // Sets cls->instancesRequireRawIsa if indexes no more indexes are available
1949 cls->chooseClassArrayIndex();
1950
1951 if (PrintConnecting) {
1952 _objc_inform("CLASS: realizing class '%s'%s %p %p #%u %s%s",
1953 cls->nameForLogging(), isMeta ? " (meta)" : "",
1954 (void*)cls, ro, cls->classArrayIndex(),
1955 cls->isSwiftStable() ? "(swift)" : "",
1956 cls->isSwiftLegacy() ? "(pre-stable swift)" : "");
1957 }
1958
1959 // Realize superclass and metaclass, if they aren't already.
1960 // This needs to be done after RW_REALIZED is set above, for root classes.
1961 // This needs to be done after class index is chosen, for root metaclasses.
1962 // This assumes that none of those classes have Swift contents,
1963 // or that Swift's initializers have already been called.
1964 // fixme that assumption will be wrong if we add support
1965 // for ObjC subclasses of Swift classes.
1966 supercls = realizeClassWithoutSwift(remapClass(cls->superclass));
1967 metacls = realizeClassWithoutSwift(remapClass(cls->ISA()));
1968
1969 #if SUPPORT_NONPOINTER_ISA
1970 // Disable non-pointer isa for some classes and/or platforms.
1971 // Set instancesRequireRawIsa.
1972 bool instancesRequireRawIsa = cls->instancesRequireRawIsa();
1973 bool rawIsaIsInherited = false;
1974 static bool hackedDispatch = false;
1975
1976 if (DisableNonpointerIsa) {
1977 // Non-pointer isa disabled by environment or app SDK version
1978 instancesRequireRawIsa = true;
1979 }
1980 else if (!hackedDispatch && !(ro->flags & RO_META) &&
1981 0 == strcmp(ro->name, "OS_object"))
1982 {
1983 // hack for libdispatch et al - isa also acts as vtable pointer
1984 hackedDispatch = true;
1985 instancesRequireRawIsa = true;
1986 }
1987 else if (supercls && supercls->superclass &&
1988 supercls->instancesRequireRawIsa())
1989 {
1990 // This is also propagated by addSubclass()
1991 // but nonpointer isa setup needs it earlier.
1992 // Special case: instancesRequireRawIsa does not propagate
1993 // from root class to root metaclass
1994 instancesRequireRawIsa = true;
1995 rawIsaIsInherited = true;
1996 }
1997
1998 if (instancesRequireRawIsa) {
1999 cls->setInstancesRequireRawIsa(rawIsaIsInherited);
2000 }
2001 // SUPPORT_NONPOINTER_ISA
2002 #endif
2003
2004 // Update superclass and metaclass in case of remapping
2005 cls->superclass = supercls;
2006 cls->initClassIsa(metacls);
2007
2008 // Reconcile instance variable offsets / layout.
2009 // This may reallocate class_ro_t, updating our ro variable.
2010 if (supercls && !isMeta) reconcileInstanceVariables(cls, supercls, ro);
2011
2012 // Set fastInstanceSize if it wasn't set already.
2013 cls->setInstanceSize(ro->instanceSize);
2014
2015 // Copy some flags from ro to rw
2016 if (ro->flags & RO_HAS_CXX_STRUCTORS) {
2017 cls->setHasCxxDtor();
2018 if (! (ro->flags & RO_HAS_CXX_DTOR_ONLY)) {
2019 cls->setHasCxxCtor();
2020 }
2021 }
2022
2023 // Propagate the associated objects forbidden flag from ro or from
2024 // the superclass.
2025 if ((ro->flags & RO_FORBIDS_ASSOCIATED_OBJECTS) ||
2026 (supercls && supercls->forbidsAssociatedObjects()))
2027 {
2028 rw->flags |= RW_FORBIDS_ASSOCIATED_OBJECTS;
2029 }
2030
2031 // Connect this class to its superclass's subclass lists
2032 if (supercls) {
2033 addSubclass(supercls, cls);
2034 } else {
2035 addRootClass(cls);
2036 }
2037
2038 // Attach categories
2039 methodizeClass(cls);
2040
2041 return cls;
2042 }
2043
2044
2045 /***********************************************************************
2046 * _objc_realizeClassFromSwift
2047 * Called by Swift when it needs the ObjC part of a class to be realized.
2048 * There are four cases:
2049 * 1. cls != nil; previously == cls
2050 * Class cls is being realized in place
2051 * 2. cls != nil; previously == nil
2052 * Class cls is being constructed at runtime
2053 * 3. cls != nil; previously != cls
2054 * The class that was at previously has been reallocated to cls
2055 * 4. cls == nil, previously != nil
2056 * The class at previously is hereby disavowed
2057 *
2058 * Only variants #1 and #2 are supported today.
2059 *
2060 * Locking: acquires runtimeLock
2061 **********************************************************************/
2062 Class _objc_realizeClassFromSwift(Class cls, void *previously)
2063 {
2064 if (cls) {
2065 if (previously && previously != (void*)cls) {
2066 // #3: relocation
2067 // In the future this will mean remapping the old address
2068 // to the new class, and installing dispatch forwarding
2069 // machinery at the old address
2070 _objc_fatal("Swift requested that class %p be reallocated, "
2071 "but libobjc does not support that.", previously);
2072 } else {
2073 // #1 and #2: realization in place, or new class
2074 mutex_locker_t lock(runtimeLock);
2075
2076 if (!previously) {
2077 // #2: new class
2078 cls = readClass(cls, false/*bundle*/, false/*shared cache*/);
2079 }
2080
2081 // #1 and #2: realization in place, or new class
2082 // We ignore the Swift metadata initializer callback.
2083 // We assume that's all handled since we're being called from Swift.
2084 return realizeClassWithoutSwift(cls);
2085 }
2086 }
2087 else {
2088 // #4: disavowal
2089 // In the future this will mean remapping the old address to nil
2090 // and if necessary removing the old address from any other tables.
2091 _objc_fatal("Swift requested that class %p be ignored, "
2092 "but libobjc does not support that.", previously);
2093 }
2094 }
2095
2096 /***********************************************************************
2097 * realizeSwiftClass
2098 * Performs first-time initialization on class cls,
2099 * including allocating its read-write data,
2100 * and any Swift-side initialization.
2101 * Returns the real class structure for the class.
2102 * Locking: acquires runtimeLock indirectly
2103 **********************************************************************/
2104 static Class realizeSwiftClass(Class cls)
2105 {
2106 runtimeLock.assertUnlocked();
2107
2108 // Some assumptions:
2109 // * Metaclasses never have a Swift initializer.
2110 // * Root classes never have a Swift initializer.
2111 // (These two together avoid initialization order problems at the root.)
2112 // * Unrealized non-Swift classes have no Swift ancestry.
2113 // * Unrealized Swift classes with no initializer have no ancestry that
2114 // does have the initializer.
2115 // (These two together mean we don't need to scan superclasses here
2116 // and we don't need to worry about Swift superclasses inside
2117 // realizeClassWithoutSwift()).
2118
2119 // fixme some of these assumptions will be wrong
2120 // if we add support for ObjC sublasses of Swift classes.
2121
2122 #if DEBUG
2123 runtimeLock.lock();
2124 assert(remapClass(cls) == cls);
2125 assert(cls->isSwiftStable_ButAllowLegacyForNow());
2126 assert(!cls->isMetaClassMaybeUnrealized());
2127 assert(cls->superclass);
2128 runtimeLock.unlock();
2129 #endif
2130
2131 // Look for a Swift metadata initialization function
2132 // installed on the class. If it is present we call it.
2133 // That function in turn initializes the Swift metadata,
2134 // prepares the "compiler-generated" ObjC metadata if not
2135 // already present, and calls _objc_realizeSwiftClass() to finish
2136 // our own initialization.
2137
2138 if (auto init = cls->swiftMetadataInitializer()) {
2139 if (PrintConnecting) {
2140 _objc_inform("CLASS: calling Swift metadata initializer "
2141 "for class '%s' (%p)", cls->nameForLogging(), cls);
2142 }
2143
2144 Class newcls = init(cls, nil);
2145
2146 // fixme someday Swift will need to relocate classes at this point,
2147 // but we don't accept that yet.
2148 if (cls != newcls) {
2149 _objc_fatal("Swift metadata initializer moved a class "
2150 "from %p to %p, but libobjc does not yet allow that.",
2151 cls, newcls);
2152 }
2153
2154 return newcls;
2155 }
2156 else {
2157 // No Swift-side initialization callback.
2158 // Perform our own realization directly.
2159 mutex_locker_t lock(runtimeLock);
2160 return realizeClassWithoutSwift(cls);
2161 }
2162 }
2163
2164
2165 /***********************************************************************
2166 * realizeClassMaybeSwift (MaybeRelock / AndUnlock / AndLeaveLocked)
2167 * Realize a class that might be a Swift class.
2168 * Returns the real class structure for the class.
2169 * Locking:
2170 * runtimeLock must be held on entry
2171 * runtimeLock may be dropped during execution
2172 * ...AndUnlock function leaves runtimeLock unlocked on exit
2173 * ...AndLeaveLocked re-acquires runtimeLock if it was dropped
2174 * This complication avoids repeated lock transitions in some cases.
2175 **********************************************************************/
2176 static Class
2177 realizeClassMaybeSwiftMaybeRelock(Class cls, mutex_t& lock, bool leaveLocked)
2178 {
2179 lock.assertLocked();
2180
2181 if (!cls->isSwiftStable_ButAllowLegacyForNow()) {
2182 // Non-Swift class. Realize it now with the lock still held.
2183 // fixme wrong in the future for objc subclasses of swift classes
2184 realizeClassWithoutSwift(cls);
2185 if (!leaveLocked) lock.unlock();
2186 } else {
2187 // Swift class. We need to drop locks and call the Swift
2188 // runtime to initialize it.
2189 lock.unlock();
2190 cls = realizeSwiftClass(cls);
2191 assert(cls->isRealized()); // callback must have provoked realization
2192 if (leaveLocked) lock.lock();
2193 }
2194
2195 return cls;
2196 }
2197
2198 static Class
2199 realizeClassMaybeSwiftAndUnlock(Class cls, mutex_t& lock)
2200 {
2201 return realizeClassMaybeSwiftMaybeRelock(cls, lock, false);
2202 }
2203
2204 static Class
2205 realizeClassMaybeSwiftAndLeaveLocked(Class cls, mutex_t& lock)
2206 {
2207 return realizeClassMaybeSwiftMaybeRelock(cls, lock, true);
2208 }
2209
2210
2211 /***********************************************************************
2212 * missingWeakSuperclass
2213 * Return YES if some superclass of cls was weak-linked and is missing.
2214 **********************************************************************/
2215 static bool
2216 missingWeakSuperclass(Class cls)
2217 {
2218 assert(!cls->isRealized());
2219
2220 if (!cls->superclass) {
2221 // superclass nil. This is normal for root classes only.
2222 return (!(cls->data()->flags & RO_ROOT));
2223 } else {
2224 // superclass not nil. Check if a higher superclass is missing.
2225 Class supercls = remapClass(cls->superclass);
2226 assert(cls != cls->superclass);
2227 assert(cls != supercls);
2228 if (!supercls) return YES;
2229 if (supercls->isRealized()) return NO;
2230 return missingWeakSuperclass(supercls);
2231 }
2232 }
2233
2234
2235 /***********************************************************************
2236 * realizeAllClassesInImage
2237 * Non-lazily realizes all unrealized classes in the given image.
2238 * Locking: runtimeLock must be held by the caller.
2239 * Locking: this function may drop and re-acquire the lock.
2240 **********************************************************************/
2241 static void realizeAllClassesInImage(header_info *hi)
2242 {
2243 runtimeLock.assertLocked();
2244
2245 size_t count, i;
2246 classref_t *classlist;
2247
2248 if (hi->areAllClassesRealized()) return;
2249
2250 classlist = _getObjc2ClassList(hi, &count);
2251
2252 for (i = 0; i < count; i++) {
2253 Class cls = remapClass(classlist[i]);
2254 if (cls) {
2255 realizeClassMaybeSwiftAndLeaveLocked(cls, runtimeLock);
2256 }
2257 }
2258
2259 hi->setAllClassesRealized(YES);
2260 }
2261
2262
2263 /***********************************************************************
2264 * realizeAllClasses
2265 * Non-lazily realizes all unrealized classes in all known images.
2266 * Locking: runtimeLock must be held by the caller.
2267 * Locking: this function may drop and re-acquire the lock.
2268 * Dropping the lock makes this function thread-unsafe with respect
2269 * to concurrent image unload, but the callers of this function
2270 * already ultimately do something that is also thread-unsafe with
2271 * respect to image unload (such as using the list of all classes).
2272 **********************************************************************/
2273 static void realizeAllClasses(void)
2274 {
2275 runtimeLock.assertLocked();
2276
2277 header_info *hi;
2278 for (hi = FirstHeader; hi; hi = hi->getNext()) {
2279 realizeAllClassesInImage(hi); // may drop and re-acquire runtimeLock
2280 }
2281 }
2282
2283
2284 /***********************************************************************
2285 * _objc_allocateFutureClass
2286 * Allocate an unresolved future class for the given class name.
2287 * Returns any existing allocation if one was already made.
2288 * Assumes the named class doesn't exist yet.
2289 * Locking: acquires runtimeLock
2290 **********************************************************************/
2291 Class _objc_allocateFutureClass(const char *name)
2292 {
2293 mutex_locker_t lock(runtimeLock);
2294
2295 Class cls;
2296 NXMapTable *map = futureNamedClasses();
2297
2298 if ((cls = (Class)NXMapGet(map, name))) {
2299 // Already have a future class for this name.
2300 return cls;
2301 }
2302
2303 cls = _calloc_class(sizeof(objc_class));
2304 addFutureNamedClass(name, cls);
2305
2306 return cls;
2307 }
2308
2309
2310 /***********************************************************************
2311 * objc_getFutureClass. Return the id of the named class.
2312 * If the class does not exist, return an uninitialized class
2313 * structure that will be used for the class when and if it
2314 * does get loaded.
2315 * Not thread safe.
2316 **********************************************************************/
2317 Class objc_getFutureClass(const char *name)
2318 {
2319 Class cls;
2320
2321 // YES unconnected, NO class handler
2322 // (unconnected is OK because it will someday be the real class)
2323 cls = look_up_class(name, YES, NO);
2324 if (cls) {
2325 if (PrintFuture) {
2326 _objc_inform("FUTURE: found %p already in use for %s",
2327 (void*)cls, name);
2328 }
2329
2330 return cls;
2331 }
2332
2333 // No class or future class with that name yet. Make one.
2334 // fixme not thread-safe with respect to
2335 // simultaneous library load or getFutureClass.
2336 return _objc_allocateFutureClass(name);
2337 }
2338
2339
2340 BOOL _class_isFutureClass(Class cls)
2341 {
2342 return cls && cls->isFuture();
2343 }
2344
2345
2346 /***********************************************************************
2347 * _objc_flush_caches
2348 * Flushes all caches.
2349 * (Historical behavior: flush caches for cls, its metaclass,
2350 * and subclasses thereof. Nil flushes all classes.)
2351 * Locking: acquires runtimeLock
2352 **********************************************************************/
2353 static void flushCaches(Class cls)
2354 {
2355 runtimeLock.assertLocked();
2356
2357 mutex_locker_t lock(cacheUpdateLock);
2358
2359 if (cls) {
2360 foreach_realized_class_and_subclass(cls, ^(Class c){
2361 cache_erase_nolock(c);
2362 });
2363 }
2364 else {
2365 foreach_realized_class_and_metaclass(^(Class c){
2366 cache_erase_nolock(c);
2367 });
2368 }
2369 }
2370
2371
2372 void _objc_flush_caches(Class cls)
2373 {
2374 {
2375 mutex_locker_t lock(runtimeLock);
2376 flushCaches(cls);
2377 if (cls && cls->superclass && cls != cls->getIsa()) {
2378 flushCaches(cls->getIsa());
2379 } else {
2380 // cls is a root class or root metaclass. Its metaclass is itself
2381 // or a subclass so the metaclass caches were already flushed.
2382 }
2383 }
2384
2385 if (!cls) {
2386 // collectALot if cls==nil
2387 mutex_locker_t lock(cacheUpdateLock);
2388 cache_collect(true);
2389 }
2390 }
2391
2392
2393 /***********************************************************************
2394 * map_images
2395 * Process the given images which are being mapped in by dyld.
2396 * Calls ABI-agnostic code after taking ABI-specific locks.
2397 *
2398 * Locking: write-locks runtimeLock
2399 **********************************************************************/
2400 void
2401 map_images(unsigned count, const char * const paths[],
2402 const struct mach_header * const mhdrs[])
2403 {
2404 mutex_locker_t lock(runtimeLock);
2405 return map_images_nolock(count, paths, mhdrs);
2406 }
2407
2408
2409 /***********************************************************************
2410 * load_images
2411 * Process +load in the given images which are being mapped in by dyld.
2412 *
2413 * Locking: write-locks runtimeLock and loadMethodLock
2414 **********************************************************************/
2415 extern bool hasLoadMethods(const headerType *mhdr);
2416 extern void prepare_load_methods(const headerType *mhdr);
2417
2418 void
2419 load_images(const char *path __unused, const struct mach_header *mh)
2420 {
2421 // Return without taking locks if there are no +load methods here.
2422 if (!hasLoadMethods((const headerType *)mh)) return;
2423
2424 recursive_mutex_locker_t lock(loadMethodLock);
2425
2426 // Discover load methods
2427 {
2428 mutex_locker_t lock2(runtimeLock);
2429 prepare_load_methods((const headerType *)mh);
2430 }
2431
2432 // Call +load methods (without runtimeLock - re-entrant)
2433 call_load_methods();
2434 }
2435
2436
2437 /***********************************************************************
2438 * unmap_image
2439 * Process the given image which is about to be unmapped by dyld.
2440 *
2441 * Locking: write-locks runtimeLock and loadMethodLock
2442 **********************************************************************/
2443 void
2444 unmap_image(const char *path __unused, const struct mach_header *mh)
2445 {
2446 recursive_mutex_locker_t lock(loadMethodLock);
2447 mutex_locker_t lock2(runtimeLock);
2448 unmap_image_nolock(mh);
2449 }
2450
2451
2452
2453
2454 /***********************************************************************
2455 * mustReadClasses
2456 * Preflight check in advance of readClass() from an image.
2457 **********************************************************************/
2458 bool mustReadClasses(header_info *hi)
2459 {
2460 const char *reason;
2461
2462 // If the image is not preoptimized then we must read classes.
2463 if (!hi->isPreoptimized()) {
2464 reason = nil; // Don't log this one because it is noisy.
2465 goto readthem;
2466 }
2467
2468 // If iOS simulator then we must read classes.
2469 #if TARGET_OS_SIMULATOR
2470 reason = "the image is for iOS simulator";
2471 goto readthem;
2472 #endif
2473
2474 assert(!hi->isBundle()); // no MH_BUNDLE in shared cache
2475
2476 // If the image may have missing weak superclasses then we must read classes
2477 if (!noMissingWeakSuperclasses()) {
2478 reason = "the image may contain classes with missing weak superclasses";
2479 goto readthem;
2480 }
2481
2482 // If there are unresolved future classes then we must read classes.
2483 if (haveFutureNamedClasses()) {
2484 reason = "there are unresolved future classes pending";
2485 goto readthem;
2486 }
2487
2488 // readClass() rewrites bits in backward-deploying Swift stable ABI code.
2489 // The assumption here is there there are no such classes
2490 // in the dyld shared cache.
2491 #if DEBUG
2492 {
2493 size_t count;
2494 classref_t *classlist = _getObjc2ClassList(hi, &count);
2495 for (size_t i = 0; i < count; i++) {
2496 Class cls = remapClass(classlist[i]);
2497 assert(!cls->isUnfixedBackwardDeployingStableSwift());
2498 }
2499 }
2500 #endif
2501
2502 // readClass() does not need to do anything.
2503 return NO;
2504
2505 readthem:
2506 if (PrintPreopt && reason) {
2507 _objc_inform("PREOPTIMIZATION: reading classes manually from %s "
2508 "because %s", hi->fname(), reason);
2509 }
2510 return YES;
2511 }
2512
2513
2514 /***********************************************************************
2515 * readClass
2516 * Read a class and metaclass as written by a compiler.
2517 * Returns the new class pointer. This could be:
2518 * - cls
2519 * - nil (cls has a missing weak-linked superclass)
2520 * - something else (space for this class was reserved by a future class)
2521 *
2522 * Note that all work performed by this function is preflighted by
2523 * mustReadClasses(). Do not change this function without updating that one.
2524 *
2525 * Locking: runtimeLock acquired by map_images or objc_readClassPair
2526 **********************************************************************/
2527 Class readClass(Class cls, bool headerIsBundle, bool headerIsPreoptimized)
2528 {
2529 const char *mangledName = cls->mangledName();
2530
2531 if (missingWeakSuperclass(cls)) {
2532 // No superclass (probably weak-linked).
2533 // Disavow any knowledge of this subclass.
2534 if (PrintConnecting) {
2535 _objc_inform("CLASS: IGNORING class '%s' with "
2536 "missing weak-linked superclass",
2537 cls->nameForLogging());
2538 }
2539 addRemappedClass(cls, nil);
2540 cls->superclass = nil;
2541 return nil;
2542 }
2543
2544 // Note: Class __ARCLite__'s hack does not go through here.
2545 // Class structure fixups that apply to it also need to be
2546 // performed in non-lazy realization below.
2547
2548 // These fields should be set to zero because of the
2549 // binding of _objc_empty_vtable, but OS X 10.8's dyld
2550 // does not bind shared cache absolute symbols as expected.
2551 // This (and the __ARCLite__ hack below) can be removed
2552 // once the simulator drops 10.8 support.
2553 #if TARGET_OS_SIMULATOR
2554 if (cls->cache._mask) cls->cache._mask = 0;
2555 if (cls->cache._occupied) cls->cache._occupied = 0;
2556 if (cls->ISA()->cache._mask) cls->ISA()->cache._mask = 0;
2557 if (cls->ISA()->cache._occupied) cls->ISA()->cache._occupied = 0;
2558 #endif
2559
2560 cls->fixupBackwardDeployingStableSwift();
2561
2562 Class replacing = nil;
2563 if (Class newCls = popFutureNamedClass(mangledName)) {
2564 // This name was previously allocated as a future class.
2565 // Copy objc_class to future class's struct.
2566 // Preserve future's rw data block.
2567
2568 if (newCls->isAnySwift()) {
2569 _objc_fatal("Can't complete future class request for '%s' "
2570 "because the real class is too big.",
2571 cls->nameForLogging());
2572 }
2573
2574 class_rw_t *rw = newCls->data();
2575 const class_ro_t *old_ro = rw->ro;
2576 memcpy(newCls, cls, sizeof(objc_class));
2577 rw->ro = (class_ro_t *)newCls->data();
2578 newCls->setData(rw);
2579 freeIfMutable((char *)old_ro->name);
2580 free((void *)old_ro);
2581
2582 addRemappedClass(cls, newCls);
2583
2584 replacing = cls;
2585 cls = newCls;
2586 }
2587
2588 if (headerIsPreoptimized && !replacing) {
2589 // class list built in shared cache
2590 // fixme strict assert doesn't work because of duplicates
2591 // assert(cls == getClass(name));
2592 assert(getClassExceptSomeSwift(mangledName));
2593 } else {
2594 addNamedClass(cls, mangledName, replacing);
2595 addClassTableEntry(cls);
2596 }
2597
2598 // for future reference: shared cache never contains MH_BUNDLEs
2599 if (headerIsBundle) {
2600 cls->data()->flags |= RO_FROM_BUNDLE;
2601 cls->ISA()->data()->flags |= RO_FROM_BUNDLE;
2602 }
2603
2604 return cls;
2605 }
2606
2607
2608 /***********************************************************************
2609 * readProtocol
2610 * Read a protocol as written by a compiler.
2611 **********************************************************************/
2612 static void
2613 readProtocol(protocol_t *newproto, Class protocol_class,
2614 NXMapTable *protocol_map,
2615 bool headerIsPreoptimized, bool headerIsBundle)
2616 {
2617 // This is not enough to make protocols in unloaded bundles safe,
2618 // but it does prevent crashes when looking up unrelated protocols.
2619 auto insertFn = headerIsBundle ? NXMapKeyCopyingInsert : NXMapInsert;
2620
2621 protocol_t *oldproto = (protocol_t *)getProtocol(newproto->mangledName);
2622
2623 if (oldproto) {
2624 // Some other definition already won.
2625 if (PrintProtocols) {
2626 _objc_inform("PROTOCOLS: protocol at %p is %s "
2627 "(duplicate of %p)",
2628 newproto, oldproto->nameForLogging(), oldproto);
2629 }
2630 }
2631 else if (headerIsPreoptimized) {
2632 // Shared cache initialized the protocol object itself,
2633 // but in order to allow out-of-cache replacement we need
2634 // to add it to the protocol table now.
2635
2636 protocol_t *cacheproto = (protocol_t *)
2637 getPreoptimizedProtocol(newproto->mangledName);
2638 protocol_t *installedproto;
2639 if (cacheproto && cacheproto != newproto) {
2640 // Another definition in the shared cache wins (because
2641 // everything in the cache was fixed up to point to it).
2642 installedproto = cacheproto;
2643 }
2644 else {
2645 // This definition wins.
2646 installedproto = newproto;
2647 }
2648
2649 assert(installedproto->getIsa() == protocol_class);
2650 assert(installedproto->size >= sizeof(protocol_t));
2651 insertFn(protocol_map, installedproto->mangledName,
2652 installedproto);
2653
2654 if (PrintProtocols) {
2655 _objc_inform("PROTOCOLS: protocol at %p is %s",
2656 installedproto, installedproto->nameForLogging());
2657 if (newproto != installedproto) {
2658 _objc_inform("PROTOCOLS: protocol at %p is %s "
2659 "(duplicate of %p)",
2660 newproto, installedproto->nameForLogging(),
2661 installedproto);
2662 }
2663 }
2664 }
2665 else if (newproto->size >= sizeof(protocol_t)) {
2666 // New protocol from an un-preoptimized image
2667 // with sufficient storage. Fix it up in place.
2668 // fixme duplicate protocols from unloadable bundle
2669 newproto->initIsa(protocol_class); // fixme pinned
2670 insertFn(protocol_map, newproto->mangledName, newproto);
2671 if (PrintProtocols) {
2672 _objc_inform("PROTOCOLS: protocol at %p is %s",
2673 newproto, newproto->nameForLogging());
2674 }
2675 }
2676 else {
2677 // New protocol from an un-preoptimized image
2678 // with insufficient storage. Reallocate it.
2679 // fixme duplicate protocols from unloadable bundle
2680 size_t size = max(sizeof(protocol_t), (size_t)newproto->size);
2681 protocol_t *installedproto = (protocol_t *)calloc(size, 1);
2682 memcpy(installedproto, newproto, newproto->size);
2683 installedproto->size = (typeof(installedproto->size))size;
2684
2685 installedproto->initIsa(protocol_class); // fixme pinned
2686 insertFn(protocol_map, installedproto->mangledName, installedproto);
2687 if (PrintProtocols) {
2688 _objc_inform("PROTOCOLS: protocol at %p is %s ",
2689 installedproto, installedproto->nameForLogging());
2690 _objc_inform("PROTOCOLS: protocol at %p is %s "
2691 "(reallocated to %p)",
2692 newproto, installedproto->nameForLogging(),
2693 installedproto);
2694 }
2695 }
2696 }
2697
2698 /***********************************************************************
2699 * _read_images
2700 * Perform initial processing of the headers in the linked
2701 * list beginning with headerList.
2702 *
2703 * Called by: map_images_nolock
2704 *
2705 * Locking: runtimeLock acquired by map_images
2706 **********************************************************************/
2707 void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClasses)
2708 {
2709 header_info *hi;
2710 uint32_t hIndex;
2711 size_t count;
2712 size_t i;
2713 Class *resolvedFutureClasses = nil;
2714 size_t resolvedFutureClassCount = 0;
2715 static bool doneOnce;
2716 TimeLogger ts(PrintImageTimes);
2717
2718 runtimeLock.assertLocked();
2719
2720 #define EACH_HEADER \
2721 hIndex = 0; \
2722 hIndex < hCount && (hi = hList[hIndex]); \
2723 hIndex++
2724
2725 if (!doneOnce) {
2726 doneOnce = YES;
2727
2728 #if SUPPORT_NONPOINTER_ISA
2729 // Disable non-pointer isa under some conditions.
2730
2731 # if SUPPORT_INDEXED_ISA
2732 // Disable nonpointer isa if any image contains old Swift code
2733 for (EACH_HEADER) {
2734 if (hi->info()->containsSwift() &&
2735 hi->info()->swiftUnstableVersion() < objc_image_info::SwiftVersion3)
2736 {
2737 DisableNonpointerIsa = true;
2738 if (PrintRawIsa) {
2739 _objc_inform("RAW ISA: disabling non-pointer isa because "
2740 "the app or a framework contains Swift code "
2741 "older than Swift 3.0");
2742 }
2743 break;
2744 }
2745 }
2746 # endif
2747
2748 # if TARGET_OS_OSX
2749 // Disable non-pointer isa if the app is too old
2750 // (linked before OS X 10.11)
2751 if (dyld_get_program_sdk_version() < DYLD_MACOSX_VERSION_10_11) {
2752 DisableNonpointerIsa = true;
2753 if (PrintRawIsa) {
2754 _objc_inform("RAW ISA: disabling non-pointer isa because "
2755 "the app is too old (SDK version " SDK_FORMAT ")",
2756 FORMAT_SDK(dyld_get_program_sdk_version()));
2757 }
2758 }
2759
2760 // Disable non-pointer isa if the app has a __DATA,__objc_rawisa section
2761 // New apps that load old extensions may need this.
2762 for (EACH_HEADER) {
2763 if (hi->mhdr()->filetype != MH_EXECUTE) continue;
2764 unsigned long size;
2765 if (getsectiondata(hi->mhdr(), "__DATA", "__objc_rawisa", &size)) {
2766 DisableNonpointerIsa = true;
2767 if (PrintRawIsa) {
2768 _objc_inform("RAW ISA: disabling non-pointer isa because "
2769 "the app has a __DATA,__objc_rawisa section");
2770 }
2771 }
2772 break; // assume only one MH_EXECUTE image
2773 }
2774 # endif
2775
2776 #endif
2777
2778 if (DisableTaggedPointers) {
2779 disableTaggedPointers();
2780 }
2781
2782 initializeTaggedPointerObfuscator();
2783
2784 if (PrintConnecting) {
2785 _objc_inform("CLASS: found %d classes during launch", totalClasses);
2786 }
2787
2788 // namedClasses
2789 // Preoptimized classes don't go in this table.
2790 // 4/3 is NXMapTable's load factor
2791 int namedClassesSize =
2792 (isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
2793 gdb_objc_realized_classes =
2794 NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
2795
2796 allocatedClasses = NXCreateHashTable(NXPtrPrototype, 0, nil);
2797
2798 ts.log("IMAGE TIMES: first time tasks");
2799 }
2800
2801
2802 // Discover classes. Fix up unresolved future classes. Mark bundle classes.
2803
2804 for (EACH_HEADER) {
2805 classref_t *classlist = _getObjc2ClassList(hi, &count);
2806
2807 if (! mustReadClasses(hi)) {
2808 // Image is sufficiently optimized that we need not call readClass()
2809 continue;
2810 }
2811
2812 bool headerIsBundle = hi->isBundle();
2813 bool headerIsPreoptimized = hi->isPreoptimized();
2814
2815 for (i = 0; i < count; i++) {
2816 Class cls = (Class)classlist[i];
2817 Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
2818
2819 if (newCls != cls && newCls) {
2820 // Class was moved but not deleted. Currently this occurs
2821 // only when the new class resolved a future class.
2822 // Non-lazily realize the class below.
2823 resolvedFutureClasses = (Class *)
2824 realloc(resolvedFutureClasses,
2825 (resolvedFutureClassCount+1) * sizeof(Class));
2826 resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
2827 }
2828 }
2829 }
2830
2831 ts.log("IMAGE TIMES: discover classes");
2832
2833 // Fix up remapped classes
2834 // Class list and nonlazy class list remain unremapped.
2835 // Class refs and super refs are remapped for message dispatching.
2836
2837 if (!noClassesRemapped()) {
2838 for (EACH_HEADER) {
2839 Class *classrefs = _getObjc2ClassRefs(hi, &count);
2840 for (i = 0; i < count; i++) {
2841 remapClassRef(&classrefs[i]);
2842 }
2843 // fixme why doesn't test future1 catch the absence of this?
2844 classrefs = _getObjc2SuperRefs(hi, &count);
2845 for (i = 0; i < count; i++) {
2846 remapClassRef(&classrefs[i]);
2847 }
2848 }
2849 }
2850
2851 ts.log("IMAGE TIMES: remap classes");
2852
2853 // Fix up @selector references
2854 static size_t UnfixedSelectors;
2855 {
2856 mutex_locker_t lock(selLock);
2857 for (EACH_HEADER) {
2858 if (hi->isPreoptimized()) continue;
2859
2860 bool isBundle = hi->isBundle();
2861 SEL *sels = _getObjc2SelectorRefs(hi, &count);
2862 UnfixedSelectors += count;
2863 for (i = 0; i < count; i++) {
2864 const char *name = sel_cname(sels[i]);
2865 sels[i] = sel_registerNameNoLock(name, isBundle);
2866 }
2867 }
2868 }
2869
2870 ts.log("IMAGE TIMES: fix up selector references");
2871
2872 #if SUPPORT_FIXUP
2873 // Fix up old objc_msgSend_fixup call sites
2874 for (EACH_HEADER) {
2875 message_ref_t *refs = _getObjc2MessageRefs(hi, &count);
2876 if (count == 0) continue;
2877
2878 if (PrintVtables) {
2879 _objc_inform("VTABLES: repairing %zu unsupported vtable dispatch "
2880 "call sites in %s", count, hi->fname());
2881 }
2882 for (i = 0; i < count; i++) {
2883 fixupMessageRef(refs+i);
2884 }
2885 }
2886
2887 ts.log("IMAGE TIMES: fix up objc_msgSend_fixup");
2888 #endif
2889
2890 // Discover protocols. Fix up protocol refs.
2891 for (EACH_HEADER) {
2892 extern objc_class OBJC_CLASS_$_Protocol;
2893 Class cls = (Class)&OBJC_CLASS_$_Protocol;
2894 assert(cls);
2895 NXMapTable *protocol_map = protocols();
2896 bool isPreoptimized = hi->isPreoptimized();
2897 bool isBundle = hi->isBundle();
2898
2899 protocol_t **protolist = _getObjc2ProtocolList(hi, &count);
2900 for (i = 0; i < count; i++) {
2901 readProtocol(protolist[i], cls, protocol_map,
2902 isPreoptimized, isBundle);
2903 }
2904 }
2905
2906 ts.log("IMAGE TIMES: discover protocols");
2907
2908 // Fix up @protocol references
2909 // Preoptimized images may have the right
2910 // answer already but we don't know for sure.
2911 for (EACH_HEADER) {
2912 protocol_t **protolist = _getObjc2ProtocolRefs(hi, &count);
2913 for (i = 0; i < count; i++) {
2914 remapProtocolRef(&protolist[i]);
2915 }
2916 }
2917
2918 ts.log("IMAGE TIMES: fix up @protocol references");
2919
2920 // Realize non-lazy classes (for +load methods and static instances)
2921 for (EACH_HEADER) {
2922 classref_t *classlist =
2923 _getObjc2NonlazyClassList(hi, &count);
2924 for (i = 0; i < count; i++) {
2925 Class cls = remapClass(classlist[i]);
2926 if (!cls) continue;
2927
2928 // hack for class __ARCLite__, which didn't get this above
2929 #if TARGET_OS_SIMULATOR
2930 if (cls->cache._buckets == (void*)&_objc_empty_cache &&
2931 (cls->cache._mask || cls->cache._occupied))
2932 {
2933 cls->cache._mask = 0;
2934 cls->cache._occupied = 0;
2935 }
2936 if (cls->ISA()->cache._buckets == (void*)&_objc_empty_cache &&
2937 (cls->ISA()->cache._mask || cls->ISA()->cache._occupied))
2938 {
2939 cls->ISA()->cache._mask = 0;
2940 cls->ISA()->cache._occupied = 0;
2941 }
2942 #endif
2943
2944 addClassTableEntry(cls);
2945
2946 if (cls->isSwiftStable()) {
2947 if (cls->swiftMetadataInitializer()) {
2948 _objc_fatal("Swift class %s with a metadata initializer "
2949 "is not allowed to be non-lazy",
2950 cls->nameForLogging());
2951 }
2952 // fixme also disallow relocatable classes
2953 // We can't disallow all Swift classes because of
2954 // classes like Swift.__EmptyArrayStorage
2955 }
2956 realizeClassWithoutSwift(cls);
2957 }
2958 }
2959
2960 ts.log("IMAGE TIMES: realize non-lazy classes");
2961
2962 // Realize newly-resolved future classes, in case CF manipulates them
2963 if (resolvedFutureClasses) {
2964 for (i = 0; i < resolvedFutureClassCount; i++) {
2965 Class cls = resolvedFutureClasses[i];
2966 if (cls->isSwiftStable()) {
2967 _objc_fatal("Swift class is not allowed to be future");
2968 }
2969 realizeClassWithoutSwift(cls);
2970 cls->setInstancesRequireRawIsa(false/*inherited*/);
2971 }
2972 free(resolvedFutureClasses);
2973 }
2974
2975 ts.log("IMAGE TIMES: realize future classes");
2976
2977 // Discover categories.
2978 for (EACH_HEADER) {
2979 category_t **catlist =
2980 _getObjc2CategoryList(hi, &count);
2981 bool hasClassProperties = hi->info()->hasCategoryClassProperties();
2982
2983 for (i = 0; i < count; i++) {
2984 category_t *cat = catlist[i];
2985 Class cls = remapClass(cat->cls);
2986
2987 if (!cls) {
2988 // Category's target class is missing (probably weak-linked).
2989 // Disavow any knowledge of this category.
2990 catlist[i] = nil;
2991 if (PrintConnecting) {
2992 _objc_inform("CLASS: IGNORING category \?\?\?(%s) %p with "
2993 "missing weak-linked target class",
2994 cat->name, cat);
2995 }
2996 continue;
2997 }
2998
2999 // Process this category.
3000 // First, register the category with its target class.
3001 // Then, rebuild the class's method lists (etc) if
3002 // the class is realized.
3003 bool classExists = NO;
3004 if (cat->instanceMethods || cat->protocols
3005 || cat->instanceProperties)
3006 {
3007 addUnattachedCategoryForClass(cat, cls, hi);
3008 if (cls->isRealized()) {
3009 remethodizeClass(cls);
3010 classExists = YES;
3011 }
3012 if (PrintConnecting) {
3013 _objc_inform("CLASS: found category -%s(%s) %s",
3014 cls->nameForLogging(), cat->name,
3015 classExists ? "on existing class" : "");
3016 }
3017 }
3018
3019 if (cat->classMethods || cat->protocols
3020 || (hasClassProperties && cat->_classProperties))
3021 {
3022 addUnattachedCategoryForClass(cat, cls->ISA(), hi);
3023 if (cls->ISA()->isRealized()) {
3024 remethodizeClass(cls->ISA());
3025 }
3026 if (PrintConnecting) {
3027 _objc_inform("CLASS: found category +%s(%s)",
3028 cls->nameForLogging(), cat->name);
3029 }
3030 }
3031 }
3032 }
3033
3034 ts.log("IMAGE TIMES: discover categories");
3035
3036 // Category discovery MUST BE LAST to avoid potential races
3037 // when other threads call the new category code before
3038 // this thread finishes its fixups.
3039
3040 // +load handled by prepare_load_methods()
3041
3042 if (DebugNonFragileIvars) {
3043 realizeAllClasses();
3044 }
3045
3046
3047 // Print preoptimization statistics
3048 if (PrintPreopt) {
3049 static unsigned int PreoptTotalMethodLists;
3050 static unsigned int PreoptOptimizedMethodLists;
3051 static unsigned int PreoptTotalClasses;
3052 static unsigned int PreoptOptimizedClasses;
3053
3054 for (EACH_HEADER) {
3055 if (hi->isPreoptimized()) {
3056 _objc_inform("PREOPTIMIZATION: honoring preoptimized selectors "
3057 "in %s", hi->fname());
3058 }
3059 else if (hi->info()->optimizedByDyld()) {
3060 _objc_inform("PREOPTIMIZATION: IGNORING preoptimized selectors "
3061 "in %s", hi->fname());
3062 }
3063
3064 classref_t *classlist = _getObjc2ClassList(hi, &count);
3065 for (i = 0; i < count; i++) {
3066 Class cls = remapClass(classlist[i]);
3067 if (!cls) continue;
3068
3069 PreoptTotalClasses++;
3070 if (hi->isPreoptimized()) {
3071 PreoptOptimizedClasses++;
3072 }
3073
3074 const method_list_t *mlist;
3075 if ((mlist = ((class_ro_t *)cls->data())->baseMethods())) {
3076 PreoptTotalMethodLists++;
3077 if (mlist->isFixedUp()) {
3078 PreoptOptimizedMethodLists++;
3079 }
3080 }
3081 if ((mlist=((class_ro_t *)cls->ISA()->data())->baseMethods())) {
3082 PreoptTotalMethodLists++;
3083 if (mlist->isFixedUp()) {
3084 PreoptOptimizedMethodLists++;
3085 }
3086 }
3087 }
3088 }
3089
3090 _objc_inform("PREOPTIMIZATION: %zu selector references not "
3091 "pre-optimized", UnfixedSelectors);
3092 _objc_inform("PREOPTIMIZATION: %u/%u (%.3g%%) method lists pre-sorted",
3093 PreoptOptimizedMethodLists, PreoptTotalMethodLists,
3094 PreoptTotalMethodLists
3095 ? 100.0*PreoptOptimizedMethodLists/PreoptTotalMethodLists
3096 : 0.0);
3097 _objc_inform("PREOPTIMIZATION: %u/%u (%.3g%%) classes pre-registered",
3098 PreoptOptimizedClasses, PreoptTotalClasses,
3099 PreoptTotalClasses
3100 ? 100.0*PreoptOptimizedClasses/PreoptTotalClasses
3101 : 0.0);
3102 _objc_inform("PREOPTIMIZATION: %zu protocol references not "
3103 "pre-optimized", UnfixedProtocolReferences);
3104 }
3105
3106 #undef EACH_HEADER
3107 }
3108
3109
3110 /***********************************************************************
3111 * prepare_load_methods
3112 * Schedule +load for classes in this image, any un-+load-ed
3113 * superclasses in other images, and any categories in this image.
3114 **********************************************************************/
3115 // Recursively schedule +load for cls and any un-+load-ed superclasses.
3116 // cls must already be connected.
3117 static void schedule_class_load(Class cls)
3118 {
3119 if (!cls) return;
3120 assert(cls->isRealized()); // _read_images should realize
3121
3122 if (cls->data()->flags & RW_LOADED) return;
3123
3124 // Ensure superclass-first ordering
3125 schedule_class_load(cls->superclass);
3126
3127 add_class_to_loadable_list(cls);
3128 cls->setInfo(RW_LOADED);
3129 }
3130
3131 // Quick scan for +load methods that doesn't take a lock.
3132 bool hasLoadMethods(const headerType *mhdr)
3133 {
3134 size_t count;
3135 if (_getObjc2NonlazyClassList(mhdr, &count) && count > 0) return true;
3136 if (_getObjc2NonlazyCategoryList(mhdr, &count) && count > 0) return true;
3137 return false;
3138 }
3139
3140 void prepare_load_methods(const headerType *mhdr)
3141 {
3142 size_t count, i;
3143
3144 runtimeLock.assertLocked();
3145
3146 classref_t *classlist =
3147 _getObjc2NonlazyClassList(mhdr, &count);
3148 for (i = 0; i < count; i++) {
3149 schedule_class_load(remapClass(classlist[i]));
3150 }
3151
3152 category_t **categorylist = _getObjc2NonlazyCategoryList(mhdr, &count);
3153 for (i = 0; i < count; i++) {
3154 category_t *cat = categorylist[i];
3155 Class cls = remapClass(cat->cls);
3156 if (!cls) continue; // category for ignored weak-linked class
3157 if (cls->isSwiftStable()) {
3158 _objc_fatal("Swift class extensions and categories on Swift "
3159 "classes are not allowed to have +load methods");
3160 }
3161 realizeClassWithoutSwift(cls);
3162 assert(cls->ISA()->isRealized());
3163 add_category_to_loadable_list(cat);
3164 }
3165 }
3166
3167
3168 /***********************************************************************
3169 * _unload_image
3170 * Only handles MH_BUNDLE for now.
3171 * Locking: write-lock and loadMethodLock acquired by unmap_image
3172 **********************************************************************/
3173 void _unload_image(header_info *hi)
3174 {
3175 size_t count, i;
3176
3177 loadMethodLock.assertLocked();
3178 runtimeLock.assertLocked();
3179
3180 // Unload unattached categories and categories waiting for +load.
3181
3182 category_t **catlist = _getObjc2CategoryList(hi, &count);
3183 for (i = 0; i < count; i++) {
3184 category_t *cat = catlist[i];
3185 if (!cat) continue; // category for ignored weak-linked class
3186 Class cls = remapClass(cat->cls);
3187 assert(cls); // shouldn't have live category for dead class
3188
3189 // fixme for MH_DYLIB cat's class may have been unloaded already
3190
3191 // unattached list
3192 removeUnattachedCategoryForClass(cat, cls);
3193
3194 // +load queue
3195 remove_category_from_loadable_list(cat);
3196 }
3197
3198 // Unload classes.
3199
3200 // Gather classes from both __DATA,__objc_clslist
3201 // and __DATA,__objc_nlclslist. arclite's hack puts a class in the latter
3202 // only, and we need to unload that class if we unload an arclite image.
3203
3204 NXHashTable *classes = NXCreateHashTable(NXPtrPrototype, 0, nil);
3205 classref_t *classlist;
3206
3207 classlist = _getObjc2ClassList(hi, &count);
3208 for (i = 0; i < count; i++) {
3209 Class cls = remapClass(classlist[i]);
3210 if (cls) NXHashInsert(classes, cls);
3211 }
3212
3213 classlist = _getObjc2NonlazyClassList(hi, &count);
3214 for (i = 0; i < count; i++) {
3215 Class cls = remapClass(classlist[i]);
3216 if (cls) NXHashInsert(classes, cls);
3217 }
3218
3219 // First detach classes from each other. Then free each class.
3220 // This avoid bugs where this loop unloads a subclass before its superclass
3221
3222 NXHashState hs;
3223 Class cls;
3224
3225 hs = NXInitHashState(classes);
3226 while (NXNextHashState(classes, &hs, (void**)&cls)) {
3227 remove_class_from_loadable_list(cls);
3228 detach_class(cls->ISA(), YES);
3229 detach_class(cls, NO);
3230 }
3231 hs = NXInitHashState(classes);
3232 while (NXNextHashState(classes, &hs, (void**)&cls)) {
3233 free_class(cls->ISA());
3234 free_class(cls);
3235 }
3236
3237 NXFreeHashTable(classes);
3238
3239 // XXX FIXME -- Clean up protocols:
3240 // <rdar://problem/9033191> Support unloading protocols at dylib/image unload time
3241
3242 // fixme DebugUnload
3243 }
3244
3245
3246 /***********************************************************************
3247 * method_getDescription
3248 * Returns a pointer to this method's objc_method_description.
3249 * Locking: none
3250 **********************************************************************/
3251 struct objc_method_description *
3252 method_getDescription(Method m)
3253 {
3254 if (!m) return nil;
3255 return (struct objc_method_description *)m;
3256 }
3257
3258
3259 IMP
3260 method_getImplementation(Method m)
3261 {
3262 return m ? m->imp : nil;
3263 }
3264
3265
3266 /***********************************************************************
3267 * method_getName
3268 * Returns this method's selector.
3269 * The method must not be nil.
3270 * The method must already have been fixed-up.
3271 * Locking: none
3272 **********************************************************************/
3273 SEL
3274 method_getName(Method m)
3275 {
3276 if (!m) return nil;
3277
3278 assert(m->name == sel_registerName(sel_getName(m->name)));
3279 return m->name;
3280 }
3281
3282
3283 /***********************************************************************
3284 * method_getTypeEncoding
3285 * Returns this method's old-style type encoding string.
3286 * The method must not be nil.
3287 * Locking: none
3288 **********************************************************************/
3289 const char *
3290 method_getTypeEncoding(Method m)
3291 {
3292 if (!m) return nil;
3293 return m->types;
3294 }
3295
3296
3297 /***********************************************************************
3298 * method_setImplementation
3299 * Sets this method's implementation to imp.
3300 * The previous implementation is returned.
3301 **********************************************************************/
3302 static IMP
3303 _method_setImplementation(Class cls, method_t *m, IMP imp)
3304 {
3305 runtimeLock.assertLocked();
3306
3307 if (!m) return nil;
3308 if (!imp) return nil;
3309
3310 IMP old = m->imp;
3311 m->imp = imp;
3312
3313 // Cache updates are slow if cls is nil (i.e. unknown)
3314 // RR/AWZ updates are slow if cls is nil (i.e. unknown)
3315 // fixme build list of classes whose Methods are known externally?
3316
3317 flushCaches(cls);
3318
3319 updateCustomRR_AWZ(cls, m);
3320
3321 return old;
3322 }
3323
3324 IMP
3325 method_setImplementation(Method m, IMP imp)
3326 {
3327 // Don't know the class - will be slow if RR/AWZ are affected
3328 // fixme build list of classes whose Methods are known externally?
3329 mutex_locker_t lock(runtimeLock);
3330 return _method_setImplementation(Nil, m, imp);
3331 }
3332
3333
3334 void method_exchangeImplementations(Method m1, Method m2)
3335 {
3336 if (!m1 || !m2) return;
3337
3338 mutex_locker_t lock(runtimeLock);
3339
3340 IMP m1_imp = m1->imp;
3341 m1->imp = m2->imp;
3342 m2->imp = m1_imp;
3343
3344
3345 // RR/AWZ updates are slow because class is unknown
3346 // Cache updates are slow because class is unknown
3347 // fixme build list of classes whose Methods are known externally?
3348
3349 flushCaches(nil);
3350
3351 updateCustomRR_AWZ(nil, m1);
3352 updateCustomRR_AWZ(nil, m2);
3353 }
3354
3355
3356 /***********************************************************************
3357 * ivar_getOffset
3358 * fixme
3359 * Locking: none
3360 **********************************************************************/
3361 ptrdiff_t
3362 ivar_getOffset(Ivar ivar)
3363 {
3364 if (!ivar) return 0;
3365 return *ivar->offset;
3366 }
3367
3368
3369 /***********************************************************************
3370 * ivar_getName
3371 * fixme
3372 * Locking: none
3373 **********************************************************************/
3374 const char *
3375 ivar_getName(Ivar ivar)
3376 {
3377 if (!ivar) return nil;
3378 return ivar->name;
3379 }
3380
3381
3382 /***********************************************************************
3383 * ivar_getTypeEncoding
3384 * fixme
3385 * Locking: none
3386 **********************************************************************/
3387 const char *
3388 ivar_getTypeEncoding(Ivar ivar)
3389 {
3390 if (!ivar) return nil;
3391 return ivar->type;
3392 }
3393
3394
3395
3396 const char *property_getName(objc_property_t prop)
3397 {
3398 return prop->name;
3399 }
3400
3401 const char *property_getAttributes(objc_property_t prop)
3402 {
3403 return prop->attributes;
3404 }
3405
3406 objc_property_attribute_t *property_copyAttributeList(objc_property_t prop,
3407 unsigned int *outCount)
3408 {
3409 if (!prop) {
3410 if (outCount) *outCount = 0;
3411 return nil;
3412 }
3413
3414 mutex_locker_t lock(runtimeLock);
3415 return copyPropertyAttributeList(prop->attributes,outCount);
3416 }
3417
3418 char * property_copyAttributeValue(objc_property_t prop, const char *name)
3419 {
3420 if (!prop || !name || *name == '\0') return nil;
3421
3422 mutex_locker_t lock(runtimeLock);
3423 return copyPropertyAttributeValue(prop->attributes, name);
3424 }
3425
3426
3427 /***********************************************************************
3428 * getExtendedTypesIndexesForMethod
3429 * Returns:
3430 * a is the count of methods in all method lists before m's method list
3431 * b is the index of m in m's method list
3432 * a+b is the index of m's extended types in the extended types array
3433 **********************************************************************/
3434 static void getExtendedTypesIndexesForMethod(protocol_t *proto, const method_t *m, bool isRequiredMethod, bool isInstanceMethod, uint32_t& a, uint32_t &b)
3435 {
3436 a = 0;
3437
3438 if (proto->instanceMethods) {
3439 if (isRequiredMethod && isInstanceMethod) {
3440 b = proto->instanceMethods->indexOfMethod(m);
3441 return;
3442 }
3443 a += proto->instanceMethods->count;
3444 }
3445
3446 if (proto->classMethods) {
3447 if (isRequiredMethod && !isInstanceMethod) {
3448 b = proto->classMethods->indexOfMethod(m);
3449 return;
3450 }
3451 a += proto->classMethods->count;
3452 }
3453
3454 if (proto->optionalInstanceMethods) {
3455 if (!isRequiredMethod && isInstanceMethod) {
3456 b = proto->optionalInstanceMethods->indexOfMethod(m);
3457 return;
3458 }
3459 a += proto->optionalInstanceMethods->count;
3460 }
3461
3462 if (proto->optionalClassMethods) {
3463 if (!isRequiredMethod && !isInstanceMethod) {
3464 b = proto->optionalClassMethods->indexOfMethod(m);
3465 return;
3466 }
3467 a += proto->optionalClassMethods->count;
3468 }
3469 }
3470
3471
3472 /***********************************************************************
3473 * getExtendedTypesIndexForMethod
3474 * Returns the index of m's extended types in proto's extended types array.
3475 **********************************************************************/
3476 static uint32_t getExtendedTypesIndexForMethod(protocol_t *proto, const method_t *m, bool isRequiredMethod, bool isInstanceMethod)
3477 {
3478 uint32_t a;
3479 uint32_t b;
3480 getExtendedTypesIndexesForMethod(proto, m, isRequiredMethod,
3481 isInstanceMethod, a, b);
3482 return a + b;
3483 }
3484
3485
3486 /***********************************************************************
3487 * fixupProtocolMethodList
3488 * Fixes up a single method list in a protocol.
3489 **********************************************************************/
3490 static void
3491 fixupProtocolMethodList(protocol_t *proto, method_list_t *mlist,
3492 bool required, bool instance)
3493 {
3494 runtimeLock.assertLocked();
3495
3496 if (!mlist) return;
3497 if (mlist->isFixedUp()) return;
3498
3499 const char **extTypes = proto->extendedMethodTypes();
3500 fixupMethodList(mlist, true/*always copy for simplicity*/,
3501 !extTypes/*sort if no extended method types*/);
3502
3503 if (extTypes) {
3504 // Sort method list and extended method types together.
3505 // fixupMethodList() can't do this.
3506 // fixme COW stomp
3507 uint32_t count = mlist->count;
3508 uint32_t prefix;
3509 uint32_t junk;
3510 getExtendedTypesIndexesForMethod(proto, &mlist->get(0),
3511 required, instance, prefix, junk);
3512 for (uint32_t i = 0; i < count; i++) {
3513 for (uint32_t j = i+1; j < count; j++) {
3514 method_t& mi = mlist->get(i);
3515 method_t& mj = mlist->get(j);
3516 if (mi.name > mj.name) {
3517 std::swap(mi, mj);
3518 std::swap(extTypes[prefix+i], extTypes[prefix+j]);
3519 }
3520 }
3521 }
3522 }
3523 }
3524
3525
3526 /***********************************************************************
3527 * fixupProtocol
3528 * Fixes up all of a protocol's method lists.
3529 **********************************************************************/
3530 static void
3531 fixupProtocol(protocol_t *proto)
3532 {
3533 runtimeLock.assertLocked();
3534
3535 if (proto->protocols) {
3536 for (uintptr_t i = 0; i < proto->protocols->count; i++) {
3537 protocol_t *sub = remapProtocol(proto->protocols->list[i]);
3538 if (!sub->isFixedUp()) fixupProtocol(sub);
3539 }
3540 }
3541
3542 fixupProtocolMethodList(proto, proto->instanceMethods, YES, YES);
3543 fixupProtocolMethodList(proto, proto->classMethods, YES, NO);
3544 fixupProtocolMethodList(proto, proto->optionalInstanceMethods, NO, YES);
3545 fixupProtocolMethodList(proto, proto->optionalClassMethods, NO, NO);
3546
3547 // fixme memory barrier so we can check this with no lock
3548 proto->setFixedUp();
3549 }
3550
3551
3552 /***********************************************************************
3553 * fixupProtocolIfNeeded
3554 * Fixes up all of a protocol's method lists if they aren't fixed up already.
3555 * Locking: write-locks runtimeLock.
3556 **********************************************************************/
3557 static void
3558 fixupProtocolIfNeeded(protocol_t *proto)
3559 {
3560 runtimeLock.assertUnlocked();
3561 assert(proto);
3562
3563 if (!proto->isFixedUp()) {
3564 mutex_locker_t lock(runtimeLock);
3565 fixupProtocol(proto);
3566 }
3567 }
3568
3569
3570 static method_list_t *
3571 getProtocolMethodList(protocol_t *proto, bool required, bool instance)
3572 {
3573 method_list_t **mlistp = nil;
3574 if (required) {
3575 if (instance) {
3576 mlistp = &proto->instanceMethods;
3577 } else {
3578 mlistp = &proto->classMethods;
3579 }
3580 } else {
3581 if (instance) {
3582 mlistp = &proto->optionalInstanceMethods;
3583 } else {
3584 mlistp = &proto->optionalClassMethods;
3585 }
3586 }
3587
3588 return *mlistp;
3589 }
3590
3591
3592 /***********************************************************************
3593 * protocol_getMethod_nolock
3594 * Locking: runtimeLock must be held by the caller
3595 **********************************************************************/
3596 static method_t *
3597 protocol_getMethod_nolock(protocol_t *proto, SEL sel,
3598 bool isRequiredMethod, bool isInstanceMethod,
3599 bool recursive)
3600 {
3601 runtimeLock.assertLocked();
3602
3603 if (!proto || !sel) return nil;
3604
3605 assert(proto->isFixedUp());
3606
3607 method_list_t *mlist =
3608 getProtocolMethodList(proto, isRequiredMethod, isInstanceMethod);
3609 if (mlist) {
3610 method_t *m = search_method_list(mlist, sel);
3611 if (m) return m;
3612 }
3613
3614 if (recursive && proto->protocols) {
3615 method_t *m;
3616 for (uint32_t i = 0; i < proto->protocols->count; i++) {
3617 protocol_t *realProto = remapProtocol(proto->protocols->list[i]);
3618 m = protocol_getMethod_nolock(realProto, sel,
3619 isRequiredMethod, isInstanceMethod,
3620 true);
3621 if (m) return m;
3622 }
3623 }
3624
3625 return nil;
3626 }
3627
3628
3629 /***********************************************************************
3630 * protocol_getMethod
3631 * fixme
3632 * Locking: acquires runtimeLock
3633 **********************************************************************/
3634 Method
3635 protocol_getMethod(protocol_t *proto, SEL sel, bool isRequiredMethod, bool isInstanceMethod, bool recursive)
3636 {
3637 if (!proto) return nil;
3638 fixupProtocolIfNeeded(proto);
3639
3640 mutex_locker_t lock(runtimeLock);
3641 return protocol_getMethod_nolock(proto, sel, isRequiredMethod,
3642 isInstanceMethod, recursive);
3643 }
3644
3645
3646 /***********************************************************************
3647 * protocol_getMethodTypeEncoding_nolock
3648 * Return the @encode string for the requested protocol method.
3649 * Returns nil if the compiler did not emit any extended @encode data.
3650 * Locking: runtimeLock must be held by the caller
3651 **********************************************************************/
3652 const char *
3653 protocol_getMethodTypeEncoding_nolock(protocol_t *proto, SEL sel,
3654 bool isRequiredMethod,
3655 bool isInstanceMethod)
3656 {
3657 runtimeLock.assertLocked();
3658
3659 if (!proto) return nil;
3660 if (!proto->extendedMethodTypes()) return nil;
3661
3662 assert(proto->isFixedUp());
3663
3664 method_t *m =
3665 protocol_getMethod_nolock(proto, sel,
3666 isRequiredMethod, isInstanceMethod, false);
3667 if (m) {
3668 uint32_t i = getExtendedTypesIndexForMethod(proto, m,
3669 isRequiredMethod,
3670 isInstanceMethod);
3671 return proto->extendedMethodTypes()[i];
3672 }
3673
3674 // No method with that name. Search incorporated protocols.
3675 if (proto->protocols) {
3676 for (uintptr_t i = 0; i < proto->protocols->count; i++) {
3677 const char *enc =
3678 protocol_getMethodTypeEncoding_nolock(remapProtocol(proto->protocols->list[i]), sel, isRequiredMethod, isInstanceMethod);
3679 if (enc) return enc;
3680 }
3681 }
3682
3683 return nil;
3684 }
3685
3686 /***********************************************************************
3687 * _protocol_getMethodTypeEncoding
3688 * Return the @encode string for the requested protocol method.
3689 * Returns nil if the compiler did not emit any extended @encode data.
3690 * Locking: acquires runtimeLock
3691 **********************************************************************/
3692 const char *
3693 _protocol_getMethodTypeEncoding(Protocol *proto_gen, SEL sel,
3694 BOOL isRequiredMethod, BOOL isInstanceMethod)
3695 {
3696 protocol_t *proto = newprotocol(proto_gen);
3697
3698 if (!proto) return nil;
3699 fixupProtocolIfNeeded(proto);
3700
3701 mutex_locker_t lock(runtimeLock);
3702 return protocol_getMethodTypeEncoding_nolock(proto, sel,
3703 isRequiredMethod,
3704 isInstanceMethod);
3705 }
3706
3707
3708 /***********************************************************************
3709 * protocol_t::demangledName
3710 * Returns the (Swift-demangled) name of the given protocol.
3711 * Locking: none
3712 **********************************************************************/
3713 const char *
3714 protocol_t::demangledName()
3715 {
3716 assert(hasDemangledNameField());
3717
3718 if (! _demangledName) {
3719 char *de = copySwiftV1DemangledName(mangledName, true/*isProtocol*/);
3720 if (! OSAtomicCompareAndSwapPtrBarrier(nil, (void*)(de ?: mangledName),
3721 (void**)&_demangledName))
3722 {
3723 if (de) free(de);
3724 }
3725 }
3726 return _demangledName;
3727 }
3728
3729 /***********************************************************************
3730 * protocol_getName
3731 * Returns the (Swift-demangled) name of the given protocol.
3732 * Locking: runtimeLock must not be held by the caller
3733 **********************************************************************/
3734 const char *
3735 protocol_getName(Protocol *proto)
3736 {
3737 if (!proto) return "nil";
3738 else return newprotocol(proto)->demangledName();
3739 }
3740
3741
3742 /***********************************************************************
3743 * protocol_getInstanceMethodDescription
3744 * Returns the description of a named instance method.
3745 * Locking: runtimeLock must not be held by the caller
3746 **********************************************************************/
3747 struct objc_method_description
3748 protocol_getMethodDescription(Protocol *p, SEL aSel,
3749 BOOL isRequiredMethod, BOOL isInstanceMethod)
3750 {
3751 Method m =
3752 protocol_getMethod(newprotocol(p), aSel,
3753 isRequiredMethod, isInstanceMethod, true);
3754 if (m) return *method_getDescription(m);
3755 else return (struct objc_method_description){nil, nil};
3756 }
3757
3758
3759 /***********************************************************************
3760 * protocol_conformsToProtocol_nolock
3761 * Returns YES if self conforms to other.
3762 * Locking: runtimeLock must be held by the caller.
3763 **********************************************************************/
3764 static bool
3765 protocol_conformsToProtocol_nolock(protocol_t *self, protocol_t *other)
3766 {
3767 runtimeLock.assertLocked();
3768
3769 if (!self || !other) {
3770 return NO;
3771 }
3772
3773 // protocols need not be fixed up
3774
3775 if (0 == strcmp(self->mangledName, other->mangledName)) {
3776 return YES;
3777 }
3778
3779 if (self->protocols) {
3780 uintptr_t i;
3781 for (i = 0; i < self->protocols->count; i++) {
3782 protocol_t *proto = remapProtocol(self->protocols->list[i]);
3783 if (0 == strcmp(other->mangledName, proto->mangledName)) {
3784 return YES;
3785 }
3786 if (protocol_conformsToProtocol_nolock(proto, other)) {
3787 return YES;
3788 }
3789 }
3790 }
3791
3792 return NO;
3793 }
3794
3795
3796 /***********************************************************************
3797 * protocol_conformsToProtocol
3798 * Returns YES if self conforms to other.
3799 * Locking: acquires runtimeLock
3800 **********************************************************************/
3801 BOOL protocol_conformsToProtocol(Protocol *self, Protocol *other)
3802 {
3803 mutex_locker_t lock(runtimeLock);
3804 return protocol_conformsToProtocol_nolock(newprotocol(self),
3805 newprotocol(other));
3806 }
3807
3808
3809 /***********************************************************************
3810 * protocol_isEqual
3811 * Return YES if two protocols are equal (i.e. conform to each other)
3812 * Locking: acquires runtimeLock
3813 **********************************************************************/
3814 BOOL protocol_isEqual(Protocol *self, Protocol *other)
3815 {
3816 if (self == other) return YES;
3817 if (!self || !other) return NO;
3818
3819 if (!protocol_conformsToProtocol(self, other)) return NO;
3820 if (!protocol_conformsToProtocol(other, self)) return NO;
3821
3822 return YES;
3823 }
3824
3825
3826 /***********************************************************************
3827 * protocol_copyMethodDescriptionList
3828 * Returns descriptions of a protocol's methods.
3829 * Locking: acquires runtimeLock
3830 **********************************************************************/
3831 struct objc_method_description *
3832 protocol_copyMethodDescriptionList(Protocol *p,
3833 BOOL isRequiredMethod,BOOL isInstanceMethod,
3834 unsigned int *outCount)
3835 {
3836 protocol_t *proto = newprotocol(p);
3837 struct objc_method_description *result = nil;
3838 unsigned int count = 0;
3839
3840 if (!proto) {
3841 if (outCount) *outCount = 0;
3842 return nil;
3843 }
3844
3845 fixupProtocolIfNeeded(proto);
3846
3847 mutex_locker_t lock(runtimeLock);
3848
3849 method_list_t *mlist =
3850 getProtocolMethodList(proto, isRequiredMethod, isInstanceMethod);
3851
3852 if (mlist) {
3853 result = (struct objc_method_description *)
3854 calloc(mlist->count + 1, sizeof(struct objc_method_description));
3855 for (const auto& meth : *mlist) {
3856 result[count].name = meth.name;
3857 result[count].types = (char *)meth.types;
3858 count++;
3859 }
3860 }
3861
3862 if (outCount) *outCount = count;
3863 return result;
3864 }
3865
3866
3867 /***********************************************************************
3868 * protocol_getProperty
3869 * fixme
3870 * Locking: runtimeLock must be held by the caller
3871 **********************************************************************/
3872 static property_t *
3873 protocol_getProperty_nolock(protocol_t *proto, const char *name,
3874 bool isRequiredProperty, bool isInstanceProperty)
3875 {
3876 runtimeLock.assertLocked();
3877
3878 if (!isRequiredProperty) {
3879 // Only required properties are currently supported.
3880 return nil;
3881 }
3882
3883 property_list_t *plist = isInstanceProperty ?
3884 proto->instanceProperties : proto->classProperties();
3885 if (plist) {
3886 for (auto& prop : *plist) {
3887 if (0 == strcmp(name, prop.name)) {
3888 return &prop;
3889 }
3890 }
3891 }
3892
3893 if (proto->protocols) {
3894 uintptr_t i;
3895 for (i = 0; i < proto->protocols->count; i++) {
3896 protocol_t *p = remapProtocol(proto->protocols->list[i]);
3897 property_t *prop =
3898 protocol_getProperty_nolock(p, name,
3899 isRequiredProperty,
3900 isInstanceProperty);
3901 if (prop) return prop;
3902 }
3903 }
3904
3905 return nil;
3906 }
3907
3908 objc_property_t protocol_getProperty(Protocol *p, const char *name,
3909 BOOL isRequiredProperty, BOOL isInstanceProperty)
3910 {
3911 if (!p || !name) return nil;
3912
3913 mutex_locker_t lock(runtimeLock);
3914 return (objc_property_t)
3915 protocol_getProperty_nolock(newprotocol(p), name,
3916 isRequiredProperty, isInstanceProperty);
3917 }
3918
3919
3920 /***********************************************************************
3921 * protocol_copyPropertyList
3922 * protocol_copyPropertyList2
3923 * fixme
3924 * Locking: acquires runtimeLock
3925 **********************************************************************/
3926 static property_t **
3927 copyPropertyList(property_list_t *plist, unsigned int *outCount)
3928 {
3929 property_t **result = nil;
3930 unsigned int count = 0;
3931
3932 if (plist) {
3933 count = plist->count;
3934 }
3935
3936 if (count > 0) {
3937 result = (property_t **)malloc((count+1) * sizeof(property_t *));
3938
3939 count = 0;
3940 for (auto& prop : *plist) {
3941 result[count++] = &prop;
3942 }
3943 result[count] = nil;
3944 }
3945
3946 if (outCount) *outCount = count;
3947 return result;
3948 }
3949
3950 objc_property_t *
3951 protocol_copyPropertyList2(Protocol *proto, unsigned int *outCount,
3952 BOOL isRequiredProperty, BOOL isInstanceProperty)
3953 {
3954 if (!proto || !isRequiredProperty) {
3955 // Optional properties are not currently supported.
3956 if (outCount) *outCount = 0;
3957 return nil;
3958 }
3959
3960 mutex_locker_t lock(runtimeLock);
3961
3962 property_list_t *plist = isInstanceProperty
3963 ? newprotocol(proto)->instanceProperties
3964 : newprotocol(proto)->classProperties();
3965 return (objc_property_t *)copyPropertyList(plist, outCount);
3966 }
3967
3968 objc_property_t *
3969 protocol_copyPropertyList(Protocol *proto, unsigned int *outCount)
3970 {
3971 return protocol_copyPropertyList2(proto, outCount,
3972 YES/*required*/, YES/*instance*/);
3973 }
3974
3975
3976 /***********************************************************************
3977 * protocol_copyProtocolList
3978 * Copies this protocol's incorporated protocols.
3979 * Does not copy those protocol's incorporated protocols in turn.
3980 * Locking: acquires runtimeLock
3981 **********************************************************************/
3982 Protocol * __unsafe_unretained *
3983 protocol_copyProtocolList(Protocol *p, unsigned int *outCount)
3984 {
3985 unsigned int count = 0;
3986 Protocol **result = nil;
3987 protocol_t *proto = newprotocol(p);
3988
3989 if (!proto) {
3990 if (outCount) *outCount = 0;
3991 return nil;
3992 }
3993
3994 mutex_locker_t lock(runtimeLock);
3995
3996 if (proto->protocols) {
3997 count = (unsigned int)proto->protocols->count;
3998 }
3999 if (count > 0) {
4000 result = (Protocol **)malloc((count+1) * sizeof(Protocol *));
4001
4002 unsigned int i;
4003 for (i = 0; i < count; i++) {
4004 result[i] = (Protocol *)remapProtocol(proto->protocols->list[i]);
4005 }
4006 result[i] = nil;
4007 }
4008
4009 if (outCount) *outCount = count;
4010 return result;
4011 }
4012
4013
4014 /***********************************************************************
4015 * objc_allocateProtocol
4016 * Creates a new protocol. The protocol may not be used until
4017 * objc_registerProtocol() is called.
4018 * Returns nil if a protocol with the same name already exists.
4019 * Locking: acquires runtimeLock
4020 **********************************************************************/
4021 Protocol *
4022 objc_allocateProtocol(const char *name)
4023 {
4024 mutex_locker_t lock(runtimeLock);
4025
4026 if (getProtocol(name)) {
4027 return nil;
4028 }
4029
4030 protocol_t *result = (protocol_t *)calloc(sizeof(protocol_t), 1);
4031
4032 extern objc_class OBJC_CLASS_$___IncompleteProtocol;
4033 Class cls = (Class)&OBJC_CLASS_$___IncompleteProtocol;
4034 result->initProtocolIsa(cls);
4035 result->size = sizeof(protocol_t);
4036 // fixme mangle the name if it looks swift-y?
4037 result->mangledName = strdupIfMutable(name);
4038
4039 // fixme reserve name without installing
4040
4041 return (Protocol *)result;
4042 }
4043
4044
4045 /***********************************************************************
4046 * objc_registerProtocol
4047 * Registers a newly-constructed protocol. The protocol is now
4048 * ready for use and immutable.
4049 * Locking: acquires runtimeLock
4050 **********************************************************************/
4051 void objc_registerProtocol(Protocol *proto_gen)
4052 {
4053 protocol_t *proto = newprotocol(proto_gen);
4054
4055 mutex_locker_t lock(runtimeLock);
4056
4057 extern objc_class OBJC_CLASS_$___IncompleteProtocol;
4058 Class oldcls = (Class)&OBJC_CLASS_$___IncompleteProtocol;
4059 extern objc_class OBJC_CLASS_$_Protocol;
4060 Class cls = (Class)&OBJC_CLASS_$_Protocol;
4061
4062 if (proto->ISA() == cls) {
4063 _objc_inform("objc_registerProtocol: protocol '%s' was already "
4064 "registered!", proto->nameForLogging());
4065 return;
4066 }
4067 if (proto->ISA() != oldcls) {
4068 _objc_inform("objc_registerProtocol: protocol '%s' was not allocated "
4069 "with objc_allocateProtocol!", proto->nameForLogging());
4070 return;
4071 }
4072
4073 // NOT initProtocolIsa(). The protocol object may already
4074 // have been retained and we must preserve that count.
4075 proto->changeIsa(cls);
4076
4077 NXMapKeyCopyingInsert(protocols(), proto->mangledName, proto);
4078 }
4079
4080
4081 /***********************************************************************
4082 * protocol_addProtocol
4083 * Adds an incorporated protocol to another protocol.
4084 * No method enforcement is performed.
4085 * `proto` must be under construction. `addition` must not.
4086 * Locking: acquires runtimeLock
4087 **********************************************************************/
4088 void
4089 protocol_addProtocol(Protocol *proto_gen, Protocol *addition_gen)
4090 {
4091 protocol_t *proto = newprotocol(proto_gen);
4092 protocol_t *addition = newprotocol(addition_gen);
4093
4094 extern objc_class OBJC_CLASS_$___IncompleteProtocol;
4095 Class cls = (Class)&OBJC_CLASS_$___IncompleteProtocol;
4096
4097 if (!proto_gen) return;
4098 if (!addition_gen) return;
4099
4100 mutex_locker_t lock(runtimeLock);
4101
4102 if (proto->ISA() != cls) {
4103 _objc_inform("protocol_addProtocol: modified protocol '%s' is not "
4104 "under construction!", proto->nameForLogging());
4105 return;
4106 }
4107 if (addition->ISA() == cls) {
4108 _objc_inform("protocol_addProtocol: added protocol '%s' is still "
4109 "under construction!", addition->nameForLogging());
4110 return;
4111 }
4112
4113 protocol_list_t *protolist = proto->protocols;
4114 if (!protolist) {
4115 protolist = (protocol_list_t *)
4116 calloc(1, sizeof(protocol_list_t)
4117 + sizeof(protolist->list[0]));
4118 } else {
4119 protolist = (protocol_list_t *)
4120 realloc(protolist, protocol_list_size(protolist)
4121 + sizeof(protolist->list[0]));
4122 }
4123
4124 protolist->list[protolist->count++] = (protocol_ref_t)addition;
4125 proto->protocols = protolist;
4126 }
4127
4128
4129 /***********************************************************************
4130 * protocol_addMethodDescription
4131 * Adds a method to a protocol. The protocol must be under construction.
4132 * Locking: acquires runtimeLock
4133 **********************************************************************/
4134 static void
4135 protocol_addMethod_nolock(method_list_t*& list, SEL name, const char *types)
4136 {
4137 if (!list) {
4138 list = (method_list_t *)calloc(sizeof(method_list_t), 1);
4139 list->entsizeAndFlags = sizeof(list->first);
4140 list->setFixedUp();
4141 } else {
4142 size_t size = list->byteSize() + list->entsize();
4143 list = (method_list_t *)realloc(list, size);
4144 }
4145
4146 method_t& meth = list->get(list->count++);
4147 meth.name = name;
4148 meth.types = types ? strdupIfMutable(types) : "";
4149 meth.imp = nil;
4150 }
4151
4152 void
4153 protocol_addMethodDescription(Protocol *proto_gen, SEL name, const char *types,
4154 BOOL isRequiredMethod, BOOL isInstanceMethod)
4155 {
4156 protocol_t *proto = newprotocol(proto_gen);
4157
4158 extern objc_class OBJC_CLASS_$___IncompleteProtocol;
4159 Class cls = (Class)&OBJC_CLASS_$___IncompleteProtocol;
4160
4161 if (!proto_gen) return;
4162
4163 mutex_locker_t lock(runtimeLock);
4164
4165 if (proto->ISA() != cls) {
4166 _objc_inform("protocol_addMethodDescription: protocol '%s' is not "
4167 "under construction!", proto->nameForLogging());
4168 return;
4169 }
4170
4171 if (isRequiredMethod && isInstanceMethod) {
4172 protocol_addMethod_nolock(proto->instanceMethods, name, types);
4173 } else if (isRequiredMethod && !isInstanceMethod) {
4174 protocol_addMethod_nolock(proto->classMethods, name, types);
4175 } else if (!isRequiredMethod && isInstanceMethod) {
4176 protocol_addMethod_nolock(proto->optionalInstanceMethods, name,types);
4177 } else /* !isRequiredMethod && !isInstanceMethod) */ {
4178 protocol_addMethod_nolock(proto->optionalClassMethods, name, types);
4179 }
4180 }
4181
4182
4183 /***********************************************************************
4184 * protocol_addProperty
4185 * Adds a property to a protocol. The protocol must be under construction.
4186 * Locking: acquires runtimeLock
4187 **********************************************************************/
4188 static void
4189 protocol_addProperty_nolock(property_list_t *&plist, const char *name,
4190 const objc_property_attribute_t *attrs,
4191 unsigned int count)
4192 {
4193 if (!plist) {
4194 plist = (property_list_t *)calloc(sizeof(property_list_t), 1);
4195 plist->entsizeAndFlags = sizeof(property_t);
4196 } else {
4197 plist = (property_list_t *)
4198 realloc(plist, sizeof(property_list_t)
4199 + plist->count * plist->entsize());
4200 }
4201
4202 property_t& prop = plist->get(plist->count++);
4203 prop.name = strdupIfMutable(name);
4204 prop.attributes = copyPropertyAttributeString(attrs, count);
4205 }
4206
4207 void
4208 protocol_addProperty(Protocol *proto_gen, const char *name,
4209 const objc_property_attribute_t *attrs,
4210 unsigned int count,
4211 BOOL isRequiredProperty, BOOL isInstanceProperty)
4212 {
4213 protocol_t *proto = newprotocol(proto_gen);
4214
4215 extern objc_class OBJC_CLASS_$___IncompleteProtocol;
4216 Class cls = (Class)&OBJC_CLASS_$___IncompleteProtocol;
4217
4218 if (!proto) return;
4219 if (!name) return;
4220
4221 mutex_locker_t lock(runtimeLock);
4222
4223 if (proto->ISA() != cls) {
4224 _objc_inform("protocol_addProperty: protocol '%s' is not "
4225 "under construction!", proto->nameForLogging());
4226 return;
4227 }
4228
4229 if (isRequiredProperty && isInstanceProperty) {
4230 protocol_addProperty_nolock(proto->instanceProperties, name, attrs, count);
4231 }
4232 else if (isRequiredProperty && !isInstanceProperty) {
4233 protocol_addProperty_nolock(proto->_classProperties, name, attrs, count);
4234 }
4235 //else if (!isRequiredProperty && isInstanceProperty) {
4236 // protocol_addProperty_nolock(proto->optionalInstanceProperties, name, attrs, count);
4237 //}
4238 //else /* !isRequiredProperty && !isInstanceProperty) */ {
4239 // protocol_addProperty_nolock(proto->optionalClassProperties, name, attrs, count);
4240 //}
4241 }
4242
4243
4244 /***********************************************************************
4245 * objc_getClassList
4246 * Returns pointers to all classes.
4247 * This requires all classes be realized, which is regretfully non-lazy.
4248 * Locking: acquires runtimeLock
4249 **********************************************************************/
4250 int
4251 objc_getClassList(Class *buffer, int bufferLen)
4252 {
4253 mutex_locker_t lock(runtimeLock);
4254
4255 realizeAllClasses();
4256
4257 __block int count = 0;
4258 foreach_realized_class_and_metaclass(^(Class cls) {
4259 if (!cls->isMetaClass()) count++;
4260 });
4261
4262 if (buffer) {
4263 __block int c = 0;
4264 foreach_realized_class_and_metaclass(^(Class cls) {
4265 if (c < bufferLen && !cls->isMetaClass()) {
4266 buffer[c++] = cls;
4267 }
4268 });
4269 }
4270
4271 return count;
4272 }
4273
4274
4275 /***********************************************************************
4276 * objc_copyClassList
4277 * Returns pointers to all classes.
4278 * This requires all classes be realized, which is regretfully non-lazy.
4279 *
4280 * outCount may be nil. *outCount is the number of classes returned.
4281 * If the returned array is not nil, it is nil-terminated and must be
4282 * freed with free().
4283 * Locking: write-locks runtimeLock
4284 **********************************************************************/
4285 Class *
4286 objc_copyClassList(unsigned int *outCount)
4287 {
4288 mutex_locker_t lock(runtimeLock);
4289
4290 realizeAllClasses();
4291
4292 Class *result = nil;
4293
4294 __block unsigned int count = 0;
4295 foreach_realized_class_and_metaclass(^(Class cls) {
4296 if (!cls->isMetaClass()) count++;
4297 });
4298
4299 if (count > 0) {
4300 result = (Class *)malloc((1+count) * sizeof(Class));
4301 __block unsigned int c = 0;
4302 foreach_realized_class_and_metaclass(^(Class cls) {
4303 if (!cls->isMetaClass()) {
4304 result[c++] = cls;
4305 }
4306 });
4307 result[c] = nil;
4308 }
4309
4310 if (outCount) *outCount = count;
4311 return result;
4312 }
4313
4314
4315 /***********************************************************************
4316 * objc_copyProtocolList
4317 * Returns pointers to all protocols.
4318 * Locking: read-locks runtimeLock
4319 **********************************************************************/
4320 Protocol * __unsafe_unretained *
4321 objc_copyProtocolList(unsigned int *outCount)
4322 {
4323 mutex_locker_t lock(runtimeLock);
4324
4325 NXMapTable *protocol_map = protocols();
4326
4327 unsigned int count = NXCountMapTable(protocol_map);
4328 if (count == 0) {
4329 if (outCount) *outCount = 0;
4330 return nil;
4331 }
4332
4333 Protocol **result = (Protocol **)malloc((count+1) * sizeof(Protocol*));
4334
4335 unsigned int i = 0;
4336 Protocol *proto;
4337 const char *name;
4338 NXMapState state = NXInitMapState(protocol_map);
4339 while (NXNextMapState(protocol_map, &state,
4340 (const void **)&name, (const void **)&proto))
4341 {
4342 result[i++] = proto;
4343 }
4344
4345 result[i++] = nil;
4346 assert(i == count+1);
4347
4348 if (outCount) *outCount = count;
4349 return result;
4350 }
4351
4352
4353 /***********************************************************************
4354 * objc_getProtocol
4355 * Get a protocol by name, or return nil
4356 * Locking: read-locks runtimeLock
4357 **********************************************************************/
4358 Protocol *objc_getProtocol(const char *name)
4359 {
4360 mutex_locker_t lock(runtimeLock);
4361 return getProtocol(name);
4362 }
4363
4364
4365 /***********************************************************************
4366 * class_copyMethodList
4367 * fixme
4368 * Locking: read-locks runtimeLock
4369 **********************************************************************/
4370 Method *
4371 class_copyMethodList(Class cls, unsigned int *outCount)
4372 {
4373 unsigned int count = 0;
4374 Method *result = nil;
4375
4376 if (!cls) {
4377 if (outCount) *outCount = 0;
4378 return nil;
4379 }
4380
4381 mutex_locker_t lock(runtimeLock);
4382
4383 assert(cls->isRealized());
4384
4385 count = cls->data()->methods.count();
4386
4387 if (count > 0) {
4388 result = (Method *)malloc((count + 1) * sizeof(Method));
4389
4390 count = 0;
4391 for (auto& meth : cls->data()->methods) {
4392 result[count++] = &meth;
4393 }
4394 result[count] = nil;
4395 }
4396
4397 if (outCount) *outCount = count;
4398 return result;
4399 }
4400
4401
4402 /***********************************************************************
4403 * class_copyIvarList
4404 * fixme
4405 * Locking: read-locks runtimeLock
4406 **********************************************************************/
4407 Ivar *
4408 class_copyIvarList(Class cls, unsigned int *outCount)
4409 {
4410 const ivar_list_t *ivars;
4411 Ivar *result = nil;
4412 unsigned int count = 0;
4413
4414 if (!cls) {
4415 if (outCount) *outCount = 0;
4416 return nil;
4417 }
4418
4419 mutex_locker_t lock(runtimeLock);
4420
4421 assert(cls->isRealized());
4422
4423 if ((ivars = cls->data()->ro->ivars) && ivars->count) {
4424 result = (Ivar *)malloc((ivars->count+1) * sizeof(Ivar));
4425
4426 for (auto& ivar : *ivars) {
4427 if (!ivar.offset) continue; // anonymous bitfield
4428 result[count++] = &ivar;
4429 }
4430 result[count] = nil;
4431 }
4432
4433 if (outCount) *outCount = count;
4434 return result;
4435 }
4436
4437
4438 /***********************************************************************
4439 * class_copyPropertyList. Returns a heap block containing the
4440 * properties declared in the class, or nil if the class
4441 * declares no properties. Caller must free the block.
4442 * Does not copy any superclass's properties.
4443 * Locking: read-locks runtimeLock
4444 **********************************************************************/
4445 objc_property_t *
4446 class_copyPropertyList(Class cls, unsigned int *outCount)
4447 {
4448 if (!cls) {
4449 if (outCount) *outCount = 0;
4450 return nil;
4451 }
4452
4453 mutex_locker_t lock(runtimeLock);
4454
4455 checkIsKnownClass(cls);
4456 assert(cls->isRealized());
4457
4458 auto rw = cls->data();
4459
4460 property_t **result = nil;
4461 unsigned int count = rw->properties.count();
4462 if (count > 0) {
4463 result = (property_t **)malloc((count + 1) * sizeof(property_t *));
4464
4465 count = 0;
4466 for (auto& prop : rw->properties) {
4467 result[count++] = &prop;
4468 }
4469 result[count] = nil;
4470 }
4471
4472 if (outCount) *outCount = count;
4473 return (objc_property_t *)result;
4474 }
4475
4476
4477 /***********************************************************************
4478 * objc_class::getLoadMethod
4479 * fixme
4480 * Called only from add_class_to_loadable_list.
4481 * Locking: runtimeLock must be read- or write-locked by the caller.
4482 **********************************************************************/
4483 IMP
4484 objc_class::getLoadMethod()
4485 {
4486 runtimeLock.assertLocked();
4487
4488 const method_list_t *mlist;
4489
4490 assert(isRealized());
4491 assert(ISA()->isRealized());
4492 assert(!isMetaClass());
4493 assert(ISA()->isMetaClass());
4494
4495 mlist = ISA()->data()->ro->baseMethods();
4496 if (mlist) {
4497 for (const auto& meth : *mlist) {
4498 const char *name = sel_cname(meth.name);
4499 if (0 == strcmp(name, "load")) {
4500 return meth.imp;
4501 }
4502 }
4503 }
4504
4505 return nil;
4506 }
4507
4508
4509 /***********************************************************************
4510 * _category_getName
4511 * Returns a category's name.
4512 * Locking: none
4513 **********************************************************************/
4514 const char *
4515 _category_getName(Category cat)
4516 {
4517 return cat->name;
4518 }
4519
4520
4521 /***********************************************************************
4522 * _category_getClassName
4523 * Returns a category's class's name
4524 * Called only from add_category_to_loadable_list and
4525 * remove_category_from_loadable_list for logging purposes.
4526 * Locking: runtimeLock must be read- or write-locked by the caller
4527 **********************************************************************/
4528 const char *
4529 _category_getClassName(Category cat)
4530 {
4531 runtimeLock.assertLocked();
4532 return remapClass(cat->cls)->nameForLogging();
4533 }
4534
4535
4536 /***********************************************************************
4537 * _category_getClass
4538 * Returns a category's class
4539 * Called only by call_category_loads.
4540 * Locking: read-locks runtimeLock
4541 **********************************************************************/
4542 Class
4543 _category_getClass(Category cat)
4544 {
4545 mutex_locker_t lock(runtimeLock);
4546 Class result = remapClass(cat->cls);
4547 assert(result->isRealized()); // ok for call_category_loads' usage
4548 return result;
4549 }
4550
4551
4552 /***********************************************************************
4553 * _category_getLoadMethod
4554 * fixme
4555 * Called only from add_category_to_loadable_list
4556 * Locking: runtimeLock must be read- or write-locked by the caller
4557 **********************************************************************/
4558 IMP
4559 _category_getLoadMethod(Category cat)
4560 {
4561 runtimeLock.assertLocked();
4562
4563 const method_list_t *mlist;
4564
4565 mlist = cat->classMethods;
4566 if (mlist) {
4567 for (const auto& meth : *mlist) {
4568 const char *name = sel_cname(meth.name);
4569 if (0 == strcmp(name, "load")) {
4570 return meth.imp;
4571 }
4572 }
4573 }
4574
4575 return nil;
4576 }
4577
4578
4579 /***********************************************************************
4580 * category_t::propertiesForMeta
4581 * Return a category's instance or class properties.
4582 * hi is the image containing the category.
4583 **********************************************************************/
4584 property_list_t *
4585 category_t::propertiesForMeta(bool isMeta, struct header_info *hi)
4586 {
4587 if (!isMeta) return instanceProperties;
4588 else if (hi->info()->hasCategoryClassProperties()) return _classProperties;
4589 else return nil;
4590 }
4591
4592
4593 /***********************************************************************
4594 * class_copyProtocolList
4595 * fixme
4596 * Locking: read-locks runtimeLock
4597 **********************************************************************/
4598 Protocol * __unsafe_unretained *
4599 class_copyProtocolList(Class cls, unsigned int *outCount)
4600 {
4601 unsigned int count = 0;
4602 Protocol **result = nil;
4603
4604 if (!cls) {
4605 if (outCount) *outCount = 0;
4606 return nil;
4607 }
4608
4609 mutex_locker_t lock(runtimeLock);
4610
4611 checkIsKnownClass(cls);
4612
4613 assert(cls->isRealized());
4614
4615 count = cls->data()->protocols.count();
4616
4617 if (count > 0) {
4618 result = (Protocol **)malloc((count+1) * sizeof(Protocol *));
4619
4620 count = 0;
4621 for (const auto& proto : cls->data()->protocols) {
4622 result[count++] = (Protocol *)remapProtocol(proto);
4623 }
4624 result[count] = nil;
4625 }
4626
4627 if (outCount) *outCount = count;
4628 return result;
4629 }
4630
4631
4632 /***********************************************************************
4633 * objc_copyImageNames
4634 * Copies names of loaded images with ObjC contents.
4635 *
4636 * Locking: acquires runtimeLock
4637 **********************************************************************/
4638 const char **objc_copyImageNames(unsigned int *outCount)
4639 {
4640 mutex_locker_t lock(runtimeLock);
4641
4642 #if TARGET_OS_WIN32
4643 const TCHAR **names = (const TCHAR **)
4644 malloc((HeaderCount+1) * sizeof(TCHAR *));
4645 #else
4646 const char **names = (const char **)
4647 malloc((HeaderCount+1) * sizeof(char *));
4648 #endif
4649
4650 unsigned int count = 0;
4651 for (header_info *hi = FirstHeader; hi != nil; hi = hi->getNext()) {
4652 #if TARGET_OS_WIN32
4653 if (hi->moduleName) {
4654 names[count++] = hi->moduleName;
4655 }
4656 #else
4657 const char *fname = hi->fname();
4658 if (fname) {
4659 names[count++] = fname;
4660 }
4661 #endif
4662 }
4663 names[count] = nil;
4664
4665 if (count == 0) {
4666 // Return nil instead of empty list if there are no images
4667 free((void *)names);
4668 names = nil;
4669 }
4670
4671 if (outCount) *outCount = count;
4672 return names;
4673 }
4674
4675
4676 /***********************************************************************
4677 * copyClassNamesForImage_nolock
4678 * Copies class names from the given image.
4679 * Missing weak-import classes are omitted.
4680 * Swift class names are demangled.
4681 *
4682 * Locking: runtimeLock must be held by the caller
4683 **********************************************************************/
4684 const char **
4685 copyClassNamesForImage_nolock(header_info *hi, unsigned int *outCount)
4686 {
4687 runtimeLock.assertLocked();
4688 assert(hi);
4689
4690 size_t count;
4691 classref_t *classlist = _getObjc2ClassList(hi, &count);
4692 const char **names = (const char **)
4693 malloc((count+1) * sizeof(const char *));
4694
4695 size_t shift = 0;
4696 for (size_t i = 0; i < count; i++) {
4697 Class cls = remapClass(classlist[i]);
4698 if (cls) {
4699 names[i-shift] = cls->demangledName();
4700 } else {
4701 shift++; // ignored weak-linked class
4702 }
4703 }
4704 count -= shift;
4705 names[count] = nil;
4706
4707 if (outCount) *outCount = (unsigned int)count;
4708 return names;
4709 }
4710
4711
4712
4713 /***********************************************************************
4714 * objc_copyClassNamesForImage
4715 * Copies class names from the named image.
4716 * The image name must be identical to dladdr's dli_fname value.
4717 * Missing weak-import classes are omitted.
4718 * Swift class names are demangled.
4719 *
4720 * Locking: acquires runtimeLock
4721 **********************************************************************/
4722 const char **
4723 objc_copyClassNamesForImage(const char *image, unsigned int *outCount)
4724 {
4725 if (!image) {
4726 if (outCount) *outCount = 0;
4727 return nil;
4728 }
4729
4730 mutex_locker_t lock(runtimeLock);
4731
4732 // Find the image.
4733 header_info *hi;
4734 for (hi = FirstHeader; hi != nil; hi = hi->getNext()) {
4735 #if TARGET_OS_WIN32
4736 if (0 == wcscmp((TCHAR *)image, hi->moduleName)) break;
4737 #else
4738 if (0 == strcmp(image, hi->fname())) break;
4739 #endif
4740 }
4741
4742 if (!hi) {
4743 if (outCount) *outCount = 0;
4744 return nil;
4745 }
4746
4747 return copyClassNamesForImage_nolock(hi, outCount);
4748 }
4749
4750
4751 /***********************************************************************
4752 * objc_copyClassNamesForImageHeader
4753 * Copies class names from the given image.
4754 * Missing weak-import classes are omitted.
4755 * Swift class names are demangled.
4756 *
4757 * Locking: acquires runtimeLock
4758 **********************************************************************/
4759 const char **
4760 objc_copyClassNamesForImageHeader(const struct mach_header *mh, unsigned int *outCount)
4761 {
4762 if (!mh) {
4763 if (outCount) *outCount = 0;
4764 return nil;
4765 }
4766
4767 mutex_locker_t lock(runtimeLock);
4768
4769 // Find the image.
4770 header_info *hi;
4771 for (hi = FirstHeader; hi != nil; hi = hi->getNext()) {
4772 if (hi->mhdr() == (const headerType *)mh) break;
4773 }
4774
4775 if (!hi) {
4776 if (outCount) *outCount = 0;
4777 return nil;
4778 }
4779
4780 return copyClassNamesForImage_nolock(hi, outCount);
4781 }
4782
4783
4784 /***********************************************************************
4785 * saveTemporaryString
4786 * Save a string in a thread-local FIFO buffer.
4787 * This is suitable for temporary strings generated for logging purposes.
4788 **********************************************************************/
4789 static void
4790 saveTemporaryString(char *str)
4791 {
4792 // Fixed-size FIFO. We free the first string, shift
4793 // the rest, and add the new string to the end.
4794 _objc_pthread_data *data = _objc_fetch_pthread_data(true);
4795 if (data->printableNames[0]) {
4796 free(data->printableNames[0]);
4797 }
4798 int last = countof(data->printableNames) - 1;
4799 for (int i = 0; i < last; i++) {
4800 data->printableNames[i] = data->printableNames[i+1];
4801 }
4802 data->printableNames[last] = str;
4803 }
4804
4805
4806 /***********************************************************************
4807 * objc_class::nameForLogging
4808 * Returns the class's name, suitable for display.
4809 * The returned memory is TEMPORARY. Print it or copy it immediately.
4810 * Locking: none
4811 **********************************************************************/
4812 const char *
4813 objc_class::nameForLogging()
4814 {
4815 // Handle the easy case directly.
4816 if (isRealized() || isFuture()) {
4817 if (data()->demangledName) return data()->demangledName;
4818 }
4819
4820 char *result;
4821
4822 const char *name = mangledName();
4823 char *de = copySwiftV1DemangledName(name);
4824 if (de) result = de;
4825 else result = strdup(name);
4826
4827 saveTemporaryString(result);
4828 return result;
4829 }
4830
4831
4832 /***********************************************************************
4833 * objc_class::demangledName
4834 * If realize=false, the class must already be realized or future.
4835 * Locking: runtimeLock may or may not be held by the caller.
4836 **********************************************************************/
4837 mutex_t DemangleCacheLock;
4838 static NXHashTable *DemangleCache;
4839 const char *
4840 objc_class::demangledName()
4841 {
4842 // Return previously demangled name if available.
4843 if (isRealized() || isFuture()) {
4844 if (data()->demangledName) return data()->demangledName;
4845 }
4846
4847 // Try demangling the mangled name.
4848 const char *mangled = mangledName();
4849 char *de = copySwiftV1DemangledName(mangled);
4850 if (isRealized() || isFuture()) {
4851 // Class is already realized or future.
4852 // Save demangling result in rw data.
4853 // We may not own runtimeLock so use an atomic operation instead.
4854 if (! OSAtomicCompareAndSwapPtrBarrier(nil, (void*)(de ?: mangled),
4855 (void**)&data()->demangledName))
4856 {
4857 if (de) free(de);
4858 }
4859 return data()->demangledName;
4860 }
4861
4862 // Class is not yet realized.
4863 if (!de) {
4864 // Name is not mangled. Return it without caching.
4865 return mangled;
4866 }
4867
4868 // Class is not yet realized and name is mangled.
4869 // Allocate the name but don't save it in the class.
4870 // Save the name in a side cache instead to prevent leaks.
4871 // When the class is actually realized we may allocate a second
4872 // copy of the name, but we don't care.
4873 // (Previously we would try to realize the class now and save the
4874 // name there, but realization is more complicated for Swift classes.)
4875
4876 // Only objc_copyClassNamesForImage() should get here.
4877 // fixme lldb's calls to class_getName() can also get here when
4878 // interrogating the dyld shared cache. (rdar://27258517)
4879 // fixme runtimeLock.assertLocked();
4880 // fixme assert(realize);
4881
4882 char *cached;
4883 {
4884 mutex_locker_t lock(DemangleCacheLock);
4885 if (!DemangleCache) {
4886 DemangleCache = NXCreateHashTable(NXStrPrototype, 0, nil);
4887 }
4888 cached = (char *)NXHashInsertIfAbsent(DemangleCache, de);
4889 }
4890 if (cached != de) free(de);
4891 return cached;
4892 }
4893
4894
4895 /***********************************************************************
4896 * class_getName
4897 * fixme
4898 * Locking: acquires runtimeLock
4899 **********************************************************************/
4900 const char *class_getName(Class cls)
4901 {
4902 if (!cls) return "nil";
4903 // fixme lldb calls class_getName() on unrealized classes (rdar://27258517)
4904 // assert(cls->isRealized() || cls->isFuture());
4905 return cls->demangledName();
4906 }
4907
4908
4909 /***********************************************************************
4910 * class_getVersion
4911 * fixme
4912 * Locking: none
4913 **********************************************************************/
4914 int
4915 class_getVersion(Class cls)
4916 {
4917 if (!cls) return 0;
4918 assert(cls->isRealized());
4919 return cls->data()->version;
4920 }
4921
4922
4923 /***********************************************************************
4924 * class_setVersion
4925 * fixme
4926 * Locking: none
4927 **********************************************************************/
4928 void
4929 class_setVersion(Class cls, int version)
4930 {
4931 if (!cls) return;
4932 assert(cls->isRealized());
4933 cls->data()->version = version;
4934 }
4935
4936
4937 static method_t *findMethodInSortedMethodList(SEL key, const method_list_t *list)
4938 {
4939 assert(list);
4940
4941 const method_t * const first = &list->first;
4942 const method_t *base = first;
4943 const method_t *probe;
4944 uintptr_t keyValue = (uintptr_t)key;
4945 uint32_t count;
4946
4947 for (count = list->count; count != 0; count >>= 1) {
4948 probe = base + (count >> 1);
4949
4950 uintptr_t probeValue = (uintptr_t)probe->name;
4951
4952 if (keyValue == probeValue) {
4953 // `probe` is a match.
4954 // Rewind looking for the *first* occurrence of this value.
4955 // This is required for correct category overrides.
4956 while (probe > first && keyValue == (uintptr_t)probe[-1].name) {
4957 probe--;
4958 }
4959 return (method_t *)probe;
4960 }
4961
4962 if (keyValue > probeValue) {
4963 base = probe + 1;
4964 count--;
4965 }
4966 }
4967
4968 return nil;
4969 }
4970
4971 /***********************************************************************
4972 * getMethodNoSuper_nolock
4973 * fixme
4974 * Locking: runtimeLock must be read- or write-locked by the caller
4975 **********************************************************************/
4976 static method_t *search_method_list(const method_list_t *mlist, SEL sel)
4977 {
4978 int methodListIsFixedUp = mlist->isFixedUp();
4979 int methodListHasExpectedSize = mlist->entsize() == sizeof(method_t);
4980
4981 if (__builtin_expect(methodListIsFixedUp && methodListHasExpectedSize, 1)) {
4982 return findMethodInSortedMethodList(sel, mlist);
4983 } else {
4984 // Linear search of unsorted method list
4985 for (auto& meth : *mlist) {
4986 if (meth.name == sel) return &meth;
4987 }
4988 }
4989
4990 #if DEBUG
4991 // sanity-check negative results
4992 if (mlist->isFixedUp()) {
4993 for (auto& meth : *mlist) {
4994 if (meth.name == sel) {
4995 _objc_fatal("linear search worked when binary search did not");
4996 }
4997 }
4998 }
4999 #endif
5000
5001 return nil;
5002 }
5003
5004 static method_t *
5005 getMethodNoSuper_nolock(Class cls, SEL sel)
5006 {
5007 runtimeLock.assertLocked();
5008
5009 assert(cls->isRealized());
5010 // fixme nil cls?
5011 // fixme nil sel?
5012
5013 for (auto mlists = cls->data()->methods.beginLists(),
5014 end = cls->data()->methods.endLists();
5015 mlists != end;
5016 ++mlists)
5017 {
5018 method_t *m = search_method_list(*mlists, sel);
5019 if (m) return m;
5020 }
5021
5022 return nil;
5023 }
5024
5025
5026 /***********************************************************************
5027 * getMethod_nolock
5028 * fixme
5029 * Locking: runtimeLock must be read- or write-locked by the caller
5030 **********************************************************************/
5031 static method_t *
5032 getMethod_nolock(Class cls, SEL sel)
5033 {
5034 method_t *m = nil;
5035
5036 runtimeLock.assertLocked();
5037
5038 // fixme nil cls?
5039 // fixme nil sel?
5040
5041 assert(cls->isRealized());
5042
5043 while (cls && ((m = getMethodNoSuper_nolock(cls, sel))) == nil) {
5044 cls = cls->superclass;
5045 }
5046
5047 return m;
5048 }
5049
5050
5051 /***********************************************************************
5052 * _class_getMethod
5053 * fixme
5054 * Locking: read-locks runtimeLock
5055 **********************************************************************/
5056 static Method _class_getMethod(Class cls, SEL sel)
5057 {
5058 mutex_locker_t lock(runtimeLock);
5059 return getMethod_nolock(cls, sel);
5060 }
5061
5062
5063 /***********************************************************************
5064 * class_getInstanceMethod. Return the instance method for the
5065 * specified class and selector.
5066 **********************************************************************/
5067 Method class_getInstanceMethod(Class cls, SEL sel)
5068 {
5069 if (!cls || !sel) return nil;
5070
5071 // This deliberately avoids +initialize because it historically did so.
5072
5073 // This implementation is a bit weird because it's the only place that
5074 // wants a Method instead of an IMP.
5075
5076 #warning fixme build and search caches
5077
5078 // Search method lists, try method resolver, etc.
5079 lookUpImpOrNil(cls, sel, nil,
5080 NO/*initialize*/, NO/*cache*/, YES/*resolver*/);
5081
5082 #warning fixme build and search caches
5083
5084 return _class_getMethod(cls, sel);
5085 }
5086
5087
5088 /***********************************************************************
5089 * resolveClassMethod
5090 * Call +resolveClassMethod, looking for a method to be added to class cls.
5091 * cls should be a metaclass.
5092 * Does not check if the method already exists.
5093 **********************************************************************/
5094 static void resolveClassMethod(Class cls, SEL sel, id inst)
5095 {
5096 runtimeLock.assertUnlocked();
5097 assert(cls->isRealized());
5098 assert(cls->isMetaClass());
5099
5100 if (! lookUpImpOrNil(cls, SEL_resolveClassMethod, inst,
5101 NO/*initialize*/, YES/*cache*/, NO/*resolver*/))
5102 {
5103 // Resolver not implemented.
5104 return;
5105 }
5106
5107 Class nonmeta;
5108 {
5109 mutex_locker_t lock(runtimeLock);
5110 nonmeta = getMaybeUnrealizedNonMetaClass(cls, inst);
5111 // +initialize path should have realized nonmeta already
5112 if (!nonmeta->isRealized()) {
5113 _objc_fatal("nonmeta class %s (%p) unexpectedly not realized",
5114 nonmeta->nameForLogging(), nonmeta);
5115 }
5116 }
5117 BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
5118 bool resolved = msg(nonmeta, SEL_resolveClassMethod, sel);
5119
5120 // Cache the result (good or bad) so the resolver doesn't fire next time.
5121 // +resolveClassMethod adds to self->ISA() a.k.a. cls
5122 IMP imp = lookUpImpOrNil(cls, sel, inst,
5123 NO/*initialize*/, YES/*cache*/, NO/*resolver*/);
5124
5125 if (resolved && PrintResolving) {
5126 if (imp) {
5127 _objc_inform("RESOLVE: method %c[%s %s] "
5128 "dynamically resolved to %p",
5129 cls->isMetaClass() ? '+' : '-',
5130 cls->nameForLogging(), sel_getName(sel), imp);
5131 }
5132 else {
5133 // Method resolver didn't add anything?
5134 _objc_inform("RESOLVE: +[%s resolveClassMethod:%s] returned YES"
5135 ", but no new implementation of %c[%s %s] was found",
5136 cls->nameForLogging(), sel_getName(sel),
5137 cls->isMetaClass() ? '+' : '-',
5138 cls->nameForLogging(), sel_getName(sel));
5139 }
5140 }
5141 }
5142
5143
5144 /***********************************************************************
5145 * resolveInstanceMethod
5146 * Call +resolveInstanceMethod, looking for a method to be added to class cls.
5147 * cls may be a metaclass or a non-meta class.
5148 * Does not check if the method already exists.
5149 **********************************************************************/
5150 static void resolveInstanceMethod(Class cls, SEL sel, id inst)
5151 {
5152 runtimeLock.assertUnlocked();
5153 assert(cls->isRealized());
5154
5155 if (! lookUpImpOrNil(cls->ISA(), SEL_resolveInstanceMethod, cls,
5156 NO/*initialize*/, YES/*cache*/, NO/*resolver*/))
5157 {
5158 // Resolver not implemented.
5159 return;
5160 }
5161
5162 BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
5163 bool resolved = msg(cls, SEL_resolveInstanceMethod, sel);
5164
5165 // Cache the result (good or bad) so the resolver doesn't fire next time.
5166 // +resolveInstanceMethod adds to self a.k.a. cls
5167 IMP imp = lookUpImpOrNil(cls, sel, inst,
5168 NO/*initialize*/, YES/*cache*/, NO/*resolver*/);
5169
5170 if (resolved && PrintResolving) {
5171 if (imp) {
5172 _objc_inform("RESOLVE: method %c[%s %s] "
5173 "dynamically resolved to %p",
5174 cls->isMetaClass() ? '+' : '-',
5175 cls->nameForLogging(), sel_getName(sel), imp);
5176 }
5177 else {
5178 // Method resolver didn't add anything?
5179 _objc_inform("RESOLVE: +[%s resolveInstanceMethod:%s] returned YES"
5180 ", but no new implementation of %c[%s %s] was found",
5181 cls->nameForLogging(), sel_getName(sel),
5182 cls->isMetaClass() ? '+' : '-',
5183 cls->nameForLogging(), sel_getName(sel));
5184 }
5185 }
5186 }
5187
5188
5189 /***********************************************************************
5190 * resolveMethod
5191 * Call +resolveClassMethod or +resolveInstanceMethod.
5192 * Returns nothing; any result would be potentially out-of-date already.
5193 * Does not check if the method already exists.
5194 **********************************************************************/
5195 static void resolveMethod(Class cls, SEL sel, id inst)
5196 {
5197 runtimeLock.assertUnlocked();
5198 assert(cls->isRealized());
5199
5200 if (! cls->isMetaClass()) {
5201 // try [cls resolveInstanceMethod:sel]
5202 resolveInstanceMethod(cls, sel, inst);
5203 }
5204 else {
5205 // try [nonMetaClass resolveClassMethod:sel]
5206 // and [cls resolveInstanceMethod:sel]
5207 resolveClassMethod(cls, sel, inst);
5208 if (!lookUpImpOrNil(cls, sel, inst,
5209 NO/*initialize*/, YES/*cache*/, NO/*resolver*/))
5210 {
5211 resolveInstanceMethod(cls, sel, inst);
5212 }
5213 }
5214 }
5215
5216
5217 /***********************************************************************
5218 * log_and_fill_cache
5219 * Log this method call. If the logger permits it, fill the method cache.
5220 * cls is the method whose cache should be filled.
5221 * implementer is the class that owns the implementation in question.
5222 **********************************************************************/
5223 static void
5224 log_and_fill_cache(Class cls, IMP imp, SEL sel, id receiver, Class implementer)
5225 {
5226 #if SUPPORT_MESSAGE_LOGGING
5227 if (objcMsgLogEnabled) {
5228 bool cacheIt = logMessageSend(implementer->isMetaClass(),
5229 cls->nameForLogging(),
5230 implementer->nameForLogging(),
5231 sel);
5232 if (!cacheIt) return;
5233 }
5234 #endif
5235 cache_fill (cls, sel, imp, receiver);
5236 }
5237
5238
5239 /***********************************************************************
5240 * _class_lookupMethodAndLoadCache.
5241 * Method lookup for dispatchers ONLY. OTHER CODE SHOULD USE lookUpImp().
5242 * This lookup avoids optimistic cache scan because the dispatcher
5243 * already tried that.
5244 **********************************************************************/
5245 IMP _class_lookupMethodAndLoadCache3(id obj, SEL sel, Class cls)
5246 {
5247 return lookUpImpOrForward(cls, sel, obj,
5248 YES/*initialize*/, NO/*cache*/, YES/*resolver*/);
5249 }
5250
5251
5252 /***********************************************************************
5253 * lookUpImpOrForward.
5254 * The standard IMP lookup.
5255 * initialize==NO tries to avoid +initialize (but sometimes fails)
5256 * cache==NO skips optimistic unlocked lookup (but uses cache elsewhere)
5257 * Most callers should use initialize==YES and cache==YES.
5258 * inst is an instance of cls or a subclass thereof, or nil if none is known.
5259 * If cls is an un-initialized metaclass then a non-nil inst is faster.
5260 * May return _objc_msgForward_impcache. IMPs destined for external use
5261 * must be converted to _objc_msgForward or _objc_msgForward_stret.
5262 * If you don't want forwarding at all, use lookUpImpOrNil() instead.
5263 **********************************************************************/
5264 IMP lookUpImpOrForward(Class cls, SEL sel, id inst,
5265 bool initialize, bool cache, bool resolver)
5266 {
5267 IMP imp = nil;
5268 bool triedResolver = NO;
5269
5270 runtimeLock.assertUnlocked();
5271
5272 // Optimistic cache lookup
5273 if (cache) {
5274 imp = cache_getImp(cls, sel);
5275 if (imp) return imp;
5276 }
5277
5278 // runtimeLock is held during isRealized and isInitialized checking
5279 // to prevent races against concurrent realization.
5280
5281 // runtimeLock is held during method search to make
5282 // method-lookup + cache-fill atomic with respect to method addition.
5283 // Otherwise, a category could be added but ignored indefinitely because
5284 // the cache was re-filled with the old value after the cache flush on
5285 // behalf of the category.
5286
5287 runtimeLock.lock();
5288 checkIsKnownClass(cls);
5289
5290 if (!cls->isRealized()) {
5291 cls = realizeClassMaybeSwiftAndLeaveLocked(cls, runtimeLock);
5292 // runtimeLock may have been dropped but is now locked again
5293 }
5294
5295 if (initialize && !cls->isInitialized()) {
5296 cls = initializeAndLeaveLocked(cls, inst, runtimeLock);
5297 // runtimeLock may have been dropped but is now locked again
5298
5299 // If sel == initialize, class_initialize will send +initialize and
5300 // then the messenger will send +initialize again after this
5301 // procedure finishes. Of course, if this is not being called
5302 // from the messenger then it won't happen. 2778172
5303 }
5304
5305
5306 retry:
5307 runtimeLock.assertLocked();
5308
5309 // Try this class's cache.
5310
5311 imp = cache_getImp(cls, sel);
5312 if (imp) goto done;
5313
5314 // Try this class's method lists.
5315 {
5316 Method meth = getMethodNoSuper_nolock(cls, sel);
5317 if (meth) {
5318 log_and_fill_cache(cls, meth->imp, sel, inst, cls);
5319 imp = meth->imp;
5320 goto done;
5321 }
5322 }
5323
5324 // Try superclass caches and method lists.
5325 {
5326 unsigned attempts = unreasonableClassCount();
5327 for (Class curClass = cls->superclass;
5328 curClass != nil;
5329 curClass = curClass->superclass)
5330 {
5331 // Halt if there is a cycle in the superclass chain.
5332 if (--attempts == 0) {
5333 _objc_fatal("Memory corruption in class list.");
5334 }
5335
5336 // Superclass cache.
5337 imp = cache_getImp(curClass, sel);
5338 if (imp) {
5339 if (imp != (IMP)_objc_msgForward_impcache) {
5340 // Found the method in a superclass. Cache it in this class.
5341 log_and_fill_cache(cls, imp, sel, inst, curClass);
5342 goto done;
5343 }
5344 else {
5345 // Found a forward:: entry in a superclass.
5346 // Stop searching, but don't cache yet; call method
5347 // resolver for this class first.
5348 break;
5349 }
5350 }
5351
5352 // Superclass method list.
5353 Method meth = getMethodNoSuper_nolock(curClass, sel);
5354 if (meth) {
5355 log_and_fill_cache(cls, meth->imp, sel, inst, curClass);
5356 imp = meth->imp;
5357 goto done;
5358 }
5359 }
5360 }
5361
5362 // No implementation found. Try method resolver once.
5363
5364 if (resolver && !triedResolver) {
5365 runtimeLock.unlock();
5366 resolveMethod(cls, sel, inst);
5367 runtimeLock.lock();
5368 // Don't cache the result; we don't hold the lock so it may have
5369 // changed already. Re-do the search from scratch instead.
5370 triedResolver = YES;
5371 goto retry;
5372 }
5373
5374 // No implementation found, and method resolver didn't help.
5375 // Use forwarding.
5376
5377 imp = (IMP)_objc_msgForward_impcache;
5378 cache_fill(cls, sel, imp, inst);
5379
5380 done:
5381 runtimeLock.unlock();
5382
5383 return imp;
5384 }
5385
5386
5387 /***********************************************************************
5388 * lookUpImpOrNil.
5389 * Like lookUpImpOrForward, but returns nil instead of _objc_msgForward_impcache
5390 **********************************************************************/
5391 IMP lookUpImpOrNil(Class cls, SEL sel, id inst,
5392 bool initialize, bool cache, bool resolver)
5393 {
5394 IMP imp = lookUpImpOrForward(cls, sel, inst, initialize, cache, resolver);
5395 if (imp == _objc_msgForward_impcache) return nil;
5396 else return imp;
5397 }
5398
5399
5400 /***********************************************************************
5401 * lookupMethodInClassAndLoadCache.
5402 * Like _class_lookupMethodAndLoadCache, but does not search superclasses.
5403 * Caches and returns objc_msgForward if the method is not found in the class.
5404 **********************************************************************/
5405 IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel)
5406 {
5407 Method meth;
5408 IMP imp;
5409
5410 // fixme this is incomplete - no resolver, +initialize -
5411 // but it's only used for .cxx_construct/destruct so we don't care
5412 assert(sel == SEL_cxx_construct || sel == SEL_cxx_destruct);
5413
5414 // Search cache first.
5415 imp = cache_getImp(cls, sel);
5416 if (imp) return imp;
5417
5418 // Cache miss. Search method list.
5419
5420 mutex_locker_t lock(runtimeLock);
5421
5422 meth = getMethodNoSuper_nolock(cls, sel);
5423
5424 if (meth) {
5425 // Hit in method list. Cache it.
5426 cache_fill(cls, sel, meth->imp, nil);
5427 return meth->imp;
5428 } else {
5429 // Miss in method list. Cache objc_msgForward.
5430 cache_fill(cls, sel, _objc_msgForward_impcache, nil);
5431 return _objc_msgForward_impcache;
5432 }
5433 }
5434
5435
5436 /***********************************************************************
5437 * class_getProperty
5438 * fixme
5439 * Locking: read-locks runtimeLock
5440 **********************************************************************/
5441 objc_property_t class_getProperty(Class cls, const char *name)
5442 {
5443 if (!cls || !name) return nil;
5444
5445 mutex_locker_t lock(runtimeLock);
5446
5447 checkIsKnownClass(cls);
5448
5449 assert(cls->isRealized());
5450
5451 for ( ; cls; cls = cls->superclass) {
5452 for (auto& prop : cls->data()->properties) {
5453 if (0 == strcmp(name, prop.name)) {
5454 return (objc_property_t)&prop;
5455 }
5456 }
5457 }
5458
5459 return nil;
5460 }
5461
5462
5463 /***********************************************************************
5464 * Locking: fixme
5465 **********************************************************************/
5466
5467 Class gdb_class_getClass(Class cls)
5468 {
5469 const char *className = cls->mangledName();
5470 if(!className || !strlen(className)) return Nil;
5471 Class rCls = look_up_class(className, NO, NO);
5472 return rCls;
5473 }
5474
5475 Class gdb_object_getClass(id obj)
5476 {
5477 if (!obj) return nil;
5478 return gdb_class_getClass(obj->getIsa());
5479 }
5480
5481
5482 /***********************************************************************
5483 * Locking: write-locks runtimeLock
5484 **********************************************************************/
5485 void
5486 objc_class::setInitialized()
5487 {
5488 Class metacls;
5489 Class cls;
5490
5491 assert(!isMetaClass());
5492
5493 cls = (Class)this;
5494 metacls = cls->ISA();
5495
5496 mutex_locker_t lock(runtimeLock);
5497
5498 // Scan metaclass for custom AWZ.
5499 // Scan metaclass for custom RR.
5500 // Scan class for custom RR.
5501 // Also print custom RR/AWZ because we probably haven't done it yet.
5502
5503 // Special cases:
5504 // NSObject AWZ class methods are default.
5505 // NSObject RR instance methods are default.
5506 // updateCustomRR_AWZ() also knows these special cases.
5507 // attachMethodLists() also knows these special cases.
5508
5509 bool inherited;
5510 bool metaCustomAWZ = NO;
5511 if (MetaclassNSObjectAWZSwizzled) {
5512 // Somebody already swizzled NSObject's methods
5513 metaCustomAWZ = YES;
5514 inherited = NO;
5515 }
5516 else if (metacls == classNSObject()->ISA()) {
5517 // NSObject's metaclass AWZ is default, but we still need to check cats
5518 auto& methods = metacls->data()->methods;
5519 for (auto mlists = methods.beginCategoryMethodLists(),
5520 end = methods.endCategoryMethodLists(metacls);
5521 mlists != end;
5522 ++mlists)
5523 {
5524 if (methodListImplementsAWZ(*mlists)) {
5525 metaCustomAWZ = YES;
5526 inherited = NO;
5527 break;
5528 }
5529 }
5530 }
5531 else if (metacls->superclass->hasCustomAWZ()) {
5532 // Superclass is custom AWZ, therefore we are too.
5533 metaCustomAWZ = YES;
5534 inherited = YES;
5535 }
5536 else {
5537 // Not metaclass NSObject.
5538 auto& methods = metacls->data()->methods;
5539 for (auto mlists = methods.beginLists(),
5540 end = methods.endLists();
5541 mlists != end;
5542 ++mlists)
5543 {
5544 if (methodListImplementsAWZ(*mlists)) {
5545 metaCustomAWZ = YES;
5546 inherited = NO;
5547 break;
5548 }
5549 }
5550 }
5551 if (!metaCustomAWZ) metacls->setHasDefaultAWZ();
5552
5553 if (PrintCustomAWZ && metaCustomAWZ) metacls->printCustomAWZ(inherited);
5554 // metacls->printCustomRR();
5555
5556
5557 bool clsCustomRR = NO;
5558 if (ClassNSObjectRRSwizzled) {
5559 // Somebody already swizzled NSObject's methods
5560 clsCustomRR = YES;
5561 inherited = NO;
5562 }
5563 if (cls == classNSObject()) {
5564 // NSObject's RR is default, but we still need to check categories
5565 auto& methods = cls->data()->methods;
5566 for (auto mlists = methods.beginCategoryMethodLists(),
5567 end = methods.endCategoryMethodLists(cls);
5568 mlists != end;
5569 ++mlists)
5570 {
5571 if (methodListImplementsRR(*mlists)) {
5572 clsCustomRR = YES;
5573 inherited = NO;
5574 break;
5575 }
5576 }
5577 }
5578 else if (!cls->superclass) {
5579 // Custom root class
5580 clsCustomRR = YES;
5581 inherited = NO;
5582 }
5583 else if (cls->superclass->hasCustomRR()) {
5584 // Superclass is custom RR, therefore we are too.
5585 clsCustomRR = YES;
5586 inherited = YES;
5587 }
5588 else {
5589 // Not class NSObject.
5590 auto& methods = cls->data()->methods;
5591 for (auto mlists = methods.beginLists(),
5592 end = methods.endLists();
5593 mlists != end;
5594 ++mlists)
5595 {
5596 if (methodListImplementsRR(*mlists)) {
5597 clsCustomRR = YES;
5598 inherited = NO;
5599 break;
5600 }
5601 }
5602 }
5603 if (!clsCustomRR) cls->setHasDefaultRR();
5604
5605 // cls->printCustomAWZ();
5606 if (PrintCustomRR && clsCustomRR) cls->printCustomRR(inherited);
5607
5608 // Update the +initialize flags.
5609 // Do this last.
5610 metacls->changeInfo(RW_INITIALIZED, RW_INITIALIZING);
5611 }
5612
5613
5614 /***********************************************************************
5615 * Return YES if sel is used by retain/release implementors
5616 **********************************************************************/
5617 static bool
5618 isRRSelector(SEL sel)
5619 {
5620 return (sel == SEL_retain || sel == SEL_release ||
5621 sel == SEL_autorelease || sel == SEL_retainCount ||
5622 sel == SEL_tryRetain || sel == SEL_retainWeakReference ||
5623 sel == SEL_isDeallocating || sel == SEL_allowsWeakReference);
5624 }
5625
5626
5627 /***********************************************************************
5628 * Return YES if mlist implements one of the isRRSelector() methods
5629 **********************************************************************/
5630 static bool
5631 methodListImplementsRR(const method_list_t *mlist)
5632 {
5633 return (search_method_list(mlist, SEL_retain) ||
5634 search_method_list(mlist, SEL_release) ||
5635 search_method_list(mlist, SEL_autorelease) ||
5636 search_method_list(mlist, SEL_retainCount) ||
5637 search_method_list(mlist, SEL_tryRetain) ||
5638 search_method_list(mlist, SEL_isDeallocating) ||
5639 search_method_list(mlist, SEL_retainWeakReference) ||
5640 search_method_list(mlist, SEL_allowsWeakReference));
5641 }
5642
5643
5644 /***********************************************************************
5645 * Return YES if sel is used by alloc or allocWithZone implementors
5646 **********************************************************************/
5647 static bool
5648 isAWZSelector(SEL sel)
5649 {
5650 return (sel == SEL_allocWithZone || sel == SEL_alloc);
5651 }
5652
5653
5654 /***********************************************************************
5655 * Return YES if mlist implements one of the isAWZSelector() methods
5656 **********************************************************************/
5657 static bool
5658 methodListImplementsAWZ(const method_list_t *mlist)
5659 {
5660 return (search_method_list(mlist, SEL_allocWithZone) ||
5661 search_method_list(mlist, SEL_alloc));
5662 }
5663
5664
5665 void
5666 objc_class::printCustomRR(bool inherited)
5667 {
5668 assert(PrintCustomRR);
5669 assert(hasCustomRR());
5670 _objc_inform("CUSTOM RR: %s%s%s", nameForLogging(),
5671 isMetaClass() ? " (meta)" : "",
5672 inherited ? " (inherited)" : "");
5673 }
5674
5675 void
5676 objc_class::printCustomAWZ(bool inherited)
5677 {
5678 assert(PrintCustomAWZ);
5679 assert(hasCustomAWZ());
5680 _objc_inform("CUSTOM AWZ: %s%s%s", nameForLogging(),
5681 isMetaClass() ? " (meta)" : "",
5682 inherited ? " (inherited)" : "");
5683 }
5684
5685 void
5686 objc_class::printInstancesRequireRawIsa(bool inherited)
5687 {
5688 assert(PrintRawIsa);
5689 assert(instancesRequireRawIsa());
5690 _objc_inform("RAW ISA: %s%s%s", nameForLogging(),
5691 isMetaClass() ? " (meta)" : "",
5692 inherited ? " (inherited)" : "");
5693 }
5694
5695
5696 /***********************************************************************
5697 * Mark this class and all of its subclasses as implementors or
5698 * inheritors of custom RR (retain/release/autorelease/retainCount)
5699 **********************************************************************/
5700 void objc_class::setHasCustomRR(bool inherited)
5701 {
5702 Class cls = (Class)this;
5703 runtimeLock.assertLocked();
5704
5705 if (hasCustomRR()) return;
5706
5707 foreach_realized_class_and_subclass(cls, ^(Class c){
5708 if (c != cls && !c->isInitialized()) {
5709 // Subclass not yet initialized. Wait for setInitialized() to do it
5710 // fixme short circuit recursion?
5711 return;
5712 }
5713 if (c->hasCustomRR()) {
5714 // fixme short circuit recursion?
5715 return;
5716 }
5717
5718 c->bits.setHasCustomRR();
5719
5720 if (PrintCustomRR) c->printCustomRR(inherited || c != cls);
5721 });
5722 }
5723
5724 /***********************************************************************
5725 * Mark this class and all of its subclasses as implementors or
5726 * inheritors of custom alloc/allocWithZone:
5727 **********************************************************************/
5728 void objc_class::setHasCustomAWZ(bool inherited)
5729 {
5730 Class cls = (Class)this;
5731 runtimeLock.assertLocked();
5732
5733 if (hasCustomAWZ()) return;
5734
5735 foreach_realized_class_and_subclass(cls, ^(Class c){
5736 if (c != cls && !c->isInitialized()) {
5737 // Subclass not yet initialized. Wait for setInitialized() to do it
5738 // fixme short circuit recursion?
5739 return;
5740 }
5741 if (c->hasCustomAWZ()) {
5742 // fixme short circuit recursion?
5743 return;
5744 }
5745
5746 c->bits.setHasCustomAWZ();
5747
5748 if (PrintCustomAWZ) c->printCustomAWZ(inherited || c != cls);
5749 });
5750 }
5751
5752
5753 /***********************************************************************
5754 * Mark this class and all of its subclasses as requiring raw isa pointers
5755 **********************************************************************/
5756 void objc_class::setInstancesRequireRawIsa(bool inherited)
5757 {
5758 Class cls = (Class)this;
5759 runtimeLock.assertLocked();
5760
5761 if (instancesRequireRawIsa()) return;
5762
5763 foreach_realized_class_and_subclass(cls, ^(Class c){
5764 if (c->instancesRequireRawIsa()) {
5765 // fixme short circuit recursion?
5766 return;
5767 }
5768
5769 c->bits.setInstancesRequireRawIsa();
5770
5771 if (PrintRawIsa) c->printInstancesRequireRawIsa(inherited || c != cls);
5772 });
5773 }
5774
5775
5776 /***********************************************************************
5777 * Choose a class index.
5778 * Set instancesRequireRawIsa if no more class indexes are available.
5779 **********************************************************************/
5780 void objc_class::chooseClassArrayIndex()
5781 {
5782 #if SUPPORT_INDEXED_ISA
5783 Class cls = (Class)this;
5784 runtimeLock.assertLocked();
5785
5786 if (objc_indexed_classes_count >= ISA_INDEX_COUNT) {
5787 // No more indexes available.
5788 assert(cls->classArrayIndex() == 0);
5789 cls->setInstancesRequireRawIsa(false/*not inherited*/);
5790 return;
5791 }
5792
5793 unsigned index = objc_indexed_classes_count++;
5794 if (index == 0) index = objc_indexed_classes_count++; // index 0 is unused
5795 classForIndex(index) = cls;
5796 cls->setClassArrayIndex(index);
5797 #endif
5798 }
5799
5800
5801 /***********************************************************************
5802 * Update custom RR and AWZ when a method changes its IMP
5803 **********************************************************************/
5804 static void
5805 updateCustomRR_AWZ(Class cls, method_t *meth)
5806 {
5807 // In almost all cases, IMP swizzling does not affect custom RR/AWZ bits.
5808 // Custom RR/AWZ search will already find the method whether or not
5809 // it is swizzled, so it does not transition from non-custom to custom.
5810 //
5811 // The only cases where IMP swizzling can affect the RR/AWZ bits is
5812 // if the swizzled method is one of the methods that is assumed to be
5813 // non-custom. These special cases are listed in setInitialized().
5814 // We look for such cases here.
5815
5816 if (isRRSelector(meth->name)) {
5817
5818 if ((classNSObject()->isInitialized() &&
5819 classNSObject()->hasCustomRR())
5820 ||
5821 ClassNSObjectRRSwizzled)
5822 {
5823 // already custom, nothing would change
5824 return;
5825 }
5826
5827 bool swizzlingNSObject = NO;
5828 if (cls == classNSObject()) {
5829 swizzlingNSObject = YES;
5830 } else {
5831 // Don't know the class.
5832 // The only special case is class NSObject.
5833 for (const auto& meth2 : classNSObject()->data()->methods) {
5834 if (meth == &meth2) {
5835 swizzlingNSObject = YES;
5836 break;
5837 }
5838 }
5839 }
5840 if (swizzlingNSObject) {
5841 if (classNSObject()->isInitialized()) {
5842 classNSObject()->setHasCustomRR();
5843 } else {
5844 // NSObject not yet +initialized, so custom RR has not yet
5845 // been checked, and setInitialized() will not notice the
5846 // swizzle.
5847 ClassNSObjectRRSwizzled = YES;
5848 }
5849 }
5850 }
5851 else if (isAWZSelector(meth->name)) {
5852 Class metaclassNSObject = classNSObject()->ISA();
5853
5854 if ((metaclassNSObject->isInitialized() &&
5855 metaclassNSObject->hasCustomAWZ())
5856 ||
5857 MetaclassNSObjectAWZSwizzled)
5858 {
5859 // already custom, nothing would change
5860 return;
5861 }
5862
5863 bool swizzlingNSObject = NO;
5864 if (cls == metaclassNSObject) {
5865 swizzlingNSObject = YES;
5866 } else {
5867 // Don't know the class.
5868 // The only special case is metaclass NSObject.
5869 for (const auto& meth2 : metaclassNSObject->data()->methods) {
5870 if (meth == &meth2) {
5871 swizzlingNSObject = YES;
5872 break;
5873 }
5874 }
5875 }
5876 if (swizzlingNSObject) {
5877 if (metaclassNSObject->isInitialized()) {
5878 metaclassNSObject->setHasCustomAWZ();
5879 } else {
5880 // NSObject not yet +initialized, so custom RR has not yet
5881 // been checked, and setInitialized() will not notice the
5882 // swizzle.
5883 MetaclassNSObjectAWZSwizzled = YES;
5884 }
5885 }
5886 }
5887 }
5888
5889
5890 /***********************************************************************
5891 * class_getIvarLayout
5892 * Called by the garbage collector.
5893 * The class must be nil or already realized.
5894 * Locking: none
5895 **********************************************************************/
5896 const uint8_t *
5897 class_getIvarLayout(Class cls)
5898 {
5899 if (cls) return cls->data()->ro->ivarLayout;
5900 else return nil;
5901 }
5902
5903
5904 /***********************************************************************
5905 * class_getWeakIvarLayout
5906 * Called by the garbage collector.
5907 * The class must be nil or already realized.
5908 * Locking: none
5909 **********************************************************************/
5910 const uint8_t *
5911 class_getWeakIvarLayout(Class cls)
5912 {
5913 if (cls) return cls->data()->ro->weakIvarLayout;
5914 else return nil;
5915 }
5916
5917
5918 /***********************************************************************
5919 * class_setIvarLayout
5920 * Changes the class's ivar layout.
5921 * nil layout means no unscanned ivars
5922 * The class must be under construction.
5923 * fixme: sanity-check layout vs instance size?
5924 * fixme: sanity-check layout vs superclass?
5925 * Locking: acquires runtimeLock
5926 **********************************************************************/
5927 void
5928 class_setIvarLayout(Class cls, const uint8_t *layout)
5929 {
5930 if (!cls) return;
5931
5932 mutex_locker_t lock(runtimeLock);
5933
5934 checkIsKnownClass(cls);
5935
5936 // Can only change layout of in-construction classes.
5937 // note: if modifications to post-construction classes were
5938 // allowed, there would be a race below (us vs. concurrent object_setIvar)
5939 if (!(cls->data()->flags & RW_CONSTRUCTING)) {
5940 _objc_inform("*** Can't set ivar layout for already-registered "
5941 "class '%s'", cls->nameForLogging());
5942 return;
5943 }
5944
5945 class_ro_t *ro_w = make_ro_writeable(cls->data());
5946
5947 try_free(ro_w->ivarLayout);
5948 ro_w->ivarLayout = ustrdupMaybeNil(layout);
5949 }
5950
5951
5952 /***********************************************************************
5953 * class_setWeakIvarLayout
5954 * Changes the class's weak ivar layout.
5955 * nil layout means no weak ivars
5956 * The class must be under construction.
5957 * fixme: sanity-check layout vs instance size?
5958 * fixme: sanity-check layout vs superclass?
5959 * Locking: acquires runtimeLock
5960 **********************************************************************/
5961 void
5962 class_setWeakIvarLayout(Class cls, const uint8_t *layout)
5963 {
5964 if (!cls) return;
5965
5966 mutex_locker_t lock(runtimeLock);
5967
5968 checkIsKnownClass(cls);
5969
5970 // Can only change layout of in-construction classes.
5971 // note: if modifications to post-construction classes were
5972 // allowed, there would be a race below (us vs. concurrent object_setIvar)
5973 if (!(cls->data()->flags & RW_CONSTRUCTING)) {
5974 _objc_inform("*** Can't set weak ivar layout for already-registered "
5975 "class '%s'", cls->nameForLogging());
5976 return;
5977 }
5978
5979 class_ro_t *ro_w = make_ro_writeable(cls->data());
5980
5981 try_free(ro_w->weakIvarLayout);
5982 ro_w->weakIvarLayout = ustrdupMaybeNil(layout);
5983 }
5984
5985
5986 /***********************************************************************
5987 * getIvar
5988 * Look up an ivar by name.
5989 * Locking: runtimeLock must be read- or write-locked by the caller.
5990 **********************************************************************/
5991 static ivar_t *getIvar(Class cls, const char *name)
5992 {
5993 runtimeLock.assertLocked();
5994
5995 const ivar_list_t *ivars;
5996 assert(cls->isRealized());
5997 if ((ivars = cls->data()->ro->ivars)) {
5998 for (auto& ivar : *ivars) {
5999 if (!ivar.offset) continue; // anonymous bitfield
6000
6001 // ivar.name may be nil for anonymous bitfields etc.
6002 if (ivar.name && 0 == strcmp(name, ivar.name)) {
6003 return &ivar;
6004 }
6005 }
6006 }
6007
6008 return nil;
6009 }
6010
6011
6012 /***********************************************************************
6013 * _class_getClassForIvar
6014 * Given a class and an ivar that is in it or one of its superclasses,
6015 * find the actual class that defined the ivar.
6016 **********************************************************************/
6017 Class _class_getClassForIvar(Class cls, Ivar ivar)
6018 {
6019 mutex_locker_t lock(runtimeLock);
6020
6021 for ( ; cls; cls = cls->superclass) {
6022 if (auto ivars = cls->data()->ro->ivars) {
6023 if (ivars->containsIvar(ivar)) {
6024 return cls;
6025 }
6026 }
6027 }
6028
6029 return nil;
6030 }
6031
6032
6033 /***********************************************************************
6034 * _class_getVariable
6035 * fixme
6036 * Locking: read-locks runtimeLock
6037 **********************************************************************/
6038 Ivar
6039 _class_getVariable(Class cls, const char *name)
6040 {
6041 mutex_locker_t lock(runtimeLock);
6042
6043 for ( ; cls; cls = cls->superclass) {
6044 ivar_t *ivar = getIvar(cls, name);
6045 if (ivar) {
6046 return ivar;
6047 }
6048 }
6049
6050 return nil;
6051 }
6052
6053
6054 /***********************************************************************
6055 * class_conformsToProtocol
6056 * fixme
6057 * Locking: read-locks runtimeLock
6058 **********************************************************************/
6059 BOOL class_conformsToProtocol(Class cls, Protocol *proto_gen)
6060 {
6061 protocol_t *proto = newprotocol(proto_gen);
6062
6063 if (!cls) return NO;
6064 if (!proto_gen) return NO;
6065
6066 mutex_locker_t lock(runtimeLock);
6067
6068 checkIsKnownClass(cls);
6069
6070 assert(cls->isRealized());
6071
6072 for (const auto& proto_ref : cls->data()->protocols) {
6073 protocol_t *p = remapProtocol(proto_ref);
6074 if (p == proto || protocol_conformsToProtocol_nolock(p, proto)) {
6075 return YES;
6076 }
6077 }
6078
6079 return NO;
6080 }
6081
6082
6083 /**********************************************************************
6084 * addMethod
6085 * fixme
6086 * Locking: runtimeLock must be held by the caller
6087 **********************************************************************/
6088 static IMP
6089 addMethod(Class cls, SEL name, IMP imp, const char *types, bool replace)
6090 {
6091 IMP result = nil;
6092
6093 runtimeLock.assertLocked();
6094
6095 checkIsKnownClass(cls);
6096
6097 assert(types);
6098 assert(cls->isRealized());
6099
6100 method_t *m;
6101 if ((m = getMethodNoSuper_nolock(cls, name))) {
6102 // already exists
6103 if (!replace) {
6104 result = m->imp;
6105 } else {
6106 result = _method_setImplementation(cls, m, imp);
6107 }
6108 } else {
6109 // fixme optimize
6110 method_list_t *newlist;
6111 newlist = (method_list_t *)calloc(sizeof(*newlist), 1);
6112 newlist->entsizeAndFlags =
6113 (uint32_t)sizeof(method_t) | fixed_up_method_list;
6114 newlist->count = 1;
6115 newlist->first.name = name;
6116 newlist->first.types = strdupIfMutable(types);
6117 newlist->first.imp = imp;
6118
6119 prepareMethodLists(cls, &newlist, 1, NO, NO);
6120 cls->data()->methods.attachLists(&newlist, 1);
6121 flushCaches(cls);
6122
6123 result = nil;
6124 }
6125
6126 return result;
6127 }
6128
6129 /**********************************************************************
6130 * addMethods
6131 * Add the given methods to a class in bulk.
6132 * Returns the selectors which could not be added, when replace == NO and a
6133 * method already exists. The returned selectors are NULL terminated and must be
6134 * freed by the caller. They are NULL if no failures occurred.
6135 * Locking: runtimeLock must be held by the caller
6136 **********************************************************************/
6137 static SEL *
6138 addMethods(Class cls, const SEL *names, const IMP *imps, const char **types,
6139 uint32_t count, bool replace, uint32_t *outFailedCount)
6140 {
6141 runtimeLock.assertLocked();
6142
6143 assert(names);
6144 assert(imps);
6145 assert(types);
6146 assert(cls->isRealized());
6147
6148 method_list_t *newlist;
6149 size_t newlistSize = method_list_t::byteSize(sizeof(method_t), count);
6150 newlist = (method_list_t *)calloc(newlistSize, 1);
6151 newlist->entsizeAndFlags =
6152 (uint32_t)sizeof(method_t) | fixed_up_method_list;
6153 newlist->count = 0;
6154
6155 method_t *newlistMethods = &newlist->first;
6156
6157 SEL *failedNames = nil;
6158 uint32_t failedCount = 0;
6159
6160 for (uint32_t i = 0; i < count; i++) {
6161 method_t *m;
6162 if ((m = getMethodNoSuper_nolock(cls, names[i]))) {
6163 // already exists
6164 if (!replace) {
6165 // report failure
6166 if (failedNames == nil) {
6167 // allocate an extra entry for a trailing NULL in case
6168 // every method fails
6169 failedNames = (SEL *)calloc(sizeof(*failedNames),
6170 count + 1);
6171 }
6172 failedNames[failedCount] = m->name;
6173 failedCount++;
6174 } else {
6175 _method_setImplementation(cls, m, imps[i]);
6176 }
6177 } else {
6178 method_t *newmethod = &newlistMethods[newlist->count];
6179 newmethod->name = names[i];
6180 newmethod->types = strdupIfMutable(types[i]);
6181 newmethod->imp = imps[i];
6182 newlist->count++;
6183 }
6184 }
6185
6186 if (newlist->count > 0) {
6187 // fixme resize newlist because it may have been over-allocated above.
6188 // Note that realloc() alone doesn't work due to ptrauth.
6189
6190 method_t::SortBySELAddress sorter;
6191 std::stable_sort(newlist->begin(), newlist->end(), sorter);
6192
6193 prepareMethodLists(cls, &newlist, 1, NO, NO);
6194 cls->data()->methods.attachLists(&newlist, 1);
6195 flushCaches(cls);
6196 } else {
6197 // Attaching the method list to the class consumes it. If we don't
6198 // do that, we have to free the memory ourselves.
6199 free(newlist);
6200 }
6201
6202 if (outFailedCount) *outFailedCount = failedCount;
6203
6204 return failedNames;
6205 }
6206
6207
6208 BOOL
6209 class_addMethod(Class cls, SEL name, IMP imp, const char *types)
6210 {
6211 if (!cls) return NO;
6212
6213 mutex_locker_t lock(runtimeLock);
6214 return ! addMethod(cls, name, imp, types ?: "", NO);
6215 }
6216
6217
6218 IMP
6219 class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
6220 {
6221 if (!cls) return nil;
6222
6223 mutex_locker_t lock(runtimeLock);
6224 return addMethod(cls, name, imp, types ?: "", YES);
6225 }
6226
6227
6228 SEL *
6229 class_addMethodsBulk(Class cls, const SEL *names, const IMP *imps,
6230 const char **types, uint32_t count,
6231 uint32_t *outFailedCount)
6232 {
6233 if (!cls) {
6234 if (outFailedCount) *outFailedCount = count;
6235 return (SEL *)memdup(names, count * sizeof(*names));
6236 }
6237
6238 mutex_locker_t lock(runtimeLock);
6239 return addMethods(cls, names, imps, types, count, NO, outFailedCount);
6240 }
6241
6242 void
6243 class_replaceMethodsBulk(Class cls, const SEL *names, const IMP *imps,
6244 const char **types, uint32_t count)
6245 {
6246 if (!cls) return;
6247
6248 mutex_locker_t lock(runtimeLock);
6249 addMethods(cls, names, imps, types, count, YES, nil);
6250 }
6251
6252
6253 /***********************************************************************
6254 * class_addIvar
6255 * Adds an ivar to a class.
6256 * Locking: acquires runtimeLock
6257 **********************************************************************/
6258 BOOL
6259 class_addIvar(Class cls, const char *name, size_t size,
6260 uint8_t alignment, const char *type)
6261 {
6262 if (!cls) return NO;
6263
6264 if (!type) type = "";
6265 if (name && 0 == strcmp(name, "")) name = nil;
6266
6267 mutex_locker_t lock(runtimeLock);
6268
6269 checkIsKnownClass(cls);
6270 assert(cls->isRealized());
6271
6272 // No class variables
6273 if (cls->isMetaClass()) {
6274 return NO;
6275 }
6276
6277 // Can only add ivars to in-construction classes.
6278 if (!(cls->data()->flags & RW_CONSTRUCTING)) {
6279 return NO;
6280 }
6281
6282 // Check for existing ivar with this name, unless it's anonymous.
6283 // Check for too-big ivar.
6284 // fixme check for superclass ivar too?
6285 if ((name && getIvar(cls, name)) || size > UINT32_MAX) {
6286 return NO;
6287 }
6288
6289 class_ro_t *ro_w = make_ro_writeable(cls->data());
6290
6291 // fixme allocate less memory here
6292
6293 ivar_list_t *oldlist, *newlist;
6294 if ((oldlist = (ivar_list_t *)cls->data()->ro->ivars)) {
6295 size_t oldsize = oldlist->byteSize();
6296 newlist = (ivar_list_t *)calloc(oldsize + oldlist->entsize(), 1);
6297 memcpy(newlist, oldlist, oldsize);
6298 free(oldlist);
6299 } else {
6300 newlist = (ivar_list_t *)calloc(sizeof(ivar_list_t), 1);
6301 newlist->entsizeAndFlags = (uint32_t)sizeof(ivar_t);
6302 }
6303
6304 uint32_t offset = cls->unalignedInstanceSize();
6305 uint32_t alignMask = (1<<alignment)-1;
6306 offset = (offset + alignMask) & ~alignMask;
6307
6308 ivar_t& ivar = newlist->get(newlist->count++);
6309 #if __x86_64__
6310 // Deliberately over-allocate the ivar offset variable.
6311 // Use calloc() to clear all 64 bits. See the note in struct ivar_t.
6312 ivar.offset = (int32_t *)(int64_t *)calloc(sizeof(int64_t), 1);
6313 #else
6314 ivar.offset = (int32_t *)malloc(sizeof(int32_t));
6315 #endif
6316 *ivar.offset = offset;
6317 ivar.name = name ? strdupIfMutable(name) : nil;
6318 ivar.type = strdupIfMutable(type);
6319 ivar.alignment_raw = alignment;
6320 ivar.size = (uint32_t)size;
6321
6322 ro_w->ivars = newlist;
6323 cls->setInstanceSize((uint32_t)(offset + size));
6324
6325 // Ivar layout updated in registerClass.
6326
6327 return YES;
6328 }
6329
6330
6331 /***********************************************************************
6332 * class_addProtocol
6333 * Adds a protocol to a class.
6334 * Locking: acquires runtimeLock
6335 **********************************************************************/
6336 BOOL class_addProtocol(Class cls, Protocol *protocol_gen)
6337 {
6338 protocol_t *protocol = newprotocol(protocol_gen);
6339
6340 if (!cls) return NO;
6341 if (class_conformsToProtocol(cls, protocol_gen)) return NO;
6342
6343 mutex_locker_t lock(runtimeLock);
6344
6345 assert(cls->isRealized());
6346
6347 // fixme optimize
6348 protocol_list_t *protolist = (protocol_list_t *)
6349 malloc(sizeof(protocol_list_t) + sizeof(protocol_t *));
6350 protolist->count = 1;
6351 protolist->list[0] = (protocol_ref_t)protocol;
6352
6353 cls->data()->protocols.attachLists(&protolist, 1);
6354
6355 // fixme metaclass?
6356
6357 return YES;
6358 }
6359
6360
6361 /***********************************************************************
6362 * class_addProperty
6363 * Adds a property to a class.
6364 * Locking: acquires runtimeLock
6365 **********************************************************************/
6366 static bool
6367 _class_addProperty(Class cls, const char *name,
6368 const objc_property_attribute_t *attrs, unsigned int count,
6369 bool replace)
6370 {
6371 if (!cls) return NO;
6372 if (!name) return NO;
6373
6374 property_t *prop = class_getProperty(cls, name);
6375 if (prop && !replace) {
6376 // already exists, refuse to replace
6377 return NO;
6378 }
6379 else if (prop) {
6380 // replace existing
6381 mutex_locker_t lock(runtimeLock);
6382 try_free(prop->attributes);
6383 prop->attributes = copyPropertyAttributeString(attrs, count);
6384 return YES;
6385 }
6386 else {
6387 mutex_locker_t lock(runtimeLock);
6388
6389 assert(cls->isRealized());
6390
6391 property_list_t *proplist = (property_list_t *)
6392 malloc(sizeof(*proplist));
6393 proplist->count = 1;
6394 proplist->entsizeAndFlags = sizeof(proplist->first);
6395 proplist->first.name = strdupIfMutable(name);
6396 proplist->first.attributes = copyPropertyAttributeString(attrs, count);
6397
6398 cls->data()->properties.attachLists(&proplist, 1);
6399
6400 return YES;
6401 }
6402 }
6403
6404 BOOL
6405 class_addProperty(Class cls, const char *name,
6406 const objc_property_attribute_t *attrs, unsigned int n)
6407 {
6408 return _class_addProperty(cls, name, attrs, n, NO);
6409 }
6410
6411 void
6412 class_replaceProperty(Class cls, const char *name,
6413 const objc_property_attribute_t *attrs, unsigned int n)
6414 {
6415 _class_addProperty(cls, name, attrs, n, YES);
6416 }
6417
6418
6419 /***********************************************************************
6420 * look_up_class
6421 * Look up a class by name, and realize it.
6422 * Locking: acquires runtimeLock
6423 **********************************************************************/
6424 static BOOL empty_getClass(const char *name, Class *outClass)
6425 {
6426 *outClass = nil;
6427 return NO;
6428 }
6429
6430 static ChainedHookFunction<objc_hook_getClass> GetClassHook{empty_getClass};
6431
6432 void objc_setHook_getClass(objc_hook_getClass newValue,
6433 objc_hook_getClass *outOldValue)
6434 {
6435 GetClassHook.set(newValue, outOldValue);
6436 }
6437
6438 Class
6439 look_up_class(const char *name,
6440 bool includeUnconnected __attribute__((unused)),
6441 bool includeClassHandler __attribute__((unused)))
6442 {
6443 if (!name) return nil;
6444
6445 Class result;
6446 bool unrealized;
6447 {
6448 runtimeLock.lock();
6449 result = getClassExceptSomeSwift(name);
6450 unrealized = result && !result->isRealized();
6451 if (unrealized) {
6452 result = realizeClassMaybeSwiftAndUnlock(result, runtimeLock);
6453 // runtimeLock is now unlocked
6454 } else {
6455 runtimeLock.unlock();
6456 }
6457 }
6458
6459 if (!result) {
6460 // Ask Swift about its un-instantiated classes.
6461
6462 // We use thread-local storage to prevent infinite recursion
6463 // if the hook function provokes another lookup of the same name
6464 // (for example, if the hook calls objc_allocateClassPair)
6465
6466 auto *tls = _objc_fetch_pthread_data(true);
6467
6468 // Stop if this thread is already looking up this name.
6469 for (unsigned i = 0; i < tls->classNameLookupsUsed; i++) {
6470 if (0 == strcmp(name, tls->classNameLookups[i])) {
6471 return nil;
6472 }
6473 }
6474
6475 // Save this lookup in tls.
6476 if (tls->classNameLookupsUsed == tls->classNameLookupsAllocated) {
6477 tls->classNameLookupsAllocated =
6478 (tls->classNameLookupsAllocated * 2 ?: 1);
6479 size_t size = tls->classNameLookupsAllocated *
6480 sizeof(tls->classNameLookups[0]);
6481 tls->classNameLookups = (const char **)
6482 realloc(tls->classNameLookups, size);
6483 }
6484 tls->classNameLookups[tls->classNameLookupsUsed++] = name;
6485
6486 // Call the hook.
6487 Class swiftcls = nil;
6488 if (GetClassHook.get()(name, &swiftcls)) {
6489 assert(swiftcls->isRealized());
6490 result = swiftcls;
6491 }
6492
6493 // Erase the name from tls.
6494 unsigned slot = --tls->classNameLookupsUsed;
6495 assert(slot >= 0 && slot < tls->classNameLookupsAllocated);
6496 assert(name == tls->classNameLookups[slot]);
6497 tls->classNameLookups[slot] = nil;
6498 }
6499
6500 return result;
6501 }
6502
6503
6504 /***********************************************************************
6505 * objc_duplicateClass
6506 * fixme
6507 * Locking: acquires runtimeLock
6508 **********************************************************************/
6509 Class
6510 objc_duplicateClass(Class original, const char *name,
6511 size_t extraBytes)
6512 {
6513 Class duplicate;
6514
6515 mutex_locker_t lock(runtimeLock);
6516
6517 checkIsKnownClass(original);
6518
6519 assert(original->isRealized());
6520 assert(!original->isMetaClass());
6521
6522 duplicate = alloc_class_for_subclass(original, extraBytes);
6523
6524 duplicate->initClassIsa(original->ISA());
6525 duplicate->superclass = original->superclass;
6526
6527 duplicate->cache.initializeToEmpty();
6528
6529 class_rw_t *rw = (class_rw_t *)calloc(sizeof(*original->data()), 1);
6530 rw->flags = (original->data()->flags | RW_COPIED_RO | RW_REALIZING);
6531 rw->version = original->data()->version;
6532 rw->firstSubclass = nil;
6533 rw->nextSiblingClass = nil;
6534
6535 duplicate->bits = original->bits;
6536 duplicate->setData(rw);
6537
6538 rw->ro = original->data()->ro->duplicate();
6539 *(char **)&rw->ro->name = strdupIfMutable(name);
6540
6541 rw->methods = original->data()->methods.duplicate();
6542
6543 // fixme dies when categories are added to the base
6544 rw->properties = original->data()->properties;
6545 rw->protocols = original->data()->protocols;
6546
6547 duplicate->chooseClassArrayIndex();
6548
6549 if (duplicate->superclass) {
6550 addSubclass(duplicate->superclass, duplicate);
6551 // duplicate->isa == original->isa so don't addSubclass() for it
6552 } else {
6553 addRootClass(duplicate);
6554 }
6555
6556 // Don't methodize class - construction above is correct
6557
6558 addNamedClass(duplicate, duplicate->data()->ro->name);
6559 addClassTableEntry(duplicate, /*addMeta=*/false);
6560
6561 if (PrintConnecting) {
6562 _objc_inform("CLASS: realizing class '%s' (duplicate of %s) %p %p",
6563 name, original->nameForLogging(),
6564 (void*)duplicate, duplicate->data()->ro);
6565 }
6566
6567 duplicate->clearInfo(RW_REALIZING);
6568
6569 return duplicate;
6570 }
6571
6572 /***********************************************************************
6573 * objc_initializeClassPair
6574 * Locking: runtimeLock must be write-locked by the caller
6575 **********************************************************************/
6576
6577 // &UnsetLayout is the default ivar layout during class construction
6578 static const uint8_t UnsetLayout = 0;
6579
6580 static void objc_initializeClassPair_internal(Class superclass, const char *name, Class cls, Class meta)
6581 {
6582 runtimeLock.assertLocked();
6583
6584 class_ro_t *cls_ro_w, *meta_ro_w;
6585
6586 cls->setData((class_rw_t *)calloc(sizeof(class_rw_t), 1));
6587 meta->setData((class_rw_t *)calloc(sizeof(class_rw_t), 1));
6588 cls_ro_w = (class_ro_t *)calloc(sizeof(class_ro_t), 1);
6589 meta_ro_w = (class_ro_t *)calloc(sizeof(class_ro_t), 1);
6590 cls->data()->ro = cls_ro_w;
6591 meta->data()->ro = meta_ro_w;
6592
6593 // Set basic info
6594
6595 cls->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED | RW_REALIZING;
6596 meta->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED | RW_REALIZING;
6597 cls->data()->version = 0;
6598 meta->data()->version = 7;
6599
6600 cls_ro_w->flags = 0;
6601 meta_ro_w->flags = RO_META;
6602 if (!superclass) {
6603 cls_ro_w->flags |= RO_ROOT;
6604 meta_ro_w->flags |= RO_ROOT;
6605 }
6606 if (superclass) {
6607 uint32_t flagsToCopy = RW_FORBIDS_ASSOCIATED_OBJECTS;
6608 cls->data()->flags |= superclass->data()->flags & flagsToCopy;
6609 cls_ro_w->instanceStart = superclass->unalignedInstanceSize();
6610 meta_ro_w->instanceStart = superclass->ISA()->unalignedInstanceSize();
6611 cls->setInstanceSize(cls_ro_w->instanceStart);
6612 meta->setInstanceSize(meta_ro_w->instanceStart);
6613 } else {
6614 cls_ro_w->instanceStart = 0;
6615 meta_ro_w->instanceStart = (uint32_t)sizeof(objc_class);
6616 cls->setInstanceSize((uint32_t)sizeof(id)); // just an isa
6617 meta->setInstanceSize(meta_ro_w->instanceStart);
6618 }
6619
6620 cls_ro_w->name = strdupIfMutable(name);
6621 meta_ro_w->name = strdupIfMutable(name);
6622
6623 cls_ro_w->ivarLayout = &UnsetLayout;
6624 cls_ro_w->weakIvarLayout = &UnsetLayout;
6625
6626 meta->chooseClassArrayIndex();
6627 cls->chooseClassArrayIndex();
6628
6629 // Connect to superclasses and metaclasses
6630 cls->initClassIsa(meta);
6631 if (superclass) {
6632 meta->initClassIsa(superclass->ISA()->ISA());
6633 cls->superclass = superclass;
6634 meta->superclass = superclass->ISA();
6635 addSubclass(superclass, cls);
6636 addSubclass(superclass->ISA(), meta);
6637 } else {
6638 meta->initClassIsa(meta);
6639 cls->superclass = Nil;
6640 meta->superclass = cls;
6641 addRootClass(cls);
6642 addSubclass(cls, meta);
6643 }
6644
6645 cls->cache.initializeToEmpty();
6646 meta->cache.initializeToEmpty();
6647
6648 addClassTableEntry(cls);
6649 }
6650
6651
6652 /***********************************************************************
6653 * verifySuperclass
6654 * Sanity-check the superclass provided to
6655 * objc_allocateClassPair, objc_initializeClassPair, or objc_readClassPair.
6656 **********************************************************************/
6657 bool
6658 verifySuperclass(Class superclass, bool rootOK)
6659 {
6660 if (!superclass) {
6661 // Superclass does not exist.
6662 // If subclass may be a root class, this is OK.
6663 // If subclass must not be a root class, this is bad.
6664 return rootOK;
6665 }
6666
6667 // Superclass must be realized.
6668 if (! superclass->isRealized()) return false;
6669
6670 // Superclass must not be under construction.
6671 if (superclass->data()->flags & RW_CONSTRUCTING) return false;
6672
6673 return true;
6674 }
6675
6676
6677 /***********************************************************************
6678 * objc_initializeClassPair
6679 **********************************************************************/
6680 Class objc_initializeClassPair(Class superclass, const char *name, Class cls, Class meta)
6681 {
6682 // Fail if the class name is in use.
6683 if (look_up_class(name, NO, NO)) return nil;
6684
6685 mutex_locker_t lock(runtimeLock);
6686
6687 // Fail if the class name is in use.
6688 // Fail if the superclass isn't kosher.
6689 if (getClassExceptSomeSwift(name) ||
6690 !verifySuperclass(superclass, true/*rootOK*/))
6691 {
6692 return nil;
6693 }
6694
6695 objc_initializeClassPair_internal(superclass, name, cls, meta);
6696
6697 return cls;
6698 }
6699
6700
6701 /***********************************************************************
6702 * objc_allocateClassPair
6703 * fixme
6704 * Locking: acquires runtimeLock
6705 **********************************************************************/
6706 Class objc_allocateClassPair(Class superclass, const char *name,
6707 size_t extraBytes)
6708 {
6709 Class cls, meta;
6710
6711 // Fail if the class name is in use.
6712 if (look_up_class(name, NO, NO)) return nil;
6713
6714 mutex_locker_t lock(runtimeLock);
6715
6716 // Fail if the class name is in use.
6717 // Fail if the superclass isn't kosher.
6718 if (getClassExceptSomeSwift(name) ||
6719 !verifySuperclass(superclass, true/*rootOK*/))
6720 {
6721 return nil;
6722 }
6723
6724 // Allocate new classes.
6725 cls = alloc_class_for_subclass(superclass, extraBytes);
6726 meta = alloc_class_for_subclass(superclass, extraBytes);
6727
6728 // fixme mangle the name if it looks swift-y?
6729 objc_initializeClassPair_internal(superclass, name, cls, meta);
6730
6731 return cls;
6732 }
6733
6734
6735 /***********************************************************************
6736 * objc_registerClassPair
6737 * fixme
6738 * Locking: acquires runtimeLock
6739 **********************************************************************/
6740 void objc_registerClassPair(Class cls)
6741 {
6742 mutex_locker_t lock(runtimeLock);
6743
6744 checkIsKnownClass(cls);
6745
6746 if ((cls->data()->flags & RW_CONSTRUCTED) ||
6747 (cls->ISA()->data()->flags & RW_CONSTRUCTED))
6748 {
6749 _objc_inform("objc_registerClassPair: class '%s' was already "
6750 "registered!", cls->data()->ro->name);
6751 return;
6752 }
6753
6754 if (!(cls->data()->flags & RW_CONSTRUCTING) ||
6755 !(cls->ISA()->data()->flags & RW_CONSTRUCTING))
6756 {
6757 _objc_inform("objc_registerClassPair: class '%s' was not "
6758 "allocated with objc_allocateClassPair!",
6759 cls->data()->ro->name);
6760 return;
6761 }
6762
6763 // Clear "under construction" bit, set "done constructing" bit
6764 cls->ISA()->changeInfo(RW_CONSTRUCTED, RW_CONSTRUCTING | RW_REALIZING);
6765 cls->changeInfo(RW_CONSTRUCTED, RW_CONSTRUCTING | RW_REALIZING);
6766
6767 // Add to named class table.
6768 addNamedClass(cls, cls->data()->ro->name);
6769 }
6770
6771
6772 /***********************************************************************
6773 * objc_readClassPair()
6774 * Read a class and metaclass as written by a compiler.
6775 * Assumes the class and metaclass are not referenced by other things
6776 * that might need to be fixed up (such as categories and subclasses).
6777 * Does not call +load.
6778 * Returns the class pointer, or nil.
6779 *
6780 * Locking: runtimeLock acquired by map_images
6781 **********************************************************************/
6782 Class objc_readClassPair(Class bits, const struct objc_image_info *info)
6783 {
6784 mutex_locker_t lock(runtimeLock);
6785
6786 // No info bits are significant yet.
6787 (void)info;
6788
6789 // Fail if the superclass isn't kosher.
6790 bool rootOK = bits->data()->flags & RO_ROOT;
6791 if (!verifySuperclass(bits->superclass, rootOK)){
6792 return nil;
6793 }
6794
6795 // Duplicate classes are allowed, just like they are for image loading.
6796 // readClass will complain about the duplicate.
6797
6798 Class cls = readClass(bits, false/*bundle*/, false/*shared cache*/);
6799 if (cls != bits) {
6800 // This function isn't allowed to remap anything.
6801 _objc_fatal("objc_readClassPair for class %s changed %p to %p",
6802 cls->nameForLogging(), bits, cls);
6803 }
6804
6805 // The only client of this function is old Swift.
6806 // Stable Swift won't use it.
6807 // fixme once Swift in the OS settles we can assert(!cls->isSwiftStable()).
6808 cls = realizeClassWithoutSwift(cls);
6809
6810 return cls;
6811 }
6812
6813
6814 /***********************************************************************
6815 * detach_class
6816 * Disconnect a class from other data structures.
6817 * Exception: does not remove the class from the +load list
6818 * Call this before free_class.
6819 * Locking: runtimeLock must be held by the caller.
6820 **********************************************************************/
6821 static void detach_class(Class cls, bool isMeta)
6822 {
6823 runtimeLock.assertLocked();
6824
6825 // categories not yet attached to this class
6826 removeAllUnattachedCategoriesForClass(cls);
6827
6828 // superclass's subclass list
6829 if (cls->isRealized()) {
6830 Class supercls = cls->superclass;
6831 if (supercls) {
6832 removeSubclass(supercls, cls);
6833 } else {
6834 removeRootClass(cls);
6835 }
6836 }
6837
6838 // class tables and +load queue
6839 if (!isMeta) {
6840 removeNamedClass(cls, cls->mangledName());
6841 }
6842 NXHashRemove(allocatedClasses, cls);
6843 }
6844
6845
6846 /***********************************************************************
6847 * free_class
6848 * Frees a class's data structures.
6849 * Call this after detach_class.
6850 * Locking: runtimeLock must be held by the caller
6851 **********************************************************************/
6852 static void free_class(Class cls)
6853 {
6854 runtimeLock.assertLocked();
6855
6856 if (! cls->isRealized()) return;
6857
6858 auto rw = cls->data();
6859 auto ro = rw->ro;
6860
6861 cache_delete(cls);
6862
6863 for (auto& meth : rw->methods) {
6864 try_free(meth.types);
6865 }
6866 rw->methods.tryFree();
6867
6868 const ivar_list_t *ivars = ro->ivars;
6869 if (ivars) {
6870 for (auto& ivar : *ivars) {
6871 try_free(ivar.offset);
6872 try_free(ivar.name);
6873 try_free(ivar.type);
6874 }
6875 try_free(ivars);
6876 }
6877
6878 for (auto& prop : rw->properties) {
6879 try_free(prop.name);
6880 try_free(prop.attributes);
6881 }
6882 rw->properties.tryFree();
6883
6884 rw->protocols.tryFree();
6885
6886 try_free(ro->ivarLayout);
6887 try_free(ro->weakIvarLayout);
6888 try_free(ro->name);
6889 try_free(ro);
6890 try_free(rw);
6891 try_free(cls);
6892 }
6893
6894
6895 void objc_disposeClassPair(Class cls)
6896 {
6897 mutex_locker_t lock(runtimeLock);
6898
6899 checkIsKnownClass(cls);
6900
6901 if (!(cls->data()->flags & (RW_CONSTRUCTED|RW_CONSTRUCTING)) ||
6902 !(cls->ISA()->data()->flags & (RW_CONSTRUCTED|RW_CONSTRUCTING)))
6903 {
6904 // class not allocated with objc_allocateClassPair
6905 // disposing still-unregistered class is OK!
6906 _objc_inform("objc_disposeClassPair: class '%s' was not "
6907 "allocated with objc_allocateClassPair!",
6908 cls->data()->ro->name);
6909 return;
6910 }
6911
6912 if (cls->isMetaClass()) {
6913 _objc_inform("objc_disposeClassPair: class '%s' is a metaclass, "
6914 "not a class!", cls->data()->ro->name);
6915 return;
6916 }
6917
6918 // Shouldn't have any live subclasses.
6919 if (cls->data()->firstSubclass) {
6920 _objc_inform("objc_disposeClassPair: class '%s' still has subclasses, "
6921 "including '%s'!", cls->data()->ro->name,
6922 cls->data()->firstSubclass->nameForLogging());
6923 }
6924 if (cls->ISA()->data()->firstSubclass) {
6925 _objc_inform("objc_disposeClassPair: class '%s' still has subclasses, "
6926 "including '%s'!", cls->data()->ro->name,
6927 cls->ISA()->data()->firstSubclass->nameForLogging());
6928 }
6929
6930 // don't remove_class_from_loadable_list()
6931 // - it's not there and we don't have the lock
6932 detach_class(cls->ISA(), YES);
6933 detach_class(cls, NO);
6934 free_class(cls->ISA());
6935 free_class(cls);
6936 }
6937
6938
6939 /***********************************************************************
6940 * objc_constructInstance
6941 * Creates an instance of `cls` at the location pointed to by `bytes`.
6942 * `bytes` must point to at least class_getInstanceSize(cls) bytes of
6943 * well-aligned zero-filled memory.
6944 * The new object's isa is set. Any C++ constructors are called.
6945 * Returns `bytes` if successful. Returns nil if `cls` or `bytes` is
6946 * nil, or if C++ constructors fail.
6947 * Note: class_createInstance() and class_createInstances() preflight this.
6948 **********************************************************************/
6949 id
6950 objc_constructInstance(Class cls, void *bytes)
6951 {
6952 if (!cls || !bytes) return nil;
6953
6954 id obj = (id)bytes;
6955
6956 // Read class's info bits all at once for performance
6957 bool hasCxxCtor = cls->hasCxxCtor();
6958 bool hasCxxDtor = cls->hasCxxDtor();
6959 bool fast = cls->canAllocNonpointer();
6960
6961 if (fast) {
6962 obj->initInstanceIsa(cls, hasCxxDtor);
6963 } else {
6964 obj->initIsa(cls);
6965 }
6966
6967 if (hasCxxCtor) {
6968 return object_cxxConstructFromClass(obj, cls);
6969 } else {
6970 return obj;
6971 }
6972 }
6973
6974
6975 /***********************************************************************
6976 * class_createInstance
6977 * fixme
6978 * Locking: none
6979 **********************************************************************/
6980
6981 static __attribute__((always_inline))
6982 id
6983 _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
6984 bool cxxConstruct = true,
6985 size_t *outAllocatedSize = nil)
6986 {
6987 if (!cls) return nil;
6988
6989 assert(cls->isRealized());
6990
6991 // Read class's info bits all at once for performance
6992 bool hasCxxCtor = cls->hasCxxCtor();
6993 bool hasCxxDtor = cls->hasCxxDtor();
6994 bool fast = cls->canAllocNonpointer();
6995
6996 size_t size = cls->instanceSize(extraBytes);
6997 if (outAllocatedSize) *outAllocatedSize = size;
6998
6999 id obj;
7000 if (!zone && fast) {
7001 obj = (id)calloc(1, size);
7002 if (!obj) return nil;
7003 obj->initInstanceIsa(cls, hasCxxDtor);
7004 }
7005 else {
7006 if (zone) {
7007 obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
7008 } else {
7009 obj = (id)calloc(1, size);
7010 }
7011 if (!obj) return nil;
7012
7013 // Use raw pointer isa on the assumption that they might be
7014 // doing something weird with the zone or RR.
7015 obj->initIsa(cls);
7016 }
7017
7018 if (cxxConstruct && hasCxxCtor) {
7019 obj = _objc_constructOrFree(obj, cls);
7020 }
7021
7022 return obj;
7023 }
7024
7025
7026 id
7027 class_createInstance(Class cls, size_t extraBytes)
7028 {
7029 return _class_createInstanceFromZone(cls, extraBytes, nil);
7030 }
7031
7032
7033 /***********************************************************************
7034 * class_createInstances
7035 * fixme
7036 * Locking: none
7037 **********************************************************************/
7038 #if SUPPORT_NONPOINTER_ISA
7039 #warning fixme optimize class_createInstances
7040 #endif
7041 unsigned
7042 class_createInstances(Class cls, size_t extraBytes,
7043 id *results, unsigned num_requested)
7044 {
7045 return _class_createInstancesFromZone(cls, extraBytes, nil,
7046 results, num_requested);
7047 }
7048
7049 /***********************************************************************
7050 * object_copyFromZone
7051 * fixme
7052 * Locking: none
7053 **********************************************************************/
7054 static id
7055 _object_copyFromZone(id oldObj, size_t extraBytes, void *zone)
7056 {
7057 if (!oldObj) return nil;
7058 if (oldObj->isTaggedPointer()) return oldObj;
7059
7060 // fixme this doesn't handle C++ ivars correctly (#4619414)
7061
7062 Class cls = oldObj->ISA();
7063 size_t size;
7064 id obj = _class_createInstanceFromZone(cls, extraBytes, zone, false, &size);
7065 if (!obj) return nil;
7066
7067 // Copy everything except the isa, which was already set above.
7068 uint8_t *copyDst = (uint8_t *)obj + sizeof(Class);
7069 uint8_t *copySrc = (uint8_t *)oldObj + sizeof(Class);
7070 size_t copySize = size - sizeof(Class);
7071 memmove(copyDst, copySrc, copySize);
7072
7073 fixupCopiedIvars(obj, oldObj);
7074
7075 return obj;
7076 }
7077
7078
7079 /***********************************************************************
7080 * object_copy
7081 * fixme
7082 * Locking: none
7083 **********************************************************************/
7084 id
7085 object_copy(id oldObj, size_t extraBytes)
7086 {
7087 return _object_copyFromZone(oldObj, extraBytes, malloc_default_zone());
7088 }
7089
7090
7091 #if SUPPORT_ZONES
7092
7093 /***********************************************************************
7094 * class_createInstanceFromZone
7095 * fixme
7096 * Locking: none
7097 **********************************************************************/
7098 id
7099 class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone)
7100 {
7101 return _class_createInstanceFromZone(cls, extraBytes, zone);
7102 }
7103
7104 /***********************************************************************
7105 * object_copyFromZone
7106 * fixme
7107 * Locking: none
7108 **********************************************************************/
7109 id
7110 object_copyFromZone(id oldObj, size_t extraBytes, void *zone)
7111 {
7112 return _object_copyFromZone(oldObj, extraBytes, zone);
7113 }
7114
7115 #endif
7116
7117
7118 /***********************************************************************
7119 * objc_destructInstance
7120 * Destroys an instance without freeing memory.
7121 * Calls C++ destructors.
7122 * Calls ARC ivar cleanup.
7123 * Removes associative references.
7124 * Returns `obj`. Does nothing if `obj` is nil.
7125 **********************************************************************/
7126 void *objc_destructInstance(id obj)
7127 {
7128 if (obj) {
7129 // Read all of the flags at once for performance.
7130 bool cxx = obj->hasCxxDtor();
7131 bool assoc = obj->hasAssociatedObjects();
7132
7133 // This order is important.
7134 if (cxx) object_cxxDestruct(obj);
7135 if (assoc) _object_remove_assocations(obj);
7136 obj->clearDeallocating();
7137 }
7138
7139 return obj;
7140 }
7141
7142
7143 /***********************************************************************
7144 * object_dispose
7145 * fixme
7146 * Locking: none
7147 **********************************************************************/
7148 id
7149 object_dispose(id obj)
7150 {
7151 if (!obj) return nil;
7152
7153 objc_destructInstance(obj);
7154 free(obj);
7155
7156 return nil;
7157 }
7158
7159
7160 /***********************************************************************
7161 * _objc_getFreedObjectClass
7162 * fixme
7163 * Locking: none
7164 **********************************************************************/
7165 Class _objc_getFreedObjectClass (void)
7166 {
7167 return nil;
7168 }
7169
7170
7171
7172 /***********************************************************************
7173 * Tagged pointer objects.
7174 *
7175 * Tagged pointer objects store the class and the object value in the
7176 * object pointer; the "pointer" does not actually point to anything.
7177 *
7178 * Tagged pointer objects currently use this representation:
7179 * (LSB)
7180 * 1 bit set if tagged, clear if ordinary object pointer
7181 * 3 bits tag index
7182 * 60 bits payload
7183 * (MSB)
7184 * The tag index defines the object's class.
7185 * The payload format is defined by the object's class.
7186 *
7187 * If the tag index is 0b111, the tagged pointer object uses an
7188 * "extended" representation, allowing more classes but with smaller payloads:
7189 * (LSB)
7190 * 1 bit set if tagged, clear if ordinary object pointer
7191 * 3 bits 0b111
7192 * 8 bits extended tag index
7193 * 52 bits payload
7194 * (MSB)
7195 *
7196 * Some architectures reverse the MSB and LSB in these representations.
7197 *
7198 * This representation is subject to change. Representation-agnostic SPI is:
7199 * objc-internal.h for class implementers.
7200 * objc-gdb.h for debuggers.
7201 **********************************************************************/
7202 #if !SUPPORT_TAGGED_POINTERS
7203
7204 // These variables are always provided for debuggers.
7205 uintptr_t objc_debug_taggedpointer_obfuscator = 0;
7206 uintptr_t objc_debug_taggedpointer_mask = 0;
7207 unsigned objc_debug_taggedpointer_slot_shift = 0;
7208 uintptr_t objc_debug_taggedpointer_slot_mask = 0;
7209 unsigned objc_debug_taggedpointer_payload_lshift = 0;
7210 unsigned objc_debug_taggedpointer_payload_rshift = 0;
7211 Class objc_debug_taggedpointer_classes[1] = { nil };
7212
7213 uintptr_t objc_debug_taggedpointer_ext_mask = 0;
7214 unsigned objc_debug_taggedpointer_ext_slot_shift = 0;
7215 uintptr_t objc_debug_taggedpointer_ext_slot_mask = 0;
7216 unsigned objc_debug_taggedpointer_ext_payload_lshift = 0;
7217 unsigned objc_debug_taggedpointer_ext_payload_rshift = 0;
7218 Class objc_debug_taggedpointer_ext_classes[1] = { nil };
7219
7220 static void
7221 disableTaggedPointers() { }
7222
7223 static void
7224 initializeTaggedPointerObfuscator(void) { }
7225
7226 #else
7227
7228 // The "slot" used in the class table and given to the debugger
7229 // includes the is-tagged bit. This makes objc_msgSend faster.
7230 // The "ext" representation doesn't do that.
7231
7232 uintptr_t objc_debug_taggedpointer_obfuscator;
7233 uintptr_t objc_debug_taggedpointer_mask = _OBJC_TAG_MASK;
7234 unsigned objc_debug_taggedpointer_slot_shift = _OBJC_TAG_SLOT_SHIFT;
7235 uintptr_t objc_debug_taggedpointer_slot_mask = _OBJC_TAG_SLOT_MASK;
7236 unsigned objc_debug_taggedpointer_payload_lshift = _OBJC_TAG_PAYLOAD_LSHIFT;
7237 unsigned objc_debug_taggedpointer_payload_rshift = _OBJC_TAG_PAYLOAD_RSHIFT;
7238 // objc_debug_taggedpointer_classes is defined in objc-msg-*.s
7239
7240 uintptr_t objc_debug_taggedpointer_ext_mask = _OBJC_TAG_EXT_MASK;
7241 unsigned objc_debug_taggedpointer_ext_slot_shift = _OBJC_TAG_EXT_SLOT_SHIFT;
7242 uintptr_t objc_debug_taggedpointer_ext_slot_mask = _OBJC_TAG_EXT_SLOT_MASK;
7243 unsigned objc_debug_taggedpointer_ext_payload_lshift = _OBJC_TAG_EXT_PAYLOAD_LSHIFT;
7244 unsigned objc_debug_taggedpointer_ext_payload_rshift = _OBJC_TAG_EXT_PAYLOAD_RSHIFT;
7245 // objc_debug_taggedpointer_ext_classes is defined in objc-msg-*.s
7246
7247 static void
7248 disableTaggedPointers()
7249 {
7250 objc_debug_taggedpointer_mask = 0;
7251 objc_debug_taggedpointer_slot_shift = 0;
7252 objc_debug_taggedpointer_slot_mask = 0;
7253 objc_debug_taggedpointer_payload_lshift = 0;
7254 objc_debug_taggedpointer_payload_rshift = 0;
7255
7256 objc_debug_taggedpointer_ext_mask = 0;
7257 objc_debug_taggedpointer_ext_slot_shift = 0;
7258 objc_debug_taggedpointer_ext_slot_mask = 0;
7259 objc_debug_taggedpointer_ext_payload_lshift = 0;
7260 objc_debug_taggedpointer_ext_payload_rshift = 0;
7261 }
7262
7263
7264 // Returns a pointer to the class's storage in the tagged class arrays.
7265 // Assumes the tag is a valid basic tag.
7266 static Class *
7267 classSlotForBasicTagIndex(objc_tag_index_t tag)
7268 {
7269 uintptr_t tagObfuscator = ((objc_debug_taggedpointer_obfuscator
7270 >> _OBJC_TAG_INDEX_SHIFT)
7271 & _OBJC_TAG_INDEX_MASK);
7272 uintptr_t obfuscatedTag = tag ^ tagObfuscator;
7273 // Array index in objc_tag_classes includes the tagged bit itself
7274 #if SUPPORT_MSB_TAGGED_POINTERS
7275 return &objc_tag_classes[0x8 | obfuscatedTag];
7276 #else
7277 return &objc_tag_classes[(obfuscatedTag << 1) | 1];
7278 #endif
7279 }
7280
7281
7282 // Returns a pointer to the class's storage in the tagged class arrays,
7283 // or nil if the tag is out of range.
7284 static Class *
7285 classSlotForTagIndex(objc_tag_index_t tag)
7286 {
7287 if (tag >= OBJC_TAG_First60BitPayload && tag <= OBJC_TAG_Last60BitPayload) {
7288 return classSlotForBasicTagIndex(tag);
7289 }
7290
7291 if (tag >= OBJC_TAG_First52BitPayload && tag <= OBJC_TAG_Last52BitPayload) {
7292 int index = tag - OBJC_TAG_First52BitPayload;
7293 uintptr_t tagObfuscator = ((objc_debug_taggedpointer_obfuscator
7294 >> _OBJC_TAG_EXT_INDEX_SHIFT)
7295 & _OBJC_TAG_EXT_INDEX_MASK);
7296 return &objc_tag_ext_classes[index ^ tagObfuscator];
7297 }
7298
7299 return nil;
7300 }
7301
7302 /***********************************************************************
7303 * initializeTaggedPointerObfuscator
7304 * Initialize objc_debug_taggedpointer_obfuscator with randomness.
7305 *
7306 * The tagged pointer obfuscator is intended to make it more difficult
7307 * for an attacker to construct a particular object as a tagged pointer,
7308 * in the presence of a buffer overflow or other write control over some
7309 * memory. The obfuscator is XORed with the tagged pointers when setting
7310 * or retrieving payload values. They are filled with randomness on first
7311 * use.
7312 **********************************************************************/
7313 static void
7314 initializeTaggedPointerObfuscator(void)
7315 {
7316 if (sdkIsOlderThan(10_14, 12_0, 12_0, 5_0, 3_0) ||
7317 // Set the obfuscator to zero for apps linked against older SDKs,
7318 // in case they're relying on the tagged pointer representation.
7319 DisableTaggedPointerObfuscation) {
7320 objc_debug_taggedpointer_obfuscator = 0;
7321 } else {
7322 // Pull random data into the variable, then shift away all non-payload bits.
7323 arc4random_buf(&objc_debug_taggedpointer_obfuscator,
7324 sizeof(objc_debug_taggedpointer_obfuscator));
7325 objc_debug_taggedpointer_obfuscator &= ~_OBJC_TAG_MASK;
7326 }
7327 }
7328
7329
7330 /***********************************************************************
7331 * _objc_registerTaggedPointerClass
7332 * Set the class to use for the given tagged pointer index.
7333 * Aborts if the tag is out of range, or if the tag is already
7334 * used by some other class.
7335 **********************************************************************/
7336 void
7337 _objc_registerTaggedPointerClass(objc_tag_index_t tag, Class cls)
7338 {
7339 if (objc_debug_taggedpointer_mask == 0) {
7340 _objc_fatal("tagged pointers are disabled");
7341 }
7342
7343 Class *slot = classSlotForTagIndex(tag);
7344 if (!slot) {
7345 _objc_fatal("tag index %u is invalid", (unsigned int)tag);
7346 }
7347
7348 Class oldCls = *slot;
7349
7350 if (cls && oldCls && cls != oldCls) {
7351 _objc_fatal("tag index %u used for two different classes "
7352 "(was %p %s, now %p %s)", tag,
7353 oldCls, oldCls->nameForLogging(),
7354 cls, cls->nameForLogging());
7355 }
7356
7357 *slot = cls;
7358
7359 // Store a placeholder class in the basic tag slot that is
7360 // reserved for the extended tag space, if it isn't set already.
7361 // Do this lazily when the first extended tag is registered so
7362 // that old debuggers characterize bogus pointers correctly more often.
7363 if (tag < OBJC_TAG_First60BitPayload || tag > OBJC_TAG_Last60BitPayload) {
7364 Class *extSlot = classSlotForBasicTagIndex(OBJC_TAG_RESERVED_7);
7365 if (*extSlot == nil) {
7366 extern objc_class OBJC_CLASS_$___NSUnrecognizedTaggedPointer;
7367 *extSlot = (Class)&OBJC_CLASS_$___NSUnrecognizedTaggedPointer;
7368 }
7369 }
7370 }
7371
7372
7373 /***********************************************************************
7374 * _objc_getClassForTag
7375 * Returns the class that is using the given tagged pointer tag.
7376 * Returns nil if no class is using that tag or the tag is out of range.
7377 **********************************************************************/
7378 Class
7379 _objc_getClassForTag(objc_tag_index_t tag)
7380 {
7381 Class *slot = classSlotForTagIndex(tag);
7382 if (slot) return *slot;
7383 else return nil;
7384 }
7385
7386 #endif
7387
7388
7389 #if SUPPORT_FIXUP
7390
7391 OBJC_EXTERN void objc_msgSend_fixup(void);
7392 OBJC_EXTERN void objc_msgSendSuper2_fixup(void);
7393 OBJC_EXTERN void objc_msgSend_stret_fixup(void);
7394 OBJC_EXTERN void objc_msgSendSuper2_stret_fixup(void);
7395 #if defined(__i386__) || defined(__x86_64__)
7396 OBJC_EXTERN void objc_msgSend_fpret_fixup(void);
7397 #endif
7398 #if defined(__x86_64__)
7399 OBJC_EXTERN void objc_msgSend_fp2ret_fixup(void);
7400 #endif
7401
7402 OBJC_EXTERN void objc_msgSend_fixedup(void);
7403 OBJC_EXTERN void objc_msgSendSuper2_fixedup(void);
7404 OBJC_EXTERN void objc_msgSend_stret_fixedup(void);
7405 OBJC_EXTERN void objc_msgSendSuper2_stret_fixedup(void);
7406 #if defined(__i386__) || defined(__x86_64__)
7407 OBJC_EXTERN void objc_msgSend_fpret_fixedup(void);
7408 #endif
7409 #if defined(__x86_64__)
7410 OBJC_EXTERN void objc_msgSend_fp2ret_fixedup(void);
7411 #endif
7412
7413 /***********************************************************************
7414 * fixupMessageRef
7415 * Repairs an old vtable dispatch call site.
7416 * vtable dispatch itself is not supported.
7417 **********************************************************************/
7418 static void
7419 fixupMessageRef(message_ref_t *msg)
7420 {
7421 msg->sel = sel_registerName((const char *)msg->sel);
7422
7423 if (msg->imp == &objc_msgSend_fixup) {
7424 if (msg->sel == SEL_alloc) {
7425 msg->imp = (IMP)&objc_alloc;
7426 } else if (msg->sel == SEL_allocWithZone) {
7427 msg->imp = (IMP)&objc_allocWithZone;
7428 } else if (msg->sel == SEL_retain) {
7429 msg->imp = (IMP)&objc_retain;
7430 } else if (msg->sel == SEL_release) {
7431 msg->imp = (IMP)&objc_release;
7432 } else if (msg->sel == SEL_autorelease) {
7433 msg->imp = (IMP)&objc_autorelease;
7434 } else {
7435 msg->imp = &objc_msgSend_fixedup;
7436 }
7437 }
7438 else if (msg->imp == &objc_msgSendSuper2_fixup) {
7439 msg->imp = &objc_msgSendSuper2_fixedup;
7440 }
7441 else if (msg->imp == &objc_msgSend_stret_fixup) {
7442 msg->imp = &objc_msgSend_stret_fixedup;
7443 }
7444 else if (msg->imp == &objc_msgSendSuper2_stret_fixup) {
7445 msg->imp = &objc_msgSendSuper2_stret_fixedup;
7446 }
7447 #if defined(__i386__) || defined(__x86_64__)
7448 else if (msg->imp == &objc_msgSend_fpret_fixup) {
7449 msg->imp = &objc_msgSend_fpret_fixedup;
7450 }
7451 #endif
7452 #if defined(__x86_64__)
7453 else if (msg->imp == &objc_msgSend_fp2ret_fixup) {
7454 msg->imp = &objc_msgSend_fp2ret_fixedup;
7455 }
7456 #endif
7457 }
7458
7459 // SUPPORT_FIXUP
7460 #endif
7461
7462
7463 // ProKit SPI
7464 static Class setSuperclass(Class cls, Class newSuper)
7465 {
7466 Class oldSuper;
7467
7468 runtimeLock.assertLocked();
7469
7470 assert(cls->isRealized());
7471 assert(newSuper->isRealized());
7472
7473 oldSuper = cls->superclass;
7474 removeSubclass(oldSuper, cls);
7475 removeSubclass(oldSuper->ISA(), cls->ISA());
7476
7477 cls->superclass = newSuper;
7478 cls->ISA()->superclass = newSuper->ISA();
7479 addSubclass(newSuper, cls);
7480 addSubclass(newSuper->ISA(), cls->ISA());
7481
7482 // Flush subclass's method caches.
7483 flushCaches(cls);
7484 flushCaches(cls->ISA());
7485
7486 return oldSuper;
7487 }
7488
7489
7490 Class class_setSuperclass(Class cls, Class newSuper)
7491 {
7492 mutex_locker_t lock(runtimeLock);
7493 return setSuperclass(cls, newSuper);
7494 }
7495
7496
7497 // __OBJC2__
7498 #endif