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