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