2 * Copyright (c) 2005-2009 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 /***********************************************************************
26 * Support for new-ABI classes and images.
27 **********************************************************************/
31 #include "objc-private.h"
32 #include "objc-runtime-new.h"
33 #include "objc-file.h"
34 #include <objc/message.h>
35 #include <mach/shared_region.h>
37 #define newcls(cls) ((class_t *)cls)
38 #define newmethod(meth) ((method_t *)meth)
39 #define newivar(ivar) ((ivar_t *)ivar)
40 #define newcategory(cat) ((category_t *)cat)
41 #define newprotocol(p) ((protocol_t *)p)
42 #define newproperty(p) ((property_t *)p)
44 static const char *getName(class_t *cls);
45 static uint32_t unalignedInstanceSize(class_t *cls);
46 static uint32_t alignedInstanceSize(class_t *cls);
47 static BOOL isMetaClass(class_t *cls);
48 static class_t *getSuperclass(class_t *cls);
49 static void detach_class(class_t *cls, BOOL isMeta);
50 static void free_class(class_t *cls);
51 static class_t *setSuperclass(class_t *cls, class_t *newSuper);
52 static class_t *realizeClass(class_t *cls);
53 static void flushCaches(class_t *cls);
54 static void flushVtables(class_t *cls);
55 static method_t *getMethodNoSuper_nolock(class_t *cls, SEL sel);
56 static method_t *getMethod_nolock(class_t *cls, SEL sel);
57 static void changeInfo(class_t *cls, unsigned int set, unsigned int clear);
58 static IMP _method_getImplementation(method_t *m);
59 static BOOL hasCxxStructors(class_t *cls);
60 static IMP addMethod(class_t *cls, SEL name, IMP imp, const char *types, BOOL replace);
61 static NXHashTable *realizedClasses(void);
62 static bool isRRSelector(SEL sel);
63 static bool isAWZSelector(SEL sel);
64 static void updateCustomRR_AWZ(class_t *cls, method_t *meth);
65 static method_t *search_method_list(const method_list_t *mlist, SEL sel);
67 id objc_noop_imp(id self, SEL _cmd __unused) {
71 /***********************************************************************
73 * Every lock used anywhere must be managed here.
74 * Locks not managed here may cause gdb deadlocks.
75 **********************************************************************/
78 mutex_t cacheUpdateLock = MUTEX_INITIALIZER;
79 recursive_mutex_t loadMethodLock = RECURSIVE_MUTEX_INITIALIZER;
80 static int debugger_runtimeLock;
81 static int debugger_selLock;
82 static int debugger_cacheUpdateLock;
83 static int debugger_loadMethodLock;
89 rwlock_init(&selLock);
90 rwlock_init(&runtimeLock);
91 recursive_mutex_init(&loadMethodLock);
95 /***********************************************************************
97 * Attempt to acquire some locks for debugger mode.
98 * Returns 0 if debugger mode failed because too many locks are unavailable.
100 * Locks successfully acquired are held until endDebuggerMode().
101 * Locks not acquired are off-limits until endDebuggerMode(); any
102 * attempt to manipulate them will cause a trap.
103 * Locks not handled here may cause deadlocks in gdb.
104 **********************************************************************/
105 int startDebuggerMode(void)
107 int result = DEBUGGER_FULL;
109 // runtimeLock is required (can't do much without it)
110 if (rwlock_try_write(&runtimeLock)) {
111 debugger_runtimeLock = RDWR;
112 } else if (rwlock_try_read(&runtimeLock)) {
113 debugger_runtimeLock = RDONLY;
114 result = DEBUGGER_PARTIAL;
119 // cacheUpdateLock is required (must not fail a necessary cache flush)
120 // must be AFTER runtimeLock to avoid lock inversion
121 if (mutex_try_lock(&cacheUpdateLock)) {
122 debugger_cacheUpdateLock = RDWR;
124 rwlock_unlock(&runtimeLock, debugger_runtimeLock);
125 debugger_runtimeLock = 0;
129 // side table locks are not optional
130 if (!noSideTableLocksHeld()) {
131 rwlock_unlock(&runtimeLock, debugger_runtimeLock);
132 mutex_unlock(&cacheUpdateLock);
133 debugger_runtimeLock = 0;
137 // selLock is optional
138 if (rwlock_try_write(&selLock)) {
139 debugger_selLock = RDWR;
140 } else if (rwlock_try_read(&selLock)) {
141 debugger_selLock = RDONLY;
142 result = DEBUGGER_PARTIAL;
144 debugger_selLock = 0;
145 result = DEBUGGER_PARTIAL;
148 // loadMethodLock is optional
149 if (recursive_mutex_try_lock(&loadMethodLock)) {
150 debugger_loadMethodLock = RDWR;
152 debugger_loadMethodLock = 0;
153 result = DEBUGGER_PARTIAL;
159 /***********************************************************************
161 * Relinquish locks acquired in startDebuggerMode().
162 **********************************************************************/
163 void endDebuggerMode(void)
165 assert(debugger_runtimeLock != 0);
167 rwlock_unlock(&runtimeLock, debugger_runtimeLock);
168 debugger_runtimeLock = 0;
170 rwlock_unlock(&selLock, debugger_selLock);
171 debugger_selLock = 0;
173 assert(debugger_cacheUpdateLock == RDWR);
174 mutex_unlock(&cacheUpdateLock);
175 debugger_cacheUpdateLock = 0;
177 if (debugger_loadMethodLock) {
178 recursive_mutex_unlock(&loadMethodLock);
179 debugger_loadMethodLock = 0;
183 /***********************************************************************
184 * isManagedDuringDebugger
185 * Returns YES if the given lock is handled specially during debugger
186 * mode (i.e. debugger mode tries to acquire it).
187 **********************************************************************/
188 BOOL isManagedDuringDebugger(void *lock)
190 if (lock == &selLock) return YES;
191 if (lock == &cacheUpdateLock) return YES;
192 if (lock == &runtimeLock) return YES;
193 if (lock == &loadMethodLock) return YES;
197 /***********************************************************************
198 * isLockedDuringDebugger
199 * Returns YES if the given mutex was acquired by debugger mode.
200 * Locking a managed mutex during debugger mode causes a trap unless
202 **********************************************************************/
203 BOOL isLockedDuringDebugger(void *lock)
205 assert(DebuggerMode);
207 if (lock == &cacheUpdateLock) return YES;
208 if (lock == (mutex_t *)&loadMethodLock) return YES;
212 /***********************************************************************
213 * isReadingDuringDebugger
214 * Returns YES if the given rwlock was read-locked by debugger mode.
215 * Read-locking a managed rwlock during debugger mode causes a trap unless
217 **********************************************************************/
218 BOOL isReadingDuringDebugger(rwlock_t *lock)
220 assert(DebuggerMode);
222 // read-lock is allowed even if debugger mode actually write-locked it
223 if (debugger_runtimeLock && lock == &runtimeLock) return YES;
224 if (debugger_selLock && lock == &selLock) return YES;
229 /***********************************************************************
230 * isWritingDuringDebugger
231 * Returns YES if the given rwlock was write-locked by debugger mode.
232 * Write-locking a managed rwlock during debugger mode causes a trap unless
234 **********************************************************************/
235 BOOL isWritingDuringDebugger(rwlock_t *lock)
237 assert(DebuggerMode);
239 if (debugger_runtimeLock == RDWR && lock == &runtimeLock) return YES;
240 if (debugger_selLock == RDWR && lock == &selLock) return YES;
246 /***********************************************************************
249 * Every class gets a vtable pointer. The vtable is an array of IMPs.
250 * The selectors represented in the vtable are the same for all classes
251 * (i.e. no class has a bigger or smaller vtable).
252 * Each vtable index has an associated trampoline which dispatches to
253 * the IMP at that index for the receiver class's vtable (after
254 * checking for NULL). Dispatch fixup uses these trampolines instead
256 * Fragility: The vtable size and list of selectors is chosen at launch
257 * time. No compiler-generated code depends on any particular vtable
258 * configuration, or even the use of vtable dispatch at all.
259 * Memory size: If a class's vtable is identical to its superclass's
260 * (i.e. the class overrides none of the vtable selectors), then
261 * the class points directly to its superclass's vtable. This means
262 * selectors to be included in the vtable should be chosen so they are
263 * (1) frequently called, but (2) not too frequently overridden. In
264 * particular, -dealloc is a bad choice.
265 * Forwarding: If a class doesn't implement some vtable selector, that
266 * selector's IMP is set to objc_msgSend in that class's vtable.
267 * +initialize: Each class keeps the default vtable (which always
268 * redirects to objc_msgSend) until its +initialize is completed.
269 * Otherwise, the first message to a class could be a vtable dispatch,
270 * and the vtable trampoline doesn't include +initialize checking.
271 * Changes: Categories, addMethod, and setImplementation all force vtable
272 * reconstruction for the class and all of its subclasses, if the
273 * vtable selectors are affected.
274 **********************************************************************/
276 /***********************************************************************
277 * ABI WARNING ABI WARNING ABI WARNING ABI WARNING ABI WARNING
278 * vtable_prototype on x86_64 steals %rax and does not clear %rdx on return
279 * This means vtable dispatch must never be used for vararg calls
280 * or very large return values.
281 * ABI WARNING ABI WARNING ABI WARNING ABI WARNING ABI WARNING
282 **********************************************************************/
287 X8(x) X8(x) X8(x) X8(x) X8(x) X8(x) X8(x) X8(x)
291 #define vtableMax 128
293 // hack to avoid conflicts with compiler's internal declaration
295 "\n .globl __objc_empty_vtable "
296 "\n __objc_empty_vtable:"
298 X128("\n .quad _objc_msgSend")
300 X128("\n .long _objc_msgSend")
306 // Trampoline descriptors for gdb.
308 objc_trampoline_header *gdb_objc_trampolines = NULL;
310 void gdb_objc_trampolines_changed(objc_trampoline_header *thdr) __attribute__((noinline));
311 void gdb_objc_trampolines_changed(objc_trampoline_header *thdr)
313 rwlock_assert_writing(&runtimeLock);
314 assert(thdr == gdb_objc_trampolines);
317 _objc_inform("VTABLES: gdb_objc_trampolines_changed(%p)", thdr);
321 // fixme workaround for rdar://6667753
322 static void appendTrampolines(objc_trampoline_header *thdr) __attribute__((noinline));
324 static void appendTrampolines(objc_trampoline_header *thdr)
326 rwlock_assert_writing(&runtimeLock);
327 assert(thdr->next == NULL);
329 if (gdb_objc_trampolines != thdr->next) {
330 thdr->next = gdb_objc_trampolines;
332 gdb_objc_trampolines = thdr;
334 gdb_objc_trampolines_changed(thdr);
337 // Vtable management.
339 static size_t vtableStrlen;
340 static size_t vtableCount;
341 static SEL *vtableSelectors;
342 static IMP *vtableTrampolines;
343 static const char * const defaultVtable[] = {
349 "respondsToSelector:",
361 static const char * const defaultVtableGC[] = {
367 "respondsToSelector:",
377 "countByEnumeratingWithState:objects:count:",
380 OBJC_EXTERN void objc_msgSend_vtable0(void);
381 OBJC_EXTERN void objc_msgSend_vtable1(void);
382 OBJC_EXTERN void objc_msgSend_vtable2(void);
383 OBJC_EXTERN void objc_msgSend_vtable3(void);
384 OBJC_EXTERN void objc_msgSend_vtable4(void);
385 OBJC_EXTERN void objc_msgSend_vtable5(void);
386 OBJC_EXTERN void objc_msgSend_vtable6(void);
387 OBJC_EXTERN void objc_msgSend_vtable7(void);
388 OBJC_EXTERN void objc_msgSend_vtable8(void);
389 OBJC_EXTERN void objc_msgSend_vtable9(void);
390 OBJC_EXTERN void objc_msgSend_vtable10(void);
391 OBJC_EXTERN void objc_msgSend_vtable11(void);
392 OBJC_EXTERN void objc_msgSend_vtable12(void);
393 OBJC_EXTERN void objc_msgSend_vtable13(void);
394 OBJC_EXTERN void objc_msgSend_vtable14(void);
395 OBJC_EXTERN void objc_msgSend_vtable15(void);
397 static IMP const defaultVtableTrampolines[] = {
398 (IMP)objc_msgSend_vtable0,
399 (IMP)objc_msgSend_vtable1,
400 (IMP)objc_msgSend_vtable2,
401 (IMP)objc_msgSend_vtable3,
402 (IMP)objc_msgSend_vtable4,
403 (IMP)objc_msgSend_vtable5,
404 (IMP)objc_msgSend_vtable6,
405 (IMP)objc_msgSend_vtable7,
406 (IMP)objc_msgSend_vtable8,
407 (IMP)objc_msgSend_vtable9,
408 (IMP)objc_msgSend_vtable10,
409 (IMP)objc_msgSend_vtable11,
410 (IMP)objc_msgSend_vtable12,
411 (IMP)objc_msgSend_vtable13,
412 (IMP)objc_msgSend_vtable14,
413 (IMP)objc_msgSend_vtable15,
415 extern objc_trampoline_header defaultVtableTrampolineDescriptors;
417 static void check_vtable_size(void) __unused;
418 static void check_vtable_size(void)
420 // Fail to compile if vtable sizes don't match.
421 int c1[sizeof(defaultVtableTrampolines)-sizeof(defaultVtable)] __unused;
422 int c2[sizeof(defaultVtable)-sizeof(defaultVtableTrampolines)] __unused;
423 int c3[sizeof(defaultVtableTrampolines)-sizeof(defaultVtableGC)] __unused;
424 int c4[sizeof(defaultVtableGC)-sizeof(defaultVtableTrampolines)] __unused;
426 // Fail to compile if vtableMax is too small
427 int c5[vtableMax - sizeof(defaultVtable)] __unused;
428 int c6[vtableMax - sizeof(defaultVtableGC)] __unused;
432 extern uint8_t vtable_prototype;
433 extern uint8_t vtable_ignored;
434 extern int vtable_prototype_size;
435 extern int vtable_prototype_index_offset;
436 extern int vtable_prototype_index2_offset;
437 extern int vtable_prototype_tagtable_offset;
438 extern int vtable_prototype_tagtable_size;
439 static size_t makeVtableTrampoline(uint8_t *dst, size_t index)
442 memcpy(dst, &vtable_prototype, vtable_prototype_size);
445 #if defined(__x86_64__)
446 if (index > 255) _objc_fatal("vtable_prototype busted");
448 // `jmpq *0x7fff(%rax)` ff a0 ff 7f
449 uint16_t *p = (uint16_t *)(dst + vtable_prototype_index_offset + 2);
450 if (*p != 0x7fff) _objc_fatal("vtable_prototype busted");
454 uint16_t *p = (uint16_t *)(dst + vtable_prototype_index2_offset + 2);
455 if (*p != 0x7fff) _objc_fatal("vtable_prototype busted");
459 # warning unknown architecture
462 // insert tagged isa table
463 #if defined(__x86_64__)
465 // `movq $0x1122334455667788, %r10` 49 ba 88 77 66 55 44 33 22 11
466 if (vtable_prototype_tagtable_size != 10) {
467 _objc_fatal("vtable_prototype busted");
469 uint8_t *p = (uint8_t *)(dst + vtable_prototype_tagtable_offset);
470 if (*p++ != 0x49) _objc_fatal("vtable_prototype busted");
471 if (*p++ != 0xba) _objc_fatal("vtable_prototype busted");
472 if (*(uintptr_t *)p != 0x1122334455667788) {
473 _objc_fatal("vtable_prototype busted");
475 uintptr_t addr = (uintptr_t)_objc_tagged_isa_table;
476 memcpy(p, &addr, sizeof(addr));
479 # warning unknown architecture
482 return vtable_prototype_size;
486 static void initVtables(void)
488 if (DisableVtables) {
490 _objc_inform("VTABLES: vtable dispatch disabled by OBJC_DISABLE_VTABLES");
493 vtableSelectors = NULL;
494 vtableTrampolines = NULL;
498 const char * const *names;
502 names = defaultVtableGC;
503 vtableCount = sizeof(defaultVtableGC) / sizeof(defaultVtableGC[0]);
505 names = defaultVtable;
506 vtableCount = sizeof(defaultVtable) / sizeof(defaultVtable[0]);
508 if (vtableCount > vtableMax) vtableCount = vtableMax;
510 vtableSelectors = (SEL*)_malloc_internal(vtableCount * sizeof(SEL));
511 vtableTrampolines = (IMP*)_malloc_internal(vtableCount * sizeof(IMP));
513 // Built-in trampolines and their descriptors
515 size_t defaultVtableTrampolineCount =
516 sizeof(defaultVtableTrampolines) / sizeof(defaultVtableTrampolines[0]);
518 // debug: use generated code for 3/4 of the table
519 // Disabled even in Debug builds to avoid breaking backtrace symbol names.
520 // defaultVtableTrampolineCount /= 4;
523 for (i = 0; i < defaultVtableTrampolineCount && i < vtableCount; i++) {
524 vtableSelectors[i] = sel_registerName(names[i]);
525 vtableTrampolines[i] = defaultVtableTrampolines[i];
527 appendTrampolines(&defaultVtableTrampolineDescriptors);
530 // Generated trampolines and their descriptors
532 if (vtableCount > defaultVtableTrampolineCount) {
533 // Memory for trampoline code
534 size_t generatedCount =
535 vtableCount - defaultVtableTrampolineCount;
537 const int align = 16;
539 round_page(sizeof(objc_trampoline_header) + align +
540 generatedCount * (sizeof(objc_trampoline_descriptor)
541 + vtable_prototype_size + align));
542 void *codeAddr = mmap(0, codeSize, PROT_READ|PROT_WRITE,
543 MAP_PRIVATE|MAP_ANON,
544 VM_MAKE_TAG(VM_MEMORY_OBJC_DISPATCHERS), 0);
545 uint8_t *t = (uint8_t *)codeAddr;
548 objc_trampoline_header *thdr = (objc_trampoline_header *)t;
549 thdr->headerSize = sizeof(objc_trampoline_header);
550 thdr->descSize = sizeof(objc_trampoline_descriptor);
551 thdr->descCount = (uint32_t)generatedCount;
554 // Trampoline descriptors
555 objc_trampoline_descriptor *tdesc = (objc_trampoline_descriptor *)(thdr+1);
556 t = (uint8_t *)&tdesc[generatedCount];
557 t += align - ((uintptr_t)t % align);
561 for (i = defaultVtableTrampolineCount, tdi = 0;
565 vtableSelectors[i] = sel_registerName(names[i]);
566 if (ignoreSelector(vtableSelectors[i])) {
567 vtableTrampolines[i] = (IMP)&vtable_ignored;
568 tdesc[tdi].offset = 0;
569 tdesc[tdi].flags = 0;
571 vtableTrampolines[i] = (IMP)t;
573 (uint32_t)((uintptr_t)t - (uintptr_t)&tdesc[tdi]);
575 OBJC_TRAMPOLINE_MESSAGE|OBJC_TRAMPOLINE_VTABLE;
577 t += makeVtableTrampoline(t, i);
578 t += align - ((uintptr_t)t % align);
582 appendTrampolines(thdr);
583 sys_icache_invalidate(codeAddr, codeSize);
584 mprotect(codeAddr, codeSize, PROT_READ|PROT_EXEC);
589 for (i = 0; i < vtableCount; i++) {
590 _objc_inform("VTABLES: vtable[%zu] %p %s",
591 i, vtableTrampolines[i],
592 sel_getName(vtableSelectors[i]));
596 if (PrintVtableImages) {
597 _objc_inform("VTABLE IMAGES: '#' implemented by class");
598 _objc_inform("VTABLE IMAGES: '-' inherited from superclass");
599 _objc_inform("VTABLE IMAGES: ' ' not implemented");
600 for (i = 0; i <= vtableCount; i++) {
601 char spaces[vtableCount+1+1];
603 for (j = 0; j < i; j++) {
607 _objc_inform("VTABLE IMAGES: %s%s", spaces,
608 i<vtableCount ? sel_getName(vtableSelectors[i]) : "");
612 if (PrintVtables || PrintVtableImages) {
614 for (i = 0; i < vtableCount; i++) {
615 vtableStrlen += strlen(sel_getName(vtableSelectors[i]));
621 static int vtable_getIndex(SEL sel)
624 for (i = 0; i < vtableCount; i++) {
625 if (vtableSelectors[i] == sel) return i;
630 static BOOL vtable_containsSelector(SEL sel)
632 return (vtable_getIndex(sel) < 0) ? NO : YES;
635 static void printVtableOverrides(class_t *cls, class_t *supercls)
637 char overrideMap[vtableCount+1];
641 size_t overridesBufferSize = vtableStrlen + 2*vtableCount + 1;
643 (char *)_calloc_internal(overridesBufferSize, 1);
644 for (i = 0; i < vtableCount; i++) {
645 if (ignoreSelector(vtableSelectors[i])) {
646 overrideMap[i] = '-';
649 if (getMethodNoSuper_nolock(cls, vtableSelectors[i])) {
650 strlcat(overrides, sel_getName(vtableSelectors[i]), overridesBufferSize);
651 strlcat(overrides, ", ", overridesBufferSize);
652 overrideMap[i] = '#';
653 } else if (getMethod_nolock(cls, vtableSelectors[i])) {
654 overrideMap[i] = '-';
656 overrideMap[i] = ' ';
660 _objc_inform("VTABLES: %s%s implements %s",
661 getName(cls), isMetaClass(cls) ? "(meta)" : "",
664 _free_internal(overrides);
667 for (i = 0; i < vtableCount; i++) {
668 overrideMap[i] = '#';
672 if (PrintVtableImages) {
673 overrideMap[vtableCount] = '\0';
674 _objc_inform("VTABLE IMAGES: %s %s%s", overrideMap,
675 getName(cls), isMetaClass(cls) ? "(meta)" : "");
679 /***********************************************************************
681 * Rebuilds vtable for cls, using superclass's vtable if appropriate.
682 * Assumes superclass's vtable is up to date.
683 * Does nothing to subclass vtables.
684 * Locking: runtimeLock must be held by the caller.
685 **********************************************************************/
686 static void updateVtable(class_t *cls, BOOL force)
688 rwlock_assert_writing(&runtimeLock);
690 // Keep default vtable until +initialize is complete.
691 // Default vtable redirects to objc_msgSend, which
692 // enforces +initialize locking.
693 if (!force && !_class_isInitialized((Class)cls)) {
696 _objc_inform("VTABLES: KEEPING DEFAULT vtable for "
697 "uninitialized class %s%s",
698 getName(cls), isMetaClass(cls) ? "(meta)" : "");
704 // Decide whether this class can share its superclass's vtable.
706 class_t *supercls = getSuperclass(cls);
707 BOOL needVtable = NO;
710 // Root classes always need a vtable
713 else if (cls->data()->flags & RW_SPECIALIZED_VTABLE) {
714 // Once you have your own vtable, you never go back
718 for (i = 0; i < vtableCount; i++) {
719 if (ignoreSelector(vtableSelectors[i])) continue;
720 method_t *m = getMethodNoSuper_nolock(cls, vtableSelectors[i]);
721 // assume any local implementation differs from super's
729 // Build a vtable for this class, or not.
733 _objc_inform("VTABLES: USING SUPERCLASS vtable for class %s%s %p",
734 getName(cls), isMetaClass(cls) ? "(meta)" : "", cls);
736 cls->vtable = supercls->vtable;
740 _objc_inform("VTABLES: %s vtable for class %s%s %p",
741 (cls->data()->flags & RW_SPECIALIZED_VTABLE) ?
742 "UPDATING SPECIALIZED" : "CREATING SPECIALIZED",
743 getName(cls), isMetaClass(cls) ? "(meta)" : "", cls);
745 if (PrintVtables || PrintVtableImages) {
746 printVtableOverrides(cls, supercls);
750 IMP *super_vtable = supercls ? supercls->vtable : &_objc_empty_vtable;
751 // fixme use msgForward (instead of msgSend from empty vtable) ?
753 if (cls->data()->flags & RW_SPECIALIZED_VTABLE) {
754 // update cls->vtable in place
755 new_vtable = cls->vtable;
756 if (new_vtable == &_objc_empty_vtable) {
757 // oops - our vtable is not as specialized as we thought
758 // This is probably the broken memcpy of __NSCFConstantString.
760 new_vtable = (IMP*)malloc(vtableCount * sizeof(IMP));
762 assert(new_vtable != &_objc_empty_vtable);
765 new_vtable = (IMP*)malloc(vtableCount * sizeof(IMP));
766 changeInfo(cls, RW_SPECIALIZED_VTABLE, 0);
769 for (i = 0; i < vtableCount; i++) {
770 if (ignoreSelector(vtableSelectors[i])) {
771 new_vtable[i] = (IMP)&vtable_ignored;
773 method_t *m = getMethodNoSuper_nolock(cls, vtableSelectors[i]);
774 if (m) new_vtable[i] = _method_getImplementation(m);
775 else new_vtable[i] = super_vtable[i];
779 if (cls->vtable != new_vtable) {
780 // don't let other threads see uninitialized parts of new_vtable
782 cls->vtable = new_vtable;
791 static void initVtables(void)
794 _objc_inform("VTABLES: no vtables on this architecture");
798 static BOOL vtable_containsSelector(SEL sel)
803 static void updateVtable(class_t *cls, BOOL force)
817 category_pair_t list[0]; // variable-size
820 #define FOREACH_METHOD_LIST(_mlist, _cls, code) \
822 const method_list_t *_mlist; \
823 if (_cls->data()->method_lists) { \
824 if (_cls->data()->flags & RW_METHOD_ARRAY) { \
825 method_list_t **_mlistp; \
826 for (_mlistp=_cls->data()->method_lists; *_mlistp; _mlistp++){\
831 _mlist = _cls->data()->method_list; \
837 #define FOREACH_REALIZED_CLASS_AND_SUBCLASS(_c, _cls, code) \
839 rwlock_assert_writing(&runtimeLock); \
840 class_t *_top = _cls; \
841 class_t *_c = _top; \
845 if (_c->data()->firstSubclass) { \
846 _c = _c->data()->firstSubclass; \
848 while (!_c->data()->nextSiblingClass && _c != _top) { \
849 _c = getSuperclass(_c); \
851 if (_c == _top) break; \
852 _c = _c->data()->nextSiblingClass; \
856 /* nil means all realized classes */ \
857 NXHashTable *_classes = realizedClasses(); \
858 NXHashTable *_metaclasses = realizedMetaclasses(); \
859 NXHashState _state; \
860 _state = NXInitHashState(_classes); \
861 while (NXNextHashState(_classes, &_state, (void**)&_c)) \
865 _state = NXInitHashState(_metaclasses); \
866 while (NXNextHashState(_metaclasses, &_state, (void**)&_c)) \
875 Low two bits of mlist->entsize is used as the fixed-up marker.
876 PREOPTIMIZED VERSION:
877 Fixed-up method lists get entsize&3 == 3.
878 dyld shared cache sets this for method lists it preoptimizes.
879 UN-PREOPTIMIZED VERSION:
880 Fixed-up method lists get entsize&3 == 1.
881 dyld shared cache uses 3, but those aren't trusted.
884 static uint32_t fixed_up_method_list = 3;
887 disableSharedCacheOptimizations(void)
889 fixed_up_method_list = 1;
892 static BOOL isMethodListFixedUp(const method_list_t *mlist)
894 return (mlist->entsize_NEVER_USE & 3) == fixed_up_method_list;
897 static void setMethodListFixedUp(method_list_t *mlist)
899 rwlock_assert_writing(&runtimeLock);
900 assert(!isMethodListFixedUp(mlist));
901 mlist->entsize_NEVER_USE = (mlist->entsize_NEVER_USE & ~3) | fixed_up_method_list;
905 static size_t chained_property_list_size(const chained_property_list *plist)
907 return sizeof(chained_property_list) +
908 plist->count * sizeof(property_t);
912 static size_t protocol_list_size(const protocol_list_t *plist)
914 return sizeof(protocol_list_t) + plist->count * sizeof(protocol_t *);
918 // low bit used by dyld shared cache
919 static uint32_t method_list_entsize(const method_list_t *mlist)
921 return mlist->entsize_NEVER_USE & ~(uint32_t)3;
924 static size_t method_list_size(const method_list_t *mlist)
926 return sizeof(method_list_t) + (mlist->count-1)*method_list_entsize(mlist);
929 static method_t *method_list_nth(const method_list_t *mlist, uint32_t i)
931 assert(i < mlist->count);
932 return (method_t *)(i*method_list_entsize(mlist) + (char *)&mlist->first);
935 static uint32_t method_list_count(const method_list_t *mlist)
937 return mlist ? mlist->count : 0;
940 static void method_list_swap(method_list_t *mlist, uint32_t i, uint32_t j)
942 size_t entsize = method_list_entsize(mlist);
944 memcpy(temp, method_list_nth(mlist, i), entsize);
945 memcpy(method_list_nth(mlist, i), method_list_nth(mlist, j), entsize);
946 memcpy(method_list_nth(mlist, j), temp, entsize);
949 static uint32_t method_list_index(const method_list_t *mlist,const method_t *m)
951 uint32_t i = (uint32_t)(((uintptr_t)m - (uintptr_t)mlist) / method_list_entsize(mlist));
952 assert(i < mlist->count);
957 static size_t ivar_list_size(const ivar_list_t *ilist)
959 return sizeof(ivar_list_t) + (ilist->count-1) * ilist->entsize;
962 static ivar_t *ivar_list_nth(const ivar_list_t *ilist, uint32_t i)
964 return (ivar_t *)(i*ilist->entsize + (char *)&ilist->first);
968 // part of ivar_t, with non-deprecated alignment
976 static uint32_t ivar_alignment(const ivar_t *ivar)
978 uint32_t alignment = ((ivar_alignment_t *)ivar)->alignment;
979 if (alignment == (uint32_t)-1) alignment = (uint32_t)WORD_SHIFT;
984 static method_list_t *cat_method_list(const category_t *cat, BOOL isMeta)
986 if (!cat) return NULL;
988 if (isMeta) return cat->classMethods;
989 else return cat->instanceMethods;
992 static uint32_t cat_method_count(const category_t *cat, BOOL isMeta)
994 method_list_t *cmlist = cat_method_list(cat, isMeta);
995 return cmlist ? cmlist->count : 0;
998 static method_t *cat_method_nth(const category_t *cat, BOOL isMeta, uint32_t i)
1000 method_list_t *cmlist = cat_method_list(cat, isMeta);
1001 if (!cmlist) return NULL;
1003 return method_list_nth(cmlist, i);
1008 property_list_nth(const property_list_t *plist, uint32_t i)
1010 return (property_t *)(i*plist->entsize + (char *)&plist->first);
1013 // fixme don't chain property lists
1014 typedef struct chained_property_list {
1015 struct chained_property_list *next;
1017 property_t list[0]; // variable-size
1018 } chained_property_list;
1021 static void try_free(const void *p)
1023 if (p && malloc_size(p)) free((void *)p);
1027 /***********************************************************************
1029 * Reallocates rw->ro if necessary to make it writeable.
1030 * Locking: runtimeLock must be held by the caller.
1031 **********************************************************************/
1032 static class_ro_t *make_ro_writeable(class_rw_t *rw)
1034 rwlock_assert_writing(&runtimeLock);
1036 if (rw->flags & RW_COPIED_RO) {
1037 // already writeable, do nothing
1039 class_ro_t *ro = (class_ro_t *)
1040 _memdup_internal(rw->ro, sizeof(*rw->ro));
1042 rw->flags |= RW_COPIED_RO;
1044 return (class_ro_t *)rw->ro;
1048 /***********************************************************************
1049 * unattachedCategories
1050 * Returns the class => categories map of unattached categories.
1051 * Locking: runtimeLock must be held by the caller.
1052 **********************************************************************/
1053 static NXMapTable *unattachedCategories(void)
1055 rwlock_assert_writing(&runtimeLock);
1057 static NXMapTable *category_map = NULL;
1059 if (category_map) return category_map;
1061 // fixme initial map size
1062 category_map = NXCreateMapTableFromZone(NXPtrValueMapPrototype, 16,
1063 _objc_internal_zone());
1065 return category_map;
1069 /***********************************************************************
1070 * addUnattachedCategoryForClass
1071 * Records an unattached category.
1072 * Locking: runtimeLock must be held by the caller.
1073 **********************************************************************/
1074 static void addUnattachedCategoryForClass(category_t *cat, class_t *cls,
1075 header_info *catHeader)
1077 rwlock_assert_writing(&runtimeLock);
1079 BOOL catFromBundle = (catHeader->mhdr->filetype == MH_BUNDLE) ? YES: NO;
1081 // DO NOT use cat->cls! cls may be cat->cls->isa instead
1082 NXMapTable *cats = unattachedCategories();
1083 category_list *list;
1085 list = (category_list *)NXMapGet(cats, cls);
1087 list = (category_list *)
1088 _calloc_internal(sizeof(*list) + sizeof(list->list[0]), 1);
1090 list = (category_list *)
1091 _realloc_internal(list, sizeof(*list) + sizeof(list->list[0]) * (list->count + 1));
1093 list->list[list->count++] = (category_pair_t){cat, catFromBundle};
1094 NXMapInsert(cats, cls, list);
1098 /***********************************************************************
1099 * removeUnattachedCategoryForClass
1100 * Removes an unattached category.
1101 * Locking: runtimeLock must be held by the caller.
1102 **********************************************************************/
1103 static void removeUnattachedCategoryForClass(category_t *cat, class_t *cls)
1105 rwlock_assert_writing(&runtimeLock);
1107 // DO NOT use cat->cls! cls may be cat->cls->isa instead
1108 NXMapTable *cats = unattachedCategories();
1109 category_list *list;
1111 list = (category_list *)NXMapGet(cats, cls);
1115 for (i = 0; i < list->count; i++) {
1116 if (list->list[i].cat == cat) {
1117 // shift entries to preserve list order
1118 memmove(&list->list[i], &list->list[i+1],
1119 (list->count-i-1) * sizeof(list->list[i]));
1127 /***********************************************************************
1128 * unattachedCategoriesForClass
1129 * Returns the list of unattached categories for a class, and
1130 * deletes them from the list.
1131 * The result must be freed by the caller.
1132 * Locking: runtimeLock must be held by the caller.
1133 **********************************************************************/
1134 static category_list *unattachedCategoriesForClass(class_t *cls)
1136 rwlock_assert_writing(&runtimeLock);
1137 return (category_list *)NXMapRemove(unattachedCategories(), cls);
1141 /***********************************************************************
1143 * Returns YES if class cls has been realized.
1144 * Locking: To prevent concurrent realization, hold runtimeLock.
1145 **********************************************************************/
1146 static BOOL isRealized(class_t *cls)
1148 return (cls->data()->flags & RW_REALIZED) ? YES : NO;
1152 /***********************************************************************
1154 * Returns YES if class cls is an unrealized future class.
1155 * Locking: To prevent concurrent realization, hold runtimeLock.
1156 **********************************************************************/
1158 // currently used in asserts only
1159 static BOOL isFuture(class_t *cls)
1161 return (cls->data()->flags & RW_FUTURE) ? YES : NO;
1166 /***********************************************************************
1168 * Returns class NSObject.
1170 **********************************************************************/
1171 static class_t *classNSObject(void)
1173 extern class_t OBJC_CLASS_$_NSObject;
1174 return &OBJC_CLASS_$_NSObject;
1178 /***********************************************************************
1180 * Implementation of PrintReplacedMethods / OBJC_PRINT_REPLACED_METHODS.
1181 * Warn about methods from cats that override other methods in cats or cls.
1182 * Assumes no methods from cats have been added to cls yet.
1183 **********************************************************************/
1184 static void printReplacements(class_t *cls, category_list *cats)
1187 BOOL isMeta = isMetaClass(cls);
1191 // Newest categories are LAST in cats
1192 // Later categories override earlier ones.
1193 for (c = 0; c < cats->count; c++) {
1194 category_t *cat = cats->list[c].cat;
1195 uint32_t cmCount = cat_method_count(cat, isMeta);
1197 for (m = 0; m < cmCount; m++) {
1199 method_t *meth2 = NULL;
1200 method_t *meth = cat_method_nth(cat, isMeta, m);
1201 SEL s = sel_registerName((const char *)meth->name);
1203 // Don't warn about GC-ignored selectors
1204 if (ignoreSelector(s)) continue;
1206 // Look for method in earlier categories
1207 for (c2 = 0; c2 < c; c2++) {
1208 category_t *cat2 = cats->list[c2].cat;
1209 uint32_t cm2Count = cat_method_count(cat2, isMeta);
1210 for (m2 = 0; m2 < cm2Count; m2++) {
1211 meth2 = cat_method_nth(cat2, isMeta, m2);
1212 SEL s2 = sel_registerName((const char *)meth2->name);
1213 if (s == s2) goto whine;
1217 // Look for method in cls
1218 FOREACH_METHOD_LIST(mlist, cls, {
1219 for (m2 = 0; m2 < mlist->count; m2++) {
1220 meth2 = method_list_nth(mlist, m2);
1221 SEL s2 = sel_registerName((const char *)meth2->name);
1222 if (s == s2) goto whine;
1226 // Didn't find any override.
1230 // Found an override.
1231 logReplacedMethod(getName(cls), s, isMetaClass(cls), cat->name,
1232 _method_getImplementation(meth2),
1233 _method_getImplementation(meth));
1239 static BOOL isBundleClass(class_t *cls)
1241 return (cls->data()->ro->flags & RO_FROM_BUNDLE) ? YES : NO;
1245 static method_list_t *
1246 fixupMethodList(method_list_t *mlist, bool bundleCopy, bool sort)
1248 assert(!isMethodListFixedUp(mlist));
1250 mlist = (method_list_t *)
1251 _memdup_internal(mlist, method_list_size(mlist));
1253 // fixme lock less in attachMethodLists ?
1256 // Unique selectors in list.
1258 for (m = 0; m < mlist->count; m++) {
1259 method_t *meth = method_list_nth(mlist, m);
1260 SEL sel = sel_registerNameNoLock((const char *)meth->name, bundleCopy);
1263 if (ignoreSelector(sel)) {
1264 meth->imp = (IMP)&_objc_ignored_method;
1270 // Sort by selector address.
1272 method_t::SortBySELAddress sorter;
1273 std::stable_sort(mlist->begin(), mlist->end(), sorter);
1276 // Mark method list as uniqued and sorted
1277 setMethodListFixedUp(mlist);
1284 attachMethodLists(class_t *cls, method_list_t **addedLists, int addedCount,
1285 BOOL baseMethods, BOOL methodsFromBundle,
1286 BOOL *inoutVtablesAffected)
1288 rwlock_assert_writing(&runtimeLock);
1290 // Don't scan redundantly
1291 bool scanForCustomRR = !UseGC && !cls->hasCustomRR();
1292 bool scanForCustomAWZ = !UseGC && !cls->hasCustomAWZ();
1294 // RR special cases:
1295 // NSObject's base instance methods are not custom RR.
1296 // All other root classes are custom RR.
1297 // updateCustomRR_AWZ also knows about these cases.
1298 if (baseMethods && scanForCustomRR && cls->isRootClass()) {
1299 if (cls != classNSObject()) {
1300 cls->setHasCustomRR();
1302 scanForCustomRR = false;
1305 // AWZ special cases:
1306 // NSObject's base class methods are not custom AWZ.
1307 // All other root metaclasses are custom AWZ.
1308 // updateCustomRR_AWZ also knows about these cases.
1309 if (baseMethods && scanForCustomAWZ && cls->isRootMetaclass()) {
1310 if (cls != classNSObject()->isa) {
1311 cls->setHasCustomAWZ();
1313 scanForCustomAWZ = false;
1316 // Method list array is NULL-terminated.
1317 // Some elements of lists are NULL; we must filter them out.
1319 method_list_t *oldBuf[2];
1320 method_list_t **oldLists;
1322 if (cls->data()->flags & RW_METHOD_ARRAY) {
1323 oldLists = cls->data()->method_lists;
1325 oldBuf[0] = cls->data()->method_list;
1330 while (oldLists[oldCount]) oldCount++;
1333 int newCount = oldCount;
1334 for (int i = 0; i < addedCount; i++) {
1335 if (addedLists[i]) newCount++; // only non-NULL entries get added
1338 method_list_t *newBuf[2];
1339 method_list_t **newLists;
1341 newLists = (method_list_t **)
1342 _malloc_internal((1 + newCount) * sizeof(*newLists));
1347 // Add method lists to array.
1348 // Reallocate un-fixed method lists.
1349 // The new methods are PREPENDED to the method list array.
1353 for (i = 0; i < addedCount; i++) {
1354 method_list_t *mlist = addedLists[i];
1355 if (!mlist) continue;
1357 // Fixup selectors if necessary
1358 if (!isMethodListFixedUp(mlist)) {
1359 mlist = fixupMethodList(mlist, methodsFromBundle, true/*sort*/);
1362 // Scan for vtable updates
1363 if (inoutVtablesAffected && !*inoutVtablesAffected) {
1365 for (m = 0; m < mlist->count; m++) {
1366 SEL sel = method_list_nth(mlist, m)->name;
1367 if (vtable_containsSelector(sel)) {
1368 *inoutVtablesAffected = YES;
1374 // Scan for method implementations tracked by the class's flags
1375 for (uint32_t m = 0;
1376 (scanForCustomRR || scanForCustomAWZ) && m < mlist->count;
1379 SEL sel = method_list_nth(mlist, m)->name;
1380 if (scanForCustomRR && isRRSelector(sel)) {
1381 cls->setHasCustomRR();
1382 scanForCustomRR = false;
1383 } else if (scanForCustomAWZ && isAWZSelector(sel)) {
1384 cls->setHasCustomAWZ();
1385 scanForCustomAWZ = false;
1389 // Fill method list array
1390 newLists[newCount++] = mlist;
1393 // Copy old methods to the method list array
1394 for (i = 0; i < oldCount; i++) {
1395 newLists[newCount++] = oldLists[i];
1397 if (oldLists && oldLists != oldBuf) free(oldLists);
1400 newLists[newCount] = NULL;
1403 assert(newLists != newBuf);
1404 cls->data()->method_lists = newLists;
1405 changeInfo(cls, RW_METHOD_ARRAY, 0);
1407 assert(newLists == newBuf);
1408 cls->data()->method_list = newLists[0];
1409 assert(!(cls->data()->flags & RW_METHOD_ARRAY));
1414 attachCategoryMethods(class_t *cls, category_list *cats,
1415 BOOL *inoutVtablesAffected)
1418 if (PrintReplacedMethods) printReplacements(cls, cats);
1420 BOOL isMeta = isMetaClass(cls);
1421 method_list_t **mlists = (method_list_t **)
1422 _malloc_internal(cats->count * sizeof(*mlists));
1424 // Count backwards through cats to get newest categories first
1426 int i = cats->count;
1427 BOOL fromBundle = NO;
1429 method_list_t *mlist = cat_method_list(cats->list[i].cat, isMeta);
1431 mlists[mcount++] = mlist;
1432 fromBundle |= cats->list[i].fromBundle;
1436 attachMethodLists(cls, mlists, mcount, NO, fromBundle, inoutVtablesAffected);
1438 _free_internal(mlists);
1443 static chained_property_list *
1444 buildPropertyList(const property_list_t *plist, category_list *cats, BOOL isMeta)
1446 chained_property_list *newlist;
1450 // Count properties in all lists.
1451 if (plist) count = plist->count;
1453 for (c = 0; c < cats->count; c++) {
1454 category_t *cat = cats->list[c].cat;
1456 if (isMeta && cat->classProperties) {
1457 count += cat->classProperties->count;
1460 if (!isMeta && cat->instanceProperties) {
1461 count += cat->instanceProperties->count;
1466 if (count == 0) return NULL;
1468 // Allocate new list.
1469 newlist = (chained_property_list *)
1470 _malloc_internal(sizeof(*newlist) + count * sizeof(property_t));
1472 newlist->next = NULL;
1474 // Copy properties; newest categories first, then ordinary properties
1478 property_list_t *cplist;
1479 category_t *cat = cats->list[c].cat;
1482 cplist = cat->classProperties;
1485 cplist = cat->instanceProperties;
1488 for (p = 0; p < cplist->count; p++) {
1489 newlist->list[newlist->count++] =
1490 *property_list_nth(cplist, p);
1496 for (p = 0; p < plist->count; p++) {
1497 newlist->list[newlist->count++] = *property_list_nth(plist, p);
1501 assert(newlist->count == count);
1507 static const protocol_list_t **
1508 buildProtocolList(category_list *cats, const protocol_list_t *base,
1509 const protocol_list_t **protos)
1511 const protocol_list_t **p, **newp;
1512 const protocol_list_t **newprotos;
1513 unsigned int count = 0;
1516 // count protocol list in base
1519 // count protocol lists in cats
1520 if (cats) for (i = 0; i < cats->count; i++) {
1521 category_t *cat = cats->list[i].cat;
1522 if (cat->protocols) count++;
1525 // no base or category protocols? return existing protocols unchanged
1526 if (count == 0) return protos;
1528 // count protocol lists in protos
1529 for (p = protos; p && *p; p++) {
1533 if (count == 0) return NULL;
1535 newprotos = (const protocol_list_t **)
1536 _malloc_internal((count+1) * sizeof(protocol_list_t *));
1543 for (p = protos; p && *p; p++) {
1547 if (cats) for (i = 0; i < cats->count; i++) {
1548 category_t *cat = cats->list[i].cat;
1549 if (cat->protocols) {
1550 *newp++ = cat->protocols;
1560 /***********************************************************************
1562 * Fixes up cls's method list, protocol list, and property list.
1563 * Attaches any outstanding categories.
1565 * Locking: runtimeLock must be held by the caller
1566 **********************************************************************/
1567 static void methodizeClass(class_t *cls)
1569 category_list *cats;
1572 rwlock_assert_writing(&runtimeLock);
1574 isMeta = isMetaClass(cls);
1576 // Methodizing for the first time
1577 if (PrintConnecting) {
1578 _objc_inform("CLASS: methodizing class '%s' %s",
1579 getName(cls), isMeta ? "(meta)" : "");
1582 // Build method and protocol and property lists.
1583 // Include methods and protocols and properties from categories, if any
1585 attachMethodLists(cls, (method_list_t **)&cls->data()->ro->baseMethods, 1,
1586 YES, isBundleClass(cls), NULL);
1588 // Root classes get bonus method implementations if they don't have
1589 // them already. These apply before category replacements.
1591 if (cls->isRootMetaclass()) {
1593 addMethod(cls, SEL_initialize, (IMP)&objc_noop_imp, "", NO);
1596 cats = unattachedCategoriesForClass(cls);
1597 attachCategoryMethods(cls, cats, NULL);
1599 if (cats || cls->data()->ro->baseProperties) {
1600 cls->data()->properties =
1601 buildPropertyList(cls->data()->ro->baseProperties, cats, isMeta);
1604 if (cats || cls->data()->ro->baseProtocols) {
1605 cls->data()->protocols =
1606 buildProtocolList(cats, cls->data()->ro->baseProtocols, NULL);
1609 if (PrintConnecting) {
1612 for (i = 0; i < cats->count; i++) {
1613 _objc_inform("CLASS: attached category %c%s(%s)",
1615 getName(cls), cats->list[i].cat->name);
1620 if (cats) _free_internal(cats);
1622 // No vtable until +initialize completes
1623 assert(cls->vtable == &_objc_empty_vtable);
1626 // Debug: sanity-check all SELs; log method list contents
1627 FOREACH_METHOD_LIST(mlist, cls, {
1628 method_list_t::method_iterator iter = mlist->begin();
1629 method_list_t::method_iterator end = mlist->end();
1630 for ( ; iter != end; ++iter) {
1631 if (PrintConnecting) {
1632 _objc_inform("METHOD %c[%s %s]", isMeta ? '+' : '-',
1633 getName(cls), sel_getName(iter->name));
1635 assert(ignoreSelector(iter->name) || sel_registerName(sel_getName(iter->name))==iter->name);
1642 /***********************************************************************
1644 * Attach outstanding categories to an existing class.
1645 * Fixes up cls's method list, protocol list, and property list.
1646 * Updates method caches and vtables for cls and its subclasses.
1647 * Locking: runtimeLock must be held by the caller
1648 **********************************************************************/
1649 static void remethodizeClass(class_t *cls)
1651 category_list *cats;
1654 rwlock_assert_writing(&runtimeLock);
1656 isMeta = isMetaClass(cls);
1658 // Re-methodizing: check for more categories
1659 if ((cats = unattachedCategoriesForClass(cls))) {
1660 chained_property_list *newproperties;
1661 const protocol_list_t **newprotos;
1663 if (PrintConnecting) {
1664 _objc_inform("CLASS: attaching categories to class '%s' %s",
1665 getName(cls), isMeta ? "(meta)" : "");
1668 // Update methods, properties, protocols
1670 BOOL vtableAffected = NO;
1671 attachCategoryMethods(cls, cats, &vtableAffected);
1673 newproperties = buildPropertyList(NULL, cats, isMeta);
1674 if (newproperties) {
1675 newproperties->next = cls->data()->properties;
1676 cls->data()->properties = newproperties;
1679 newprotos = buildProtocolList(cats, NULL, cls->data()->protocols);
1680 if (cls->data()->protocols && cls->data()->protocols != newprotos) {
1681 _free_internal(cls->data()->protocols);
1683 cls->data()->protocols = newprotos;
1685 _free_internal(cats);
1687 // Update method caches and vtables
1689 if (vtableAffected) flushVtables(cls);
1694 /***********************************************************************
1696 * Atomically sets and clears some bits in cls's info field.
1697 * set and clear must not overlap.
1698 **********************************************************************/
1699 static void changeInfo(class_t *cls, unsigned int set, unsigned int clear)
1701 uint32_t oldf, newf;
1703 assert(isFuture(cls) || isRealized(cls));
1706 oldf = cls->data()->flags;
1707 newf = (oldf | set) & ~clear;
1708 } while (!OSAtomicCompareAndSwap32Barrier(oldf, newf, (volatile int32_t *)&cls->data()->flags));
1712 /***********************************************************************
1714 * Looks up a class by name. The class MIGHT NOT be realized.
1715 * Locking: runtimeLock must be read- or write-locked by the caller.
1716 **********************************************************************/
1718 // This is a misnomer: gdb_objc_realized_classes is actually a list of
1719 // named classes not in the dyld shared cache, whether realized or not.
1720 NXMapTable *gdb_objc_realized_classes; // exported for debuggers in objc-gdb.h
1722 static class_t *getClass(const char *name)
1724 rwlock_assert_locked(&runtimeLock);
1726 // allocated in _read_images
1727 assert(gdb_objc_realized_classes);
1729 // Try runtime-allocated table
1730 class_t *result = (class_t *)NXMapGet(gdb_objc_realized_classes, name);
1731 if (result) return result;
1733 // Try table from dyld shared cache
1734 return getPreoptimizedClass(name);
1738 /***********************************************************************
1740 * Adds name => cls to the named non-meta class map.
1741 * Warns about duplicate class names and keeps the old mapping.
1742 * Locking: runtimeLock must be held by the caller
1743 **********************************************************************/
1744 static void addNamedClass(class_t *cls, const char *name)
1746 rwlock_assert_writing(&runtimeLock);
1748 if ((old = getClass(name))) {
1749 inform_duplicate(name, (Class)old, (Class)cls);
1751 NXMapInsert(gdb_objc_realized_classes, name, cls);
1753 assert(!(cls->data()->flags & RO_META));
1755 // wrong: constructed classes are already realized when they get here
1756 // assert(!isRealized(cls));
1760 /***********************************************************************
1762 * Removes cls from the name => cls map.
1763 * Locking: runtimeLock must be held by the caller
1764 **********************************************************************/
1765 static void removeNamedClass(class_t *cls, const char *name)
1767 rwlock_assert_writing(&runtimeLock);
1768 assert(!(cls->data()->flags & RO_META));
1769 if (cls == NXMapGet(gdb_objc_realized_classes, name)) {
1770 NXMapRemove(gdb_objc_realized_classes, name);
1772 // cls has a name collision with another class - don't remove the other
1777 /***********************************************************************
1779 * Returns the class list for realized non-meta classes.
1780 * Locking: runtimeLock must be read- or write-locked by the caller
1781 **********************************************************************/
1782 static NXHashTable *realized_class_hash = NULL;
1784 static NXHashTable *realizedClasses(void)
1786 rwlock_assert_locked(&runtimeLock);
1788 // allocated in _read_images
1789 assert(realized_class_hash);
1791 return realized_class_hash;
1795 /***********************************************************************
1796 * realizedMetaclasses
1797 * Returns the class list for realized metaclasses.
1798 * Locking: runtimeLock must be read- or write-locked by the caller
1799 **********************************************************************/
1800 static NXHashTable *realized_metaclass_hash = NULL;
1801 static NXHashTable *realizedMetaclasses(void)
1803 rwlock_assert_locked(&runtimeLock);
1805 // allocated in _read_images
1806 assert(realized_metaclass_hash);
1808 return realized_metaclass_hash;
1812 /***********************************************************************
1814 * Adds cls to the realized non-meta class hash.
1815 * Locking: runtimeLock must be held by the caller
1816 **********************************************************************/
1817 static void addRealizedClass(class_t *cls)
1819 rwlock_assert_writing(&runtimeLock);
1821 old = NXHashInsert(realizedClasses(), cls);
1822 objc_addRegisteredClass((Class)cls);
1823 assert(!isMetaClass(cls));
1828 /***********************************************************************
1829 * removeRealizedClass
1830 * Removes cls from the realized non-meta class hash.
1831 * Locking: runtimeLock must be held by the caller
1832 **********************************************************************/
1833 static void removeRealizedClass(class_t *cls)
1835 rwlock_assert_writing(&runtimeLock);
1836 if (isRealized(cls)) {
1837 assert(!isMetaClass(cls));
1838 NXHashRemove(realizedClasses(), cls);
1839 objc_removeRegisteredClass((Class)cls);
1844 /***********************************************************************
1845 * addRealizedMetaclass
1846 * Adds cls to the realized metaclass hash.
1847 * Locking: runtimeLock must be held by the caller
1848 **********************************************************************/
1849 static void addRealizedMetaclass(class_t *cls)
1851 rwlock_assert_writing(&runtimeLock);
1853 old = NXHashInsert(realizedMetaclasses(), cls);
1854 assert(isMetaClass(cls));
1859 /***********************************************************************
1860 * removeRealizedMetaclass
1861 * Removes cls from the realized metaclass hash.
1862 * Locking: runtimeLock must be held by the caller
1863 **********************************************************************/
1864 static void removeRealizedMetaclass(class_t *cls)
1866 rwlock_assert_writing(&runtimeLock);
1867 if (isRealized(cls)) {
1868 assert(isMetaClass(cls));
1869 NXHashRemove(realizedMetaclasses(), cls);
1874 /***********************************************************************
1875 * futureNamedClasses
1876 * Returns the classname => future class map for unrealized future classes.
1877 * Locking: runtimeLock must be held by the caller
1878 **********************************************************************/
1879 static NXMapTable *futureNamedClasses(void)
1881 rwlock_assert_writing(&runtimeLock);
1883 static NXMapTable *future_named_class_map = NULL;
1885 if (future_named_class_map) return future_named_class_map;
1887 // future_named_class_map is big enough for CF's classes and a few others
1888 future_named_class_map =
1889 NXCreateMapTableFromZone(NXStrValueMapPrototype, 32,
1890 _objc_internal_zone());
1892 return future_named_class_map;
1896 /***********************************************************************
1897 * addFutureNamedClass
1898 * Installs cls as the class structure to use for the named class if it appears.
1899 * Locking: runtimeLock must be held by the caller
1900 **********************************************************************/
1901 static void addFutureNamedClass(const char *name, class_t *cls)
1905 rwlock_assert_writing(&runtimeLock);
1908 _objc_inform("FUTURE: reserving %p for %s", cls, name);
1911 cls->setData((class_rw_t *)_calloc_internal(sizeof(*cls->data()), 1));
1912 cls->data()->flags = RO_FUTURE;
1914 old = NXMapKeyCopyingInsert(futureNamedClasses(), name, cls);
1919 /***********************************************************************
1920 * removeFutureNamedClass
1921 * Removes the named class from the unrealized future class list,
1922 * because it has been realized.
1923 * Locking: runtimeLock must be held by the caller
1924 **********************************************************************/
1925 static void removeFutureNamedClass(const char *name)
1927 rwlock_assert_writing(&runtimeLock);
1929 NXMapKeyFreeingRemove(futureNamedClasses(), name);
1933 /***********************************************************************
1935 * Returns the oldClass => newClass map for realized future classes.
1936 * Returns the oldClass => NULL map for ignored weak-linked classes.
1937 * Locking: runtimeLock must be read- or write-locked by the caller
1938 **********************************************************************/
1939 static NXMapTable *remappedClasses(BOOL create)
1941 static NXMapTable *remapped_class_map = NULL;
1943 rwlock_assert_locked(&runtimeLock);
1945 if (remapped_class_map) return remapped_class_map;
1946 if (!create) return NULL;
1948 // remapped_class_map is big enough to hold CF's classes and a few others
1949 INIT_ONCE_PTR(remapped_class_map,
1950 NXCreateMapTableFromZone(NXPtrValueMapPrototype, 32,
1951 _objc_internal_zone()),
1954 return remapped_class_map;
1958 /***********************************************************************
1960 * Returns YES if no classes have been remapped
1961 * Locking: runtimeLock must be read- or write-locked by the caller
1962 **********************************************************************/
1963 static BOOL noClassesRemapped(void)
1965 rwlock_assert_locked(&runtimeLock);
1967 BOOL result = (remappedClasses(NO) == NULL);
1972 /***********************************************************************
1974 * newcls is a realized future class, replacing oldcls.
1975 * OR newcls is NULL, replacing ignored weak-linked class oldcls.
1976 * Locking: runtimeLock must be write-locked by the caller
1977 **********************************************************************/
1978 static void addRemappedClass(class_t *oldcls, class_t *newcls)
1980 rwlock_assert_writing(&runtimeLock);
1983 _objc_inform("FUTURE: using %p instead of %p for %s",
1984 oldcls, newcls, getName(oldcls));
1988 old = NXMapInsert(remappedClasses(YES), oldcls, newcls);
1993 /***********************************************************************
1995 * Returns the live class pointer for cls, which may be pointing to
1996 * a class struct that has been reallocated.
1997 * Returns NULL if cls is ignored because of weak linking.
1998 * Locking: runtimeLock must be read- or write-locked by the caller
1999 **********************************************************************/
2000 static class_t *remapClass(class_t *cls)
2002 rwlock_assert_locked(&runtimeLock);
2006 if (!cls) return NULL;
2008 if (NXMapMember(remappedClasses(YES), cls, (void**)&c2) == NX_MAPNOTAKEY) {
2015 static class_t *remapClass(classref_t cls)
2017 return remapClass((class_t *)cls);
2020 Class _class_remap(Class cls_gen)
2022 rwlock_read(&runtimeLock);
2023 Class result = (Class)remapClass(newcls(cls_gen));
2024 rwlock_unlock_read(&runtimeLock);
2028 /***********************************************************************
2030 * Fix up a class ref, in case the class referenced has been reallocated
2031 * or is an ignored weak-linked class.
2032 * Locking: runtimeLock must be read- or write-locked by the caller
2033 **********************************************************************/
2034 static void remapClassRef(class_t **clsref)
2036 rwlock_assert_locked(&runtimeLock);
2038 class_t *newcls = remapClass(*clsref);
2039 if (*clsref != newcls) *clsref = newcls;
2043 /***********************************************************************
2045 * Returns the memoized metaclass => class map
2046 * Used for some cases of +initialize.
2047 * This map does not contain all classes and metaclasses. It only
2048 * contains memoized results from the slow path in getNonMetaClass(),
2049 * and classes that the slow path can't find (like objc_registerClassPair).
2050 * Locking: runtimeLock must be read- or write-locked by the caller
2051 **********************************************************************/
2052 static NXMapTable *nonmeta_class_map = NULL;
2053 static NXMapTable *nonMetaClasses(void)
2055 rwlock_assert_locked(&runtimeLock);
2057 if (nonmeta_class_map) return nonmeta_class_map;
2059 // nonmeta_class_map is typically small
2060 INIT_ONCE_PTR(nonmeta_class_map,
2061 NXCreateMapTableFromZone(NXPtrValueMapPrototype, 32,
2062 _objc_internal_zone()),
2065 return nonmeta_class_map;
2069 /***********************************************************************
2071 * Adds metacls => cls to the memoized metaclass map
2072 * Locking: runtimeLock must be held by the caller
2073 **********************************************************************/
2074 static void addNonMetaClass(class_t *cls)
2076 rwlock_assert_writing(&runtimeLock);
2078 old = NXMapInsert(nonMetaClasses(), cls->isa, cls);
2080 assert(isRealized(cls));
2081 assert(isRealized(cls->isa));
2082 assert(!isMetaClass(cls));
2083 assert(isMetaClass(cls->isa));
2088 static void removeNonMetaClass(class_t *cls)
2090 rwlock_assert_writing(&runtimeLock);
2091 NXMapRemove(nonMetaClasses(), cls->isa);
2095 /***********************************************************************
2097 * Return the ordinary class for this class or metaclass.
2098 * `inst` is an instance of `cls` or a subclass thereof, or nil.
2099 * Non-nil inst is faster.
2100 * Used by +initialize.
2101 * Locking: runtimeLock must be read- or write-locked by the caller
2102 **********************************************************************/
2103 static class_t *getNonMetaClass(class_t *metacls, id inst)
2105 static int total, slow, memo;
2106 rwlock_assert_locked(&runtimeLock);
2108 realizeClass(metacls);
2112 // return cls itself if it's already a non-meta class
2113 if (!isMetaClass(metacls)) return metacls;
2115 // metacls really is a metaclass
2117 // special case for root metaclass
2118 // where inst == inst->isa == metacls is possible
2119 if (metacls->isa == metacls) {
2120 class_t *cls = metacls->superclass;
2121 assert(isRealized(cls));
2122 assert(!isMetaClass(cls));
2123 assert(cls->isa == metacls);
2124 if (cls->isa == metacls) return cls;
2127 // use inst if available
2129 class_t *cls = (class_t *)inst;
2131 // cls may be a subclass - find the real class for metacls
2132 while (cls && cls->isa != metacls) {
2133 cls = cls->superclass;
2137 assert(!isMetaClass(cls));
2138 assert(cls->isa == metacls);
2142 _objc_fatal("cls is not an instance of metacls");
2144 // release build: be forgiving and fall through to slow lookups
2148 // try memoized table
2149 class_t *cls = (class_t *)NXMapGet(nonMetaClasses(), metacls);
2152 if (PrintInitializing) {
2153 _objc_inform("INITIALIZE: %d/%d (%g%%) memoized metaclass lookups",
2154 memo, total, memo*100.0/total);
2157 assert(isRealized(cls));
2158 assert(!isMetaClass(cls));
2159 assert(cls->isa == metacls);
2165 if (PrintInitializing) {
2166 _objc_inform("INITIALIZE: %d/%d (%g%%) slow metaclass lookups",
2167 slow, total, slow*100.0/total);
2170 for (header_info *hi = FirstHeader; hi; hi = hi->next) {
2172 classref_t *classlist = _getObjc2ClassList(hi, &count);
2173 for (size_t i = 0; i < count; i++) {
2174 cls = remapClass(classlist[i]);
2175 if (cls && cls->isa == metacls) {
2178 addNonMetaClass(cls);
2184 _objc_fatal("no class for metaclass %p", metacls);
2190 /***********************************************************************
2191 * _class_getNonMetaClass
2192 * Return the ordinary class for this class or metaclass.
2193 * Used by +initialize.
2194 * Locking: acquires runtimeLock
2195 **********************************************************************/
2196 Class _class_getNonMetaClass(Class cls_gen, id obj)
2198 class_t *cls = newcls(cls_gen);
2199 rwlock_write(&runtimeLock);
2200 cls = getNonMetaClass(cls, obj);
2201 assert(isRealized(cls));
2202 rwlock_unlock_write(&runtimeLock);
2208 /***********************************************************************
2210 * Adds subcls as a subclass of supercls.
2211 * Locking: runtimeLock must be held by the caller.
2212 **********************************************************************/
2213 static void addSubclass(class_t *supercls, class_t *subcls)
2215 rwlock_assert_writing(&runtimeLock);
2217 if (supercls && subcls) {
2218 assert(isRealized(supercls));
2219 assert(isRealized(subcls));
2220 subcls->data()->nextSiblingClass = supercls->data()->firstSubclass;
2221 supercls->data()->firstSubclass = subcls;
2223 if (supercls->data()->flags & RW_HAS_CXX_STRUCTORS) {
2224 subcls->data()->flags |= RW_HAS_CXX_STRUCTORS;
2227 if (supercls->hasCustomRR()) {
2228 subcls->setHasCustomRR(true);
2231 if (supercls->hasCustomAWZ()) {
2232 subcls->setHasCustomAWZ(true);
2238 /***********************************************************************
2240 * Removes subcls as a subclass of supercls.
2241 * Locking: runtimeLock must be held by the caller.
2242 **********************************************************************/
2243 static void removeSubclass(class_t *supercls, class_t *subcls)
2245 rwlock_assert_writing(&runtimeLock);
2246 assert(isRealized(supercls));
2247 assert(isRealized(subcls));
2248 assert(getSuperclass(subcls) == supercls);
2251 for (cp = &supercls->data()->firstSubclass;
2252 *cp && *cp != subcls;
2253 cp = &(*cp)->data()->nextSiblingClass)
2255 assert(*cp == subcls);
2256 *cp = subcls->data()->nextSiblingClass;
2261 /***********************************************************************
2263 * Returns the protocol name => protocol map for protocols.
2264 * Locking: runtimeLock must read- or write-locked by the caller
2265 **********************************************************************/
2266 static NXMapTable *protocols(void)
2268 static NXMapTable *protocol_map = NULL;
2270 rwlock_assert_locked(&runtimeLock);
2272 INIT_ONCE_PTR(protocol_map,
2273 NXCreateMapTableFromZone(NXStrValueMapPrototype, 16,
2274 _objc_internal_zone()),
2275 NXFreeMapTable(v) );
2277 return protocol_map;
2281 /***********************************************************************
2283 * Returns the live protocol pointer for proto, which may be pointing to
2284 * a protocol struct that has been reallocated.
2285 * Locking: runtimeLock must be read- or write-locked by the caller
2286 **********************************************************************/
2287 static protocol_t *remapProtocol(protocol_ref_t proto)
2289 rwlock_assert_locked(&runtimeLock);
2291 protocol_t *newproto = (protocol_t *)
2292 NXMapGet(protocols(), ((protocol_t *)proto)->name);
2293 return newproto ? newproto : (protocol_t *)proto;
2297 /***********************************************************************
2299 * Fix up a protocol ref, in case the protocol referenced has been reallocated.
2300 * Locking: runtimeLock must be read- or write-locked by the caller
2301 **********************************************************************/
2302 static void remapProtocolRef(protocol_t **protoref)
2304 rwlock_assert_locked(&runtimeLock);
2306 protocol_t *newproto = remapProtocol((protocol_ref_t)*protoref);
2307 if (*protoref != newproto) *protoref = newproto;
2311 /***********************************************************************
2313 * Slides a class's ivars to accommodate the given superclass size.
2314 * Also slides ivar and weak GC layouts if provided.
2315 * Ivars are NOT compacted to compensate for a superclass that shrunk.
2316 * Locking: runtimeLock must be held by the caller.
2317 **********************************************************************/
2318 static void moveIvars(class_ro_t *ro, uint32_t superSize,
2319 layout_bitmap *ivarBitmap, layout_bitmap *weakBitmap)
2321 rwlock_assert_writing(&runtimeLock);
2326 assert(superSize > ro->instanceStart);
2327 diff = superSize - ro->instanceStart;
2330 // Find maximum alignment in this class's ivars
2331 uint32_t maxAlignment = 1;
2332 for (i = 0; i < ro->ivars->count; i++) {
2333 ivar_t *ivar = ivar_list_nth(ro->ivars, i);
2334 if (!ivar->offset) continue; // anonymous bitfield
2336 uint32_t alignment = ivar_alignment(ivar);
2337 if (alignment > maxAlignment) maxAlignment = alignment;
2340 // Compute a slide value that preserves that alignment
2341 uint32_t alignMask = maxAlignment - 1;
2342 if (diff & alignMask) diff = (diff + alignMask) & ~alignMask;
2344 // Slide all of this class's ivars en masse
2345 for (i = 0; i < ro->ivars->count; i++) {
2346 ivar_t *ivar = ivar_list_nth(ro->ivars, i);
2347 if (!ivar->offset) continue; // anonymous bitfield
2349 uint32_t oldOffset = (uint32_t)*ivar->offset;
2350 uint32_t newOffset = oldOffset + diff;
2351 *ivar->offset = newOffset;
2354 _objc_inform("IVARS: offset %u -> %u for %s (size %u, align %u)",
2355 oldOffset, newOffset, ivar->name,
2356 ivar->size, ivar_alignment(ivar));
2361 uint32_t oldOffset = ro->instanceStart;
2362 uint32_t newOffset = ro->instanceStart + diff;
2365 layout_bitmap_slide(ivarBitmap,
2366 oldOffset >> WORD_SHIFT,
2367 newOffset >> WORD_SHIFT);
2370 layout_bitmap_slide(weakBitmap,
2371 oldOffset >> WORD_SHIFT,
2372 newOffset >> WORD_SHIFT);
2376 *(uint32_t *)&ro->instanceStart += diff;
2377 *(uint32_t *)&ro->instanceSize += diff;
2380 // No ivars slid, but superclass changed size.
2381 // Expand bitmap in preparation for layout_bitmap_splat().
2382 if (ivarBitmap) layout_bitmap_grow(ivarBitmap, ro->instanceSize >> WORD_SHIFT);
2383 if (weakBitmap) layout_bitmap_grow(weakBitmap, ro->instanceSize >> WORD_SHIFT);
2388 /***********************************************************************
2390 * Look up an ivar by name.
2391 * Locking: runtimeLock must be read- or write-locked by the caller.
2392 **********************************************************************/
2393 static ivar_t *getIvar(class_t *cls, const char *name)
2395 rwlock_assert_locked(&runtimeLock);
2397 const ivar_list_t *ivars;
2398 assert(isRealized(cls));
2399 if ((ivars = cls->data()->ro->ivars)) {
2401 for (i = 0; i < ivars->count; i++) {
2402 ivar_t *ivar = ivar_list_nth(ivars, i);
2403 if (!ivar->offset) continue; // anonymous bitfield
2405 // ivar->name may be NULL for anonymous bitfields etc.
2406 if (ivar->name && 0 == strcmp(name, ivar->name)) {
2415 static void reconcileInstanceVariables(class_t *cls, class_t *supercls) {
2416 class_rw_t *rw = cls->data();
2417 const class_ro_t *ro = rw->ro;
2420 // Non-fragile ivars - reconcile this class with its superclass
2421 // Does this really need to happen for the isMETA case?
2422 layout_bitmap ivarBitmap;
2423 layout_bitmap weakBitmap;
2424 BOOL layoutsChanged = NO;
2425 BOOL mergeLayouts = UseGC;
2426 const class_ro_t *super_ro = supercls->data()->ro;
2428 if (DebugNonFragileIvars) {
2429 // Debugging: Force non-fragile ivars to slide.
2430 // Intended to find compiler, runtime, and program bugs.
2431 // If it fails with this and works without, you have a problem.
2433 // Operation: Reset everything to 0 + misalignment.
2434 // Then force the normal sliding logic to push everything back.
2436 // Exceptions: root classes, metaclasses, *NSCF* classes,
2437 // __CF* classes, NSConstantString, NSSimpleCString
2439 // (already know it's not root because supercls != nil)
2440 if (!strstr(getName(cls), "NSCF") &&
2441 0 != strncmp(getName(cls), "__CF", 4) &&
2442 0 != strcmp(getName(cls), "NSConstantString") &&
2443 0 != strcmp(getName(cls), "NSSimpleCString"))
2445 uint32_t oldStart = ro->instanceStart;
2446 uint32_t oldSize = ro->instanceSize;
2447 class_ro_t *ro_w = make_ro_writeable(rw);
2450 // Find max ivar alignment in class.
2451 // default to word size to simplify ivar update
2452 uint32_t alignment = 1<<WORD_SHIFT;
2455 for (i = 0; i < ro->ivars->count; i++) {
2456 ivar_t *ivar = ivar_list_nth(ro->ivars, i);
2457 if (ivar_alignment(ivar) > alignment) {
2458 alignment = ivar_alignment(ivar);
2462 uint32_t misalignment = ro->instanceStart % alignment;
2463 uint32_t delta = ro->instanceStart - misalignment;
2464 ro_w->instanceStart = misalignment;
2465 ro_w->instanceSize -= delta;
2468 _objc_inform("IVARS: DEBUG: forcing ivars for class '%s' "
2469 "to slide (instanceStart %zu -> %zu)",
2470 getName(cls), (size_t)oldStart,
2471 (size_t)ro->instanceStart);
2476 for (i = 0; i < ro->ivars->count; i++) {
2477 ivar_t *ivar = ivar_list_nth(ro->ivars, i);
2478 if (!ivar->offset) continue; // anonymous bitfield
2479 *ivar->offset -= delta;
2484 layout_bitmap layout;
2485 if (ro->ivarLayout) {
2486 layout = layout_bitmap_create(ro->ivarLayout,
2487 oldSize, oldSize, NO);
2488 layout_bitmap_slide_anywhere(&layout,
2489 delta >> WORD_SHIFT, 0);
2490 ro_w->ivarLayout = layout_string_create(layout);
2491 layout_bitmap_free(layout);
2493 if (ro->weakIvarLayout) {
2494 layout = layout_bitmap_create(ro->weakIvarLayout,
2495 oldSize, oldSize, YES);
2496 layout_bitmap_slide_anywhere(&layout,
2497 delta >> WORD_SHIFT, 0);
2498 ro_w->weakIvarLayout = layout_string_create(layout);
2499 layout_bitmap_free(layout);
2505 // fixme can optimize for "class has no new ivars", etc
2506 // WARNING: gcc c++ sets instanceStart/Size=0 for classes with
2507 // no local ivars, but does provide a layout bitmap.
2508 // Handle that case specially so layout_bitmap_create doesn't die
2509 // The other ivar sliding code below still works fine, and
2510 // the final result is a good class.
2511 if (ro->instanceStart == 0 && ro->instanceSize == 0) {
2512 // We can't use ro->ivarLayout because we don't know
2513 // how long it is. Force a new layout to be created.
2515 _objc_inform("IVARS: instanceStart/Size==0 for class %s; "
2516 "disregarding ivar layout", ro->name);
2518 ivarBitmap = layout_bitmap_create_empty(super_ro->instanceSize, NO);
2519 weakBitmap = layout_bitmap_create_empty(super_ro->instanceSize, YES);
2520 layoutsChanged = YES;
2523 layout_bitmap_create(ro->ivarLayout,
2525 ro->instanceSize, NO);
2527 layout_bitmap_create(ro->weakIvarLayout,
2529 ro->instanceSize, YES);
2532 if (ro->instanceStart < super_ro->instanceSize) {
2533 // Superclass has changed size. This class's ivars must move.
2534 // Also slide layout bits in parallel.
2535 // This code is incapable of compacting the subclass to
2536 // compensate for a superclass that shrunk, so don't do that.
2538 _objc_inform("IVARS: sliding ivars for class %s "
2539 "(superclass was %u bytes, now %u)",
2540 ro->name, ro->instanceStart,
2541 super_ro->instanceSize);
2543 class_ro_t *ro_w = make_ro_writeable(rw);
2545 moveIvars(ro_w, super_ro->instanceSize,
2546 mergeLayouts ? &ivarBitmap : NULL, mergeLayouts ? &weakBitmap : NULL);
2547 gdb_objc_class_changed((Class)cls, OBJC_CLASS_IVARS_CHANGED, ro->name);
2548 layoutsChanged = mergeLayouts;
2552 // Check superclass's layout against this class's layout.
2553 // This needs to be done even if the superclass is not bigger.
2554 layout_bitmap superBitmap = layout_bitmap_create(super_ro->ivarLayout,
2555 super_ro->instanceSize,
2556 super_ro->instanceSize, NO);
2557 layoutsChanged |= layout_bitmap_splat(ivarBitmap, superBitmap,
2559 layout_bitmap_free(superBitmap);
2561 // check the superclass' weak layout.
2562 superBitmap = layout_bitmap_create(super_ro->weakIvarLayout,
2563 super_ro->instanceSize,
2564 super_ro->instanceSize, YES);
2565 layoutsChanged |= layout_bitmap_splat(weakBitmap, superBitmap,
2567 layout_bitmap_free(superBitmap);
2570 if (layoutsChanged) {
2571 // Rebuild layout strings.
2573 _objc_inform("IVARS: gc layout changed for class %s",
2576 class_ro_t *ro_w = make_ro_writeable(rw);
2578 if (DebugNonFragileIvars) {
2579 try_free(ro_w->ivarLayout);
2580 try_free(ro_w->weakIvarLayout);
2582 ro_w->ivarLayout = layout_string_create(ivarBitmap);
2583 ro_w->weakIvarLayout = layout_string_create(weakBitmap);
2586 layout_bitmap_free(ivarBitmap);
2587 layout_bitmap_free(weakBitmap);
2591 /***********************************************************************
2593 * Performs first-time initialization on class cls,
2594 * including allocating its read-write data.
2595 * Returns the real class structure for the class.
2596 * Locking: runtimeLock must be write-locked by the caller
2597 **********************************************************************/
2598 static class_t *realizeClass(class_t *cls)
2600 rwlock_assert_writing(&runtimeLock);
2602 const class_ro_t *ro;
2608 if (!cls) return NULL;
2609 if (isRealized(cls)) return cls;
2610 assert(cls == remapClass(cls));
2612 ro = (const class_ro_t *)cls->data();
2613 if (ro->flags & RO_FUTURE) {
2614 // This was a future class. rw data is already allocated.
2616 ro = cls->data()->ro;
2617 changeInfo(cls, RW_REALIZED, RW_FUTURE);
2619 // Normal class. Allocate writeable class data.
2620 rw = (class_rw_t *)_calloc_internal(sizeof(class_rw_t), 1);
2622 rw->flags = RW_REALIZED;
2626 isMeta = (ro->flags & RO_META) ? YES : NO;
2628 rw->version = isMeta ? 7 : 0; // old runtime went up to 6
2630 if (PrintConnecting) {
2631 _objc_inform("CLASS: realizing class '%s' %s %p %p",
2632 ro->name, isMeta ? "(meta)" : "", cls, ro);
2635 // Realize superclass and metaclass, if they aren't already.
2636 // This needs to be done after RW_REALIZED is set above, for root classes.
2637 supercls = realizeClass(remapClass(cls->superclass));
2638 metacls = realizeClass(remapClass(cls->isa));
2640 // Check for remapped superclass and metaclass
2641 if (supercls != cls->superclass) {
2642 cls->superclass = supercls;
2644 if (metacls != cls->isa) {
2648 /* debug: print them all
2651 for (i = 0; i < ro->ivars->count; i++) {
2652 ivar_t *ivar = ivar_list_nth(ro->ivars, i);
2653 if (!ivar->offset) continue; // anonymous bitfield
2655 _objc_inform("IVARS: %s.%s (offset %u, size %u, align %u)",
2656 ro->name, ivar->name,
2657 *ivar->offset, ivar->size, ivar_alignment(ivar));
2662 // Reconcile instance variable offsets / layout.
2663 if (!isMeta) reconcileInstanceVariables(cls, supercls);
2665 // Copy some flags from ro to rw
2666 if (ro->flags & RO_HAS_CXX_STRUCTORS) rw->flags |= RW_HAS_CXX_STRUCTORS;
2668 // Connect this class to its superclass's subclass lists
2670 addSubclass(supercls, cls);
2673 // Attach categories
2674 methodizeClass(cls);
2677 addRealizedClass(cls);
2679 addRealizedMetaclass(cls);
2686 /***********************************************************************
2687 * missingWeakSuperclass
2688 * Return YES if some superclass of cls was weak-linked and is missing.
2689 **********************************************************************/
2691 missingWeakSuperclass(class_t *cls)
2693 assert(!isRealized(cls));
2695 if (!cls->superclass) {
2696 // superclass NULL. This is normal for root classes only.
2697 return (!(cls->data()->flags & RO_ROOT));
2699 // superclass not NULL. Check if a higher superclass is missing.
2700 class_t *supercls = remapClass(cls->superclass);
2701 assert(cls != cls->superclass);
2702 assert(cls != supercls);
2703 if (!supercls) return YES;
2704 if (isRealized(supercls)) return NO;
2705 return missingWeakSuperclass(supercls);
2710 /***********************************************************************
2711 * realizeAllClassesInImage
2712 * Non-lazily realizes all unrealized classes in the given image.
2713 * Locking: runtimeLock must be held by the caller.
2714 **********************************************************************/
2715 static void realizeAllClassesInImage(header_info *hi)
2717 rwlock_assert_writing(&runtimeLock);
2720 classref_t *classlist;
2722 if (hi->allClassesRealized) return;
2724 classlist = _getObjc2ClassList(hi, &count);
2726 for (i = 0; i < count; i++) {
2727 realizeClass(remapClass(classlist[i]));
2730 hi->allClassesRealized = YES;
2734 /***********************************************************************
2736 * Non-lazily realizes all unrealized classes in all known images.
2737 * Locking: runtimeLock must be held by the caller.
2738 **********************************************************************/
2739 static void realizeAllClasses(void)
2741 rwlock_assert_writing(&runtimeLock);
2744 for (hi = FirstHeader; hi; hi = hi->next) {
2745 realizeAllClassesInImage(hi);
2750 /***********************************************************************
2751 * _objc_allocateFutureClass
2752 * Allocate an unresolved future class for the given class name.
2753 * Returns any existing allocation if one was already made.
2754 * Assumes the named class doesn't exist yet.
2755 * Locking: acquires runtimeLock
2756 **********************************************************************/
2757 Class _objc_allocateFutureClass(const char *name)
2759 rwlock_write(&runtimeLock);
2762 NXMapTable *future_named_class_map = futureNamedClasses();
2764 if ((cls = (class_t *)NXMapGet(future_named_class_map, name))) {
2765 // Already have a future class for this name.
2766 rwlock_unlock_write(&runtimeLock);
2770 cls = (class_t *)_calloc_class(sizeof(*cls));
2771 addFutureNamedClass(name, cls);
2773 rwlock_unlock_write(&runtimeLock);
2778 /***********************************************************************
2780 **********************************************************************/
2781 void objc_setFutureClass(Class cls, const char *name)
2783 // fixme hack do nothing - NSCFString handled specially elsewhere
2787 /***********************************************************************
2789 * Rebuilds vtables for cls and its realized subclasses.
2790 * If cls is Nil, all realized classes and metaclasses are touched.
2791 * Locking: runtimeLock must be held by the caller.
2792 **********************************************************************/
2793 static void flushVtables(class_t *cls)
2795 rwlock_assert_writing(&runtimeLock);
2797 if (PrintVtables && !cls) {
2798 _objc_inform("VTABLES: ### EXPENSIVE ### global vtable flush!");
2801 FOREACH_REALIZED_CLASS_AND_SUBCLASS(c, cls, {
2802 updateVtable(c, NO);
2807 /***********************************************************************
2809 * Flushes caches for cls and its realized subclasses.
2810 * Does not update vtables.
2811 * If cls is Nil, all realized and metaclasses classes are touched.
2812 * Locking: runtimeLock must be held by the caller.
2813 **********************************************************************/
2814 static void flushCaches(class_t *cls)
2816 rwlock_assert_writing(&runtimeLock);
2818 FOREACH_REALIZED_CLASS_AND_SUBCLASS(c, cls, {
2819 flush_cache((Class)c);
2824 /***********************************************************************
2826 * Flushes caches and rebuilds vtables for cls, its subclasses,
2827 * and optionally its metaclass.
2828 * Locking: acquires runtimeLock
2829 **********************************************************************/
2830 void flush_caches(Class cls_gen, BOOL flush_meta)
2832 class_t *cls = newcls(cls_gen);
2833 rwlock_write(&runtimeLock);
2834 // fixme optimize vtable flushing? (only needed for vtable'd selectors)
2837 // don't flush root class's metaclass twice (it's a subclass of the root)
2838 if (flush_meta && getSuperclass(cls)) {
2839 flushCaches(cls->isa);
2840 flushVtables(cls->isa);
2842 rwlock_unlock_write(&runtimeLock);
2846 /***********************************************************************
2848 * Process the given images which are being mapped in by dyld.
2849 * Calls ABI-agnostic code after taking ABI-specific locks.
2851 * Locking: write-locks runtimeLock
2852 **********************************************************************/
2854 map_images(enum dyld_image_states state, uint32_t infoCount,
2855 const struct dyld_image_info infoList[])
2859 rwlock_write(&runtimeLock);
2860 err = map_images_nolock(state, infoCount, infoList);
2861 rwlock_unlock_write(&runtimeLock);
2866 /***********************************************************************
2868 * Process +load in the given images which are being mapped in by dyld.
2869 * Calls ABI-agnostic code after taking ABI-specific locks.
2871 * Locking: write-locks runtimeLock and loadMethodLock
2872 **********************************************************************/
2874 load_images(enum dyld_image_states state, uint32_t infoCount,
2875 const struct dyld_image_info infoList[])
2879 recursive_mutex_lock(&loadMethodLock);
2881 // Discover load methods
2882 rwlock_write(&runtimeLock);
2883 found = load_images_nolock(state, infoCount, infoList);
2884 rwlock_unlock_write(&runtimeLock);
2886 // Call +load methods (without runtimeLock - re-entrant)
2888 call_load_methods();
2891 recursive_mutex_unlock(&loadMethodLock);
2897 /***********************************************************************
2899 * Process the given image which is about to be unmapped by dyld.
2900 * mh is mach_header instead of headerType because that's what
2901 * dyld_priv.h says even for 64-bit.
2903 * Locking: write-locks runtimeLock and loadMethodLock
2904 **********************************************************************/
2906 unmap_image(const struct mach_header *mh, intptr_t vmaddr_slide)
2908 recursive_mutex_lock(&loadMethodLock);
2909 rwlock_write(&runtimeLock);
2911 unmap_image_nolock(mh);
2913 rwlock_unlock_write(&runtimeLock);
2914 recursive_mutex_unlock(&loadMethodLock);
2919 /***********************************************************************
2921 * Perform initial processing of the headers in the linked
2922 * list beginning with headerList.
2924 * Called by: map_images_nolock
2926 * Locking: runtimeLock acquired by map_images
2927 **********************************************************************/
2928 void _read_images(header_info **hList, uint32_t hCount)
2934 class_t **resolvedFutureClasses = NULL;
2935 size_t resolvedFutureClassCount = 0;
2936 static unsigned int totalMethodLists;
2937 static unsigned int preoptimizedMethodLists;
2938 static unsigned int totalClasses;
2939 static unsigned int preoptimizedClasses;
2940 static BOOL doneOnce;
2942 rwlock_assert_writing(&runtimeLock);
2944 #define EACH_HEADER \
2946 crashlog_header_name(NULL) && hIndex < hCount && (hi = hList[hIndex]) && crashlog_header_name(hi); \
2953 // Count classes. Size various table based on the total.
2955 size_t unoptimizedTotal = 0;
2957 if (_getObjc2ClassList(hi, &count)) {
2959 if (!hi->inSharedCache) unoptimizedTotal += count;
2963 if (PrintConnecting) {
2964 _objc_inform("CLASS: found %zu classes during launch", total);
2967 // namedClasses (NOT realizedClasses)
2968 // Preoptimized classes don't go in this table.
2969 // 4/3 is NXMapTable's load factor
2970 size_t namedClassesSize =
2971 (isPreoptimized() ? unoptimizedTotal : total) * 4 / 3;
2972 gdb_objc_realized_classes =
2973 NXCreateMapTableFromZone(NXStrValueMapPrototype, namedClassesSize,
2974 _objc_internal_zone());
2976 // realizedClasses and realizedMetaclasses - less than the full total
2977 realized_class_hash =
2978 NXCreateHashTableFromZone(NXPtrPrototype, total / 8, NULL,
2979 _objc_internal_zone());
2980 realized_metaclass_hash =
2981 NXCreateHashTableFromZone(NXPtrPrototype, total / 8, NULL,
2982 _objc_internal_zone());
2986 // Discover classes. Fix up unresolved future classes. Mark bundle classes.
2987 NXMapTable *future_named_class_map = futureNamedClasses();
2990 bool headerIsBundle = (hi->mhdr->filetype == MH_BUNDLE);
2991 bool headerInSharedCache = hi->inSharedCache;
2993 classref_t *classlist = _getObjc2ClassList(hi, &count);
2994 for (i = 0; i < count; i++) {
2995 class_t *cls = (class_t *)classlist[i];
2996 const char *name = getName(cls);
2998 if (missingWeakSuperclass(cls)) {
2999 // No superclass (probably weak-linked).
3000 // Disavow any knowledge of this subclass.
3001 if (PrintConnecting) {
3002 _objc_inform("CLASS: IGNORING class '%s' with "
3003 "missing weak-linked superclass", name);
3005 addRemappedClass(cls, NULL);
3006 cls->superclass = NULL;
3010 class_t *newCls = NULL;
3011 if (NXCountMapTable(future_named_class_map) > 0) {
3012 newCls = (class_t *)NXMapGet(future_named_class_map, name);
3013 removeFutureNamedClass(name);
3017 // Copy class_t to future class's struct.
3018 // Preserve future's rw data block.
3019 class_rw_t *rw = newCls->data();
3020 memcpy(newCls, cls, sizeof(class_t));
3021 rw->ro = (class_ro_t *)newCls->data();
3022 newCls->setData(rw);
3024 addRemappedClass(cls, newCls);
3027 // Non-lazily realize the class below.
3028 resolvedFutureClasses = (class_t **)
3029 _realloc_internal(resolvedFutureClasses,
3030 (resolvedFutureClassCount+1)
3031 * sizeof(class_t *));
3032 resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
3036 if (headerInSharedCache && isPreoptimized()) {
3037 // class list built in shared cache
3038 // fixme strict assert doesn't work because of duplicates
3039 // assert(cls == getClass(name));
3040 assert(getClass(name));
3041 preoptimizedClasses++;
3043 addNamedClass(cls, name);
3046 // for future reference: shared cache never contains MH_BUNDLEs
3047 if (headerIsBundle) {
3048 cls->data()->flags |= RO_FROM_BUNDLE;
3049 cls->isa->data()->flags |= RO_FROM_BUNDLE;
3053 const method_list_t *mlist;
3054 if ((mlist = ((class_ro_t *)cls->data())->baseMethods)) {
3056 if (isMethodListFixedUp(mlist)) preoptimizedMethodLists++;
3058 if ((mlist = ((class_ro_t *)cls->isa->data())->baseMethods)) {
3060 if (isMethodListFixedUp(mlist)) preoptimizedMethodLists++;
3066 if (PrintPreopt && totalMethodLists) {
3067 _objc_inform("PREOPTIMIZATION: %u/%u (%.3g%%) method lists pre-sorted",
3068 preoptimizedMethodLists, totalMethodLists,
3069 100.0*preoptimizedMethodLists/totalMethodLists);
3071 if (PrintPreopt && totalClasses) {
3072 _objc_inform("PREOPTIMIZATION: %u/%u (%.3g%%) classes pre-registered",
3073 preoptimizedClasses, totalClasses,
3074 100.0*preoptimizedClasses/totalClasses);
3077 // Fix up remapped classes
3078 // Class list and nonlazy class list remain unremapped.
3079 // Class refs and super refs are remapped for message dispatching.
3081 if (!noClassesRemapped()) {
3083 class_t **classrefs = _getObjc2ClassRefs(hi, &count);
3084 for (i = 0; i < count; i++) {
3085 remapClassRef(&classrefs[i]);
3087 // fixme why doesn't test future1 catch the absence of this?
3088 classrefs = _getObjc2SuperRefs(hi, &count);
3089 for (i = 0; i < count; i++) {
3090 remapClassRef(&classrefs[i]);
3096 // Fix up @selector references
3100 if (sel_preoptimizationValid(hi)) {
3101 _objc_inform("PREOPTIMIZATION: honoring preoptimized selectors in %s",
3104 else if (_objcHeaderOptimizedByDyld(hi)) {
3105 _objc_inform("PREOPTIMIZATION: IGNORING preoptimized selectors in %s",
3110 if (sel_preoptimizationValid(hi)) continue;
3112 SEL *sels = _getObjc2SelectorRefs(hi, &count);
3113 BOOL isBundle = hi->mhdr->filetype == MH_BUNDLE;
3114 for (i = 0; i < count; i++) {
3115 sels[i] = sel_registerNameNoLock((const char *)sels[i], isBundle);
3120 // Discover protocols. Fix up protocol refs.
3121 NXMapTable *protocol_map = protocols();
3123 extern class_t OBJC_CLASS_$_Protocol;
3124 Class cls = (Class)&OBJC_CLASS_$_Protocol;
3126 protocol_t **protocols = _getObjc2ProtocolList(hi, &count);
3127 // fixme duplicate protocol from bundle
3128 for (i = 0; i < count; i++) {
3129 if (!NXMapGet(protocol_map, protocols[i]->name)) {
3130 protocols[i]->isa = cls;
3131 NXMapKeyCopyingInsert(protocol_map,
3132 protocols[i]->name, protocols[i]);
3133 if (PrintProtocols) {
3134 _objc_inform("PROTOCOLS: protocol at %p is %s",
3135 protocols[i], protocols[i]->name);
3138 if (PrintProtocols) {
3139 _objc_inform("PROTOCOLS: protocol at %p is %s (duplicate)",
3140 protocols[i], protocols[i]->name);
3146 protocol_t **protocols;
3147 protocols = _getObjc2ProtocolRefs(hi, &count);
3148 for (i = 0; i < count; i++) {
3149 remapProtocolRef(&protocols[i]);
3153 // Realize non-lazy classes (for +load methods and static instances)
3155 classref_t *classlist =
3156 _getObjc2NonlazyClassList(hi, &count);
3157 for (i = 0; i < count; i++) {
3158 realizeClass(remapClass(classlist[i]));
3162 // Realize newly-resolved future classes, in case CF manipulates them
3163 if (resolvedFutureClasses) {
3164 for (i = 0; i < resolvedFutureClassCount; i++) {
3165 realizeClass(resolvedFutureClasses[i]);
3167 _free_internal(resolvedFutureClasses);
3170 // Discover categories.
3172 category_t **catlist =
3173 _getObjc2CategoryList(hi, &count);
3174 for (i = 0; i < count; i++) {
3175 category_t *cat = catlist[i];
3176 class_t *cls = remapClass(cat->cls);
3179 // Category's target class is missing (probably weak-linked).
3180 // Disavow any knowledge of this category.
3182 if (PrintConnecting) {
3183 _objc_inform("CLASS: IGNORING category \?\?\?(%s) %p with "
3184 "missing weak-linked target class",
3190 // Process this category.
3191 // First, register the category with its target class.
3192 // Then, rebuild the class's method lists (etc) if
3193 // the class is realized.
3194 BOOL classExists = NO;
3195 if (cat->instanceMethods || cat->protocols
3196 || cat->instanceProperties)
3198 addUnattachedCategoryForClass(cat, cls, hi);
3199 if (isRealized(cls)) {
3200 remethodizeClass(cls);
3203 if (PrintConnecting) {
3204 _objc_inform("CLASS: found category -%s(%s) %s",
3205 getName(cls), cat->name,
3206 classExists ? "on existing class" : "");
3210 if (cat->classMethods || cat->protocols
3211 /* || cat->classProperties */)
3213 addUnattachedCategoryForClass(cat, cls->isa, hi);
3214 if (isRealized(cls->isa)) {
3215 remethodizeClass(cls->isa);
3217 if (PrintConnecting) {
3218 _objc_inform("CLASS: found category +%s(%s)",
3219 getName(cls), cat->name);
3225 // Category discovery MUST BE LAST to avoid potential races
3226 // when other threads call the new category code before
3227 // this thread finishes its fixups.
3229 // +load handled by prepare_load_methods()
3231 if (DebugNonFragileIvars) {
3232 realizeAllClasses();
3239 /***********************************************************************
3240 * prepare_load_methods
3241 * Schedule +load for classes in this image, any un-+load-ed
3242 * superclasses in other images, and any categories in this image.
3243 **********************************************************************/
3244 // Recursively schedule +load for cls and any un-+load-ed superclasses.
3245 // cls must already be connected.
3246 static void schedule_class_load(class_t *cls)
3249 assert(isRealized(cls)); // _read_images should realize
3251 if (cls->data()->flags & RW_LOADED) return;
3253 // Ensure superclass-first ordering
3254 schedule_class_load(getSuperclass(cls));
3256 add_class_to_loadable_list((Class)cls);
3257 changeInfo(cls, RW_LOADED, 0);
3260 void prepare_load_methods(header_info *hi)
3264 rwlock_assert_writing(&runtimeLock);
3266 classref_t *classlist =
3267 _getObjc2NonlazyClassList(hi, &count);
3268 for (i = 0; i < count; i++) {
3269 schedule_class_load(remapClass(classlist[i]));
3272 category_t **categorylist = _getObjc2NonlazyCategoryList(hi, &count);
3273 for (i = 0; i < count; i++) {
3274 category_t *cat = categorylist[i];
3275 class_t *cls = remapClass(cat->cls);
3276 if (!cls) continue; // category for ignored weak-linked class
3278 assert(isRealized(cls->isa));
3279 add_category_to_loadable_list((Category)cat);
3284 /***********************************************************************
3286 * Only handles MH_BUNDLE for now.
3287 * Locking: write-lock and loadMethodLock acquired by unmap_image
3288 **********************************************************************/
3289 void _unload_image(header_info *hi)
3293 recursive_mutex_assert_locked(&loadMethodLock);
3294 rwlock_assert_writing(&runtimeLock);
3296 // Unload unattached categories and categories waiting for +load.
3298 category_t **catlist = _getObjc2CategoryList(hi, &count);
3299 for (i = 0; i < count; i++) {
3300 category_t *cat = catlist[i];
3301 if (!cat) continue; // category for ignored weak-linked class
3302 class_t *cls = remapClass(cat->cls);
3303 assert(cls); // shouldn't have live category for dead class
3305 // fixme for MH_DYLIB cat's class may have been unloaded already
3308 removeUnattachedCategoryForClass(cat, cls);
3311 remove_category_from_loadable_list((Category)cat);
3316 classref_t *classlist = _getObjc2ClassList(hi, &count);
3318 // First detach classes from each other. Then free each class.
3319 // This avoid bugs where this loop unloads a subclass before its superclass
3321 for (i = 0; i < count; i++) {
3322 class_t *cls = remapClass(classlist[i]);
3324 remove_class_from_loadable_list((Class)cls);
3325 detach_class(cls->isa, YES);
3326 detach_class(cls, NO);
3330 for (i = 0; i < count; i++) {
3331 class_t *cls = remapClass(classlist[i]);
3333 free_class(cls->isa);
3338 // XXX FIXME -- Clean up protocols:
3339 // <rdar://problem/9033191> Support unloading protocols at dylib/image unload time
3341 // fixme DebugUnload
3345 /***********************************************************************
3346 * method_getDescription
3347 * Returns a pointer to this method's objc_method_description.
3349 **********************************************************************/
3350 struct objc_method_description *
3351 method_getDescription(Method m)
3353 if (!m) return NULL;
3354 return (struct objc_method_description *)newmethod(m);
3358 /***********************************************************************
3359 * method_getImplementation
3360 * Returns this method's IMP.
3362 **********************************************************************/
3364 _method_getImplementation(method_t *m)
3366 if (!m) return NULL;
3371 method_getImplementation(Method m)
3373 return _method_getImplementation(newmethod(m));
3377 /***********************************************************************
3379 * Returns this method's selector.
3380 * The method must not be NULL.
3381 * The method must already have been fixed-up.
3383 **********************************************************************/
3385 method_getName(Method m_gen)
3387 method_t *m = newmethod(m_gen);
3388 if (!m) return NULL;
3390 assert((SEL)m->name == sel_registerName((char *)m->name));
3391 return (SEL)m->name;
3395 /***********************************************************************
3396 * method_getTypeEncoding
3397 * Returns this method's old-style type encoding string.
3398 * The method must not be NULL.
3400 **********************************************************************/
3402 method_getTypeEncoding(Method m)
3404 if (!m) return NULL;
3405 return newmethod(m)->types;
3409 /***********************************************************************
3410 * method_setImplementation
3411 * Sets this method's implementation to imp.
3412 * The previous implementation is returned.
3413 **********************************************************************/
3415 _method_setImplementation(class_t *cls, method_t *m, IMP imp)
3417 rwlock_assert_writing(&runtimeLock);
3419 if (!m) return NULL;
3420 if (!imp) return NULL;
3422 if (ignoreSelector(m->name)) {
3423 // Ignored methods stay ignored
3427 IMP old = _method_getImplementation(m);
3430 // No cache flushing needed - cache contains Methods not IMPs.
3432 // vtable and RR/AWZ updates are slow if cls is NULL (i.e. unknown)
3433 // fixme build list of classes whose Methods are known externally?
3435 if (vtable_containsSelector(m->name)) {
3439 // Catch changes to retain/release and allocWithZone implementations
3440 updateCustomRR_AWZ(cls, m);
3442 // fixme update monomorphism if necessary
3448 method_setImplementation(Method m, IMP imp)
3450 // Don't know the class - will be slow if vtables are affected
3451 // fixme build list of classes whose Methods are known externally?
3453 rwlock_write(&runtimeLock);
3454 result = _method_setImplementation(Nil, newmethod(m), imp);
3455 rwlock_unlock_write(&runtimeLock);
3460 void method_exchangeImplementations(Method m1_gen, Method m2_gen)
3462 method_t *m1 = newmethod(m1_gen);
3463 method_t *m2 = newmethod(m2_gen);
3464 if (!m1 || !m2) return;
3466 rwlock_write(&runtimeLock);
3468 if (ignoreSelector(m1->name) || ignoreSelector(m2->name)) {
3469 // Ignored methods stay ignored. Now they're both ignored.
3470 m1->imp = (IMP)&_objc_ignored_method;
3471 m2->imp = (IMP)&_objc_ignored_method;
3472 rwlock_unlock_write(&runtimeLock);
3476 IMP m1_imp = m1->imp;
3480 // vtable and RR/AWZ updates are slow because class is unknown
3481 // fixme build list of classes whose Methods are known externally?
3483 if (vtable_containsSelector(m1->name) ||
3484 vtable_containsSelector(m2->name))
3486 // Don't know the class - will be slow if vtables are affected
3487 // fixme build list of classes whose Methods are known externally?
3491 updateCustomRR_AWZ(nil, m1);
3492 updateCustomRR_AWZ(nil, m2);
3494 // fixme update monomorphism if necessary
3496 rwlock_unlock_write(&runtimeLock);
3500 /***********************************************************************
3504 **********************************************************************/
3506 ivar_getOffset(Ivar ivar)
3508 if (!ivar) return 0;
3509 return *newivar(ivar)->offset;
3513 /***********************************************************************
3517 **********************************************************************/
3519 ivar_getName(Ivar ivar)
3521 if (!ivar) return NULL;
3522 return newivar(ivar)->name;
3526 /***********************************************************************
3527 * ivar_getTypeEncoding
3530 **********************************************************************/
3532 ivar_getTypeEncoding(Ivar ivar)
3534 if (!ivar) return NULL;
3535 return newivar(ivar)->type;
3540 const char *property_getName(objc_property_t prop)
3542 return newproperty(prop)->name;
3545 const char *property_getAttributes(objc_property_t prop)
3547 return newproperty(prop)->attributes;
3550 objc_property_attribute_t *property_copyAttributeList(objc_property_t prop,
3551 unsigned int *outCount)
3554 if (outCount) *outCount = 0;
3558 objc_property_attribute_t *result;
3559 rwlock_read(&runtimeLock);
3560 result = copyPropertyAttributeList(newproperty(prop)->attributes,outCount);
3561 rwlock_unlock_read(&runtimeLock);
3565 char * property_copyAttributeValue(objc_property_t prop, const char *name)
3567 if (!prop || !name || *name == '\0') return NULL;
3570 rwlock_read(&runtimeLock);
3571 result = copyPropertyAttributeValue(newproperty(prop)->attributes, name);
3572 rwlock_unlock_read(&runtimeLock);
3577 /***********************************************************************
3578 * getExtendedTypesIndexesForMethod
3580 * a is the count of methods in all method lists before m's method list
3581 * b is the index of m in m's method list
3582 * a+b is the index of m's extended types in the extended types array
3583 **********************************************************************/
3584 static void getExtendedTypesIndexesForMethod(protocol_t *proto, const method_t *m, BOOL isRequiredMethod, BOOL isInstanceMethod, uint32_t& a, uint32_t &b)
3588 if (isRequiredMethod && isInstanceMethod) {
3589 b = method_list_index(proto->instanceMethods, m);
3592 a += method_list_count(proto->instanceMethods);
3594 if (isRequiredMethod && !isInstanceMethod) {
3595 b = method_list_index(proto->classMethods, m);
3598 a += method_list_count(proto->classMethods);
3600 if (!isRequiredMethod && isInstanceMethod) {
3601 b = method_list_index(proto->optionalInstanceMethods, m);
3604 a += method_list_count(proto->optionalInstanceMethods);
3606 if (!isRequiredMethod && !isInstanceMethod) {
3607 b = method_list_index(proto->optionalClassMethods, m);
3610 a += method_list_count(proto->optionalClassMethods);
3614 /***********************************************************************
3615 * getExtendedTypesIndexForMethod
3616 * Returns the index of m's extended types in proto's extended types array.
3617 **********************************************************************/
3618 static uint32_t getExtendedTypesIndexForMethod(protocol_t *proto, const method_t *m, BOOL isRequiredMethod, BOOL isInstanceMethod)
3622 getExtendedTypesIndexesForMethod(proto, m, isRequiredMethod,
3623 isInstanceMethod, a, b);
3628 /***********************************************************************
3629 * _protocol_getMethod_nolock
3630 * Locking: runtimeLock must be write-locked by the caller
3631 **********************************************************************/
3633 _protocol_getMethod_nolock(protocol_t *proto, SEL sel,
3634 BOOL isRequiredMethod, BOOL isInstanceMethod,
3637 rwlock_assert_writing(&runtimeLock);
3639 if (!proto || !sel) return NULL;
3641 method_list_t **mlistp = NULL;
3643 if (isRequiredMethod) {
3644 if (isInstanceMethod) {
3645 mlistp = &proto->instanceMethods;
3647 mlistp = &proto->classMethods;
3650 if (isInstanceMethod) {
3651 mlistp = &proto->optionalInstanceMethods;
3653 mlistp = &proto->optionalClassMethods;
3658 method_list_t *mlist = *mlistp;
3659 if (!isMethodListFixedUp(mlist)) {
3660 bool hasExtendedMethodTypes = proto->hasExtendedMethodTypes();
3661 mlist = fixupMethodList(mlist, true/*always copy for simplicity*/,
3662 !hasExtendedMethodTypes/*sort if no ext*/);
3665 if (hasExtendedMethodTypes) {
3666 // Sort method list and extended method types together.
3667 // fixupMethodList() can't do this.
3669 uint32_t count = method_list_count(mlist);
3672 getExtendedTypesIndexesForMethod(proto, method_list_nth(mlist, 0), isRequiredMethod, isInstanceMethod, prefix, unused);
3673 const char **types = proto->extendedMethodTypes;
3674 for (uint32_t i = 0; i < count; i++) {
3675 for (uint32_t j = i+1; j < count; j++) {
3676 method_t *mi = method_list_nth(mlist, i);
3677 method_t *mj = method_list_nth(mlist, j);
3678 if (mi->name > mj->name) {
3679 method_list_swap(mlist, i, j);
3680 std::swap(types[prefix+i], types[prefix+j]);
3687 method_t *m = search_method_list(mlist, sel);
3691 if (recursive && proto->protocols) {
3693 for (uint32_t i = 0; i < proto->protocols->count; i++) {
3694 protocol_t *realProto = remapProtocol(proto->protocols->list[i]);
3695 m = _protocol_getMethod_nolock(realProto, sel,
3696 isRequiredMethod, isInstanceMethod,
3706 /***********************************************************************
3707 * _protocol_getMethod
3709 * Locking: write-locks runtimeLock
3710 **********************************************************************/
3712 _protocol_getMethod(Protocol *p, SEL sel, BOOL isRequiredMethod, BOOL isInstanceMethod, BOOL recursive)
3714 rwlock_write(&runtimeLock);
3715 method_t *result = _protocol_getMethod_nolock(newprotocol(p), sel,
3719 rwlock_unlock_write(&runtimeLock);
3720 return (Method)result;
3724 /***********************************************************************
3725 * _protocol_getMethodTypeEncoding_nolock
3726 * Return the @encode string for the requested protocol method.
3727 * Returns NULL if the compiler did not emit any extended @encode data.
3728 * Locking: runtimeLock must be held for writing by the caller
3729 **********************************************************************/
3731 _protocol_getMethodTypeEncoding_nolock(protocol_t *proto, SEL sel,
3732 BOOL isRequiredMethod,
3733 BOOL isInstanceMethod)
3735 rwlock_assert_writing(&runtimeLock);
3737 if (!proto) return NULL;
3738 if (!proto->hasExtendedMethodTypes()) return NULL;
3741 _protocol_getMethod_nolock(proto, sel,
3742 isRequiredMethod, isInstanceMethod, false);
3744 uint32_t i = getExtendedTypesIndexForMethod(proto, m,
3747 return proto->extendedMethodTypes[i];
3750 // No method with that name. Search incorporated protocols.
3751 if (proto->protocols) {
3752 for (uintptr_t i = 0; i < proto->protocols->count; i++) {
3754 _protocol_getMethodTypeEncoding_nolock(remapProtocol(proto->protocols->list[i]), sel, isRequiredMethod, isInstanceMethod);
3755 if (enc) return enc;
3762 /***********************************************************************
3763 * _protocol_getMethodTypeEncoding
3764 * Return the @encode string for the requested protocol method.
3765 * Returns NULL if the compiler did not emit any extended @encode data.
3766 * Locking: runtimeLock must not be held by the caller
3767 **********************************************************************/
3769 _protocol_getMethodTypeEncoding(Protocol *proto_gen, SEL sel,
3770 BOOL isRequiredMethod, BOOL isInstanceMethod)
3773 rwlock_write(&runtimeLock);
3774 enc = _protocol_getMethodTypeEncoding_nolock(newprotocol(proto_gen), sel,
3777 rwlock_unlock_write(&runtimeLock);
3781 /***********************************************************************
3783 * Returns the name of the given protocol.
3784 * Locking: runtimeLock must not be held by the caller
3785 **********************************************************************/
3787 protocol_getName(Protocol *proto)
3789 return newprotocol(proto)->name;
3793 /***********************************************************************
3794 * protocol_getInstanceMethodDescription
3795 * Returns the description of a named instance method.
3796 * Locking: runtimeLock must not be held by the caller
3797 **********************************************************************/
3798 struct objc_method_description
3799 protocol_getMethodDescription(Protocol *p, SEL aSel,
3800 BOOL isRequiredMethod, BOOL isInstanceMethod)
3803 _protocol_getMethod(p, aSel, isRequiredMethod, isInstanceMethod, true);
3804 if (m) return *method_getDescription(m);
3805 else return (struct objc_method_description){NULL, NULL};
3809 /***********************************************************************
3810 * _protocol_conformsToProtocol_nolock
3811 * Returns YES if self conforms to other.
3812 * Locking: runtimeLock must be held by the caller.
3813 **********************************************************************/
3814 static BOOL _protocol_conformsToProtocol_nolock(protocol_t *self, protocol_t *other)
3816 if (!self || !other) {
3820 if (0 == strcmp(self->name, other->name)) {
3824 if (self->protocols) {
3826 for (i = 0; i < self->protocols->count; i++) {
3827 protocol_t *proto = remapProtocol(self->protocols->list[i]);
3828 if (0 == strcmp(other->name, proto->name)) {
3831 if (_protocol_conformsToProtocol_nolock(proto, other)) {
3841 /***********************************************************************
3842 * protocol_conformsToProtocol
3843 * Returns YES if self conforms to other.
3844 * Locking: acquires runtimeLock
3845 **********************************************************************/
3846 BOOL protocol_conformsToProtocol(Protocol *self, Protocol *other)
3849 rwlock_read(&runtimeLock);
3850 result = _protocol_conformsToProtocol_nolock(newprotocol(self),
3851 newprotocol(other));
3852 rwlock_unlock_read(&runtimeLock);
3857 /***********************************************************************
3859 * Return YES if two protocols are equal (i.e. conform to each other)
3860 * Locking: acquires runtimeLock
3861 **********************************************************************/
3862 BOOL protocol_isEqual(Protocol *self, Protocol *other)
3864 if (self == other) return YES;
3865 if (!self || !other) return NO;
3867 if (!protocol_conformsToProtocol(self, other)) return NO;
3868 if (!protocol_conformsToProtocol(other, self)) return NO;
3874 /***********************************************************************
3875 * protocol_copyMethodDescriptionList
3876 * Returns descriptions of a protocol's methods.
3877 * Locking: acquires runtimeLock
3878 **********************************************************************/
3879 struct objc_method_description *
3880 protocol_copyMethodDescriptionList(Protocol *p,
3881 BOOL isRequiredMethod,BOOL isInstanceMethod,
3882 unsigned int *outCount)
3884 protocol_t *proto = newprotocol(p);
3885 struct objc_method_description *result = NULL;
3886 unsigned int count = 0;
3889 if (outCount) *outCount = 0;
3893 rwlock_read(&runtimeLock);
3895 method_list_t *mlist = NULL;
3897 if (isRequiredMethod) {
3898 if (isInstanceMethod) {
3899 mlist = proto->instanceMethods;
3901 mlist = proto->classMethods;
3904 if (isInstanceMethod) {
3905 mlist = proto->optionalInstanceMethods;
3907 mlist = proto->optionalClassMethods;
3913 count = mlist->count;
3914 result = (struct objc_method_description *)
3915 calloc(count + 1, sizeof(struct objc_method_description));
3916 for (i = 0; i < count; i++) {
3917 method_t *m = method_list_nth(mlist, i);
3918 result[i].name = sel_registerName((const char *)m->name);
3919 result[i].types = (char *)m->types;
3923 rwlock_unlock_read(&runtimeLock);
3925 if (outCount) *outCount = count;
3930 /***********************************************************************
3931 * protocol_getProperty
3933 * Locking: acquires runtimeLock
3934 **********************************************************************/
3936 _protocol_getProperty_nolock(protocol_t *proto, const char *name,
3937 BOOL isRequiredProperty, BOOL isInstanceProperty)
3939 if (!isRequiredProperty || !isInstanceProperty) {
3940 // Only required instance properties are currently supported
3944 property_list_t *plist;
3945 if ((plist = proto->instanceProperties)) {
3947 for (i = 0; i < plist->count; i++) {
3948 property_t *prop = property_list_nth(plist, i);
3949 if (0 == strcmp(name, prop->name)) {
3955 if (proto->protocols) {
3957 for (i = 0; i < proto->protocols->count; i++) {
3958 protocol_t *p = remapProtocol(proto->protocols->list[i]);
3960 _protocol_getProperty_nolock(p, name,
3962 isInstanceProperty);
3963 if (prop) return prop;
3970 objc_property_t protocol_getProperty(Protocol *p, const char *name,
3971 BOOL isRequiredProperty, BOOL isInstanceProperty)
3975 if (!p || !name) return NULL;
3977 rwlock_read(&runtimeLock);
3978 result = _protocol_getProperty_nolock(newprotocol(p), name,
3980 isInstanceProperty);
3981 rwlock_unlock_read(&runtimeLock);
3983 return (objc_property_t)result;
3987 /***********************************************************************
3988 * protocol_copyPropertyList
3990 * Locking: acquires runtimeLock
3991 **********************************************************************/
3992 static property_t **
3993 copyPropertyList(property_list_t *plist, unsigned int *outCount)
3995 property_t **result = NULL;
3996 unsigned int count = 0;
3999 count = plist->count;
4004 result = (property_t **)malloc((count+1) * sizeof(property_t *));
4006 for (i = 0; i < count; i++) {
4007 result[i] = property_list_nth(plist, i);
4012 if (outCount) *outCount = count;
4016 objc_property_t *protocol_copyPropertyList(Protocol *proto, unsigned int *outCount)
4018 property_t **result = NULL;
4021 if (outCount) *outCount = 0;
4025 rwlock_read(&runtimeLock);
4027 property_list_t *plist = newprotocol(proto)->instanceProperties;
4028 result = copyPropertyList(plist, outCount);
4030 rwlock_unlock_read(&runtimeLock);
4032 return (objc_property_t *)result;
4036 /***********************************************************************
4037 * protocol_copyProtocolList
4038 * Copies this protocol's incorporated protocols.
4039 * Does not copy those protocol's incorporated protocols in turn.
4040 * Locking: acquires runtimeLock
4041 **********************************************************************/
4042 Protocol * __unsafe_unretained *
4043 protocol_copyProtocolList(Protocol *p, unsigned int *outCount)
4045 unsigned int count = 0;
4046 Protocol **result = NULL;
4047 protocol_t *proto = newprotocol(p);
4050 if (outCount) *outCount = 0;
4054 rwlock_read(&runtimeLock);
4056 if (proto->protocols) {
4057 count = (unsigned int)proto->protocols->count;
4060 result = (Protocol **)malloc((count+1) * sizeof(Protocol *));
4063 for (i = 0; i < count; i++) {
4064 result[i] = (Protocol *)remapProtocol(proto->protocols->list[i]);
4069 rwlock_unlock_read(&runtimeLock);
4071 if (outCount) *outCount = count;
4076 /***********************************************************************
4077 * objc_allocateProtocol
4078 * Creates a new protocol. The protocol may not be used until
4079 * objc_registerProtocol() is called.
4080 * Returns NULL if a protocol with the same name already exists.
4081 * Locking: acquires runtimeLock
4082 **********************************************************************/
4084 objc_allocateProtocol(const char *name)
4086 rwlock_write(&runtimeLock);
4088 if (NXMapGet(protocols(), name)) {
4089 rwlock_unlock_write(&runtimeLock);
4093 protocol_t *result = (protocol_t *)_calloc_internal(sizeof(protocol_t), 1);
4095 extern class_t OBJC_CLASS_$___IncompleteProtocol;
4096 Class cls = (Class)&OBJC_CLASS_$___IncompleteProtocol;
4098 result->name = _strdup_internal(name);
4100 // fixme reserve name without installing
4102 rwlock_unlock_write(&runtimeLock);
4104 return (Protocol *)result;
4108 /***********************************************************************
4109 * objc_registerProtocol
4110 * Registers a newly-constructed protocol. The protocol is now
4111 * ready for use and immutable.
4112 * Locking: acquires runtimeLock
4113 **********************************************************************/
4114 void objc_registerProtocol(Protocol *proto_gen)
4116 protocol_t *proto = newprotocol(proto_gen);
4118 rwlock_write(&runtimeLock);
4120 extern class_t OBJC_CLASS_$___IncompleteProtocol;
4121 Class oldcls = (Class)&OBJC_CLASS_$___IncompleteProtocol;
4122 extern class_t OBJC_CLASS_$_Protocol;
4123 Class cls = (Class)&OBJC_CLASS_$_Protocol;
4125 if (proto->isa == cls) {
4126 _objc_inform("objc_registerProtocol: protocol '%s' was already "
4127 "registered!", proto->name);
4128 rwlock_unlock_write(&runtimeLock);
4131 if (proto->isa != oldcls) {
4132 _objc_inform("objc_registerProtocol: protocol '%s' was not allocated "
4133 "with objc_allocateProtocol!", proto->name);
4134 rwlock_unlock_write(&runtimeLock);
4140 NXMapKeyCopyingInsert(protocols(), proto->name, proto);
4142 rwlock_unlock_write(&runtimeLock);
4146 /***********************************************************************
4147 * protocol_addProtocol
4148 * Adds an incorporated protocol to another protocol.
4149 * No method enforcement is performed.
4150 * `proto` must be under construction. `addition` must not.
4151 * Locking: acquires runtimeLock
4152 **********************************************************************/
4154 protocol_addProtocol(Protocol *proto_gen, Protocol *addition_gen)
4156 protocol_t *proto = newprotocol(proto_gen);
4157 protocol_t *addition = newprotocol(addition_gen);
4159 extern class_t OBJC_CLASS_$___IncompleteProtocol;
4160 Class cls = (Class)&OBJC_CLASS_$___IncompleteProtocol;
4162 if (!proto_gen) return;
4163 if (!addition_gen) return;
4165 rwlock_write(&runtimeLock);
4167 if (proto->isa != cls) {
4168 _objc_inform("protocol_addProtocol: modified protocol '%s' is not "
4169 "under construction!", proto->name);
4170 rwlock_unlock_write(&runtimeLock);
4173 if (addition->isa == cls) {
4174 _objc_inform("protocol_addProtocol: added protocol '%s' is still "
4175 "under construction!", addition->name);
4176 rwlock_unlock_write(&runtimeLock);
4180 protocol_list_t *protolist = proto->protocols;
4182 protolist = (protocol_list_t *)
4183 _calloc_internal(1, sizeof(protocol_list_t)
4184 + sizeof(protolist->list[0]));
4186 protolist = (protocol_list_t *)
4187 _realloc_internal(protolist, protocol_list_size(protolist)
4188 + sizeof(protolist->list[0]));
4191 protolist->list[protolist->count++] = (protocol_ref_t)addition;
4192 proto->protocols = protolist;
4194 rwlock_unlock_write(&runtimeLock);
4198 /***********************************************************************
4199 * protocol_addMethodDescription
4200 * Adds a method to a protocol. The protocol must be under construction.
4201 * Locking: acquires runtimeLock
4202 **********************************************************************/
4204 _protocol_addMethod(method_list_t **list, SEL name, const char *types)
4207 *list = (method_list_t *)
4208 _calloc_internal(sizeof(method_list_t), 1);
4209 (*list)->entsize_NEVER_USE = sizeof((*list)->first);
4210 setMethodListFixedUp(*list);
4212 size_t size = method_list_size(*list) + method_list_entsize(*list);
4213 *list = (method_list_t *)
4214 _realloc_internal(*list, size);
4217 method_t *meth = method_list_nth(*list, (*list)->count++);
4219 meth->types = _strdup_internal(types ? types : "");
4224 protocol_addMethodDescription(Protocol *proto_gen, SEL name, const char *types,
4225 BOOL isRequiredMethod, BOOL isInstanceMethod)
4227 protocol_t *proto = newprotocol(proto_gen);
4229 extern class_t OBJC_CLASS_$___IncompleteProtocol;
4230 Class cls = (Class)&OBJC_CLASS_$___IncompleteProtocol;
4232 if (!proto_gen) return;
4234 rwlock_write(&runtimeLock);
4236 if (proto->isa != cls) {
4237 _objc_inform("protocol_addMethodDescription: protocol '%s' is not "
4238 "under construction!", proto->name);
4239 rwlock_unlock_write(&runtimeLock);
4243 if (isRequiredMethod && isInstanceMethod) {
4244 _protocol_addMethod(&proto->instanceMethods, name, types);
4245 } else if (isRequiredMethod && !isInstanceMethod) {
4246 _protocol_addMethod(&proto->classMethods, name, types);
4247 } else if (!isRequiredMethod && isInstanceMethod) {
4248 _protocol_addMethod(&proto->optionalInstanceMethods, name, types);
4249 } else /* !isRequiredMethod && !isInstanceMethod) */ {
4250 _protocol_addMethod(&proto->optionalClassMethods, name, types);
4253 rwlock_unlock_write(&runtimeLock);
4257 /***********************************************************************
4258 * protocol_addProperty
4259 * Adds a property to a protocol. The protocol must be under construction.
4260 * Locking: acquires runtimeLock
4261 **********************************************************************/
4263 _protocol_addProperty(property_list_t **plist, const char *name,
4264 const objc_property_attribute_t *attrs,
4268 *plist = (property_list_t *)
4269 _calloc_internal(sizeof(property_list_t), 1);
4270 (*plist)->entsize = sizeof(property_t);
4272 *plist = (property_list_t *)
4273 _realloc_internal(*plist, sizeof(property_list_t)
4274 + (*plist)->count * (*plist)->entsize);
4277 property_t *prop = property_list_nth(*plist, (*plist)->count++);
4278 prop->name = _strdup_internal(name);
4279 prop->attributes = copyPropertyAttributeString(attrs, count);
4283 protocol_addProperty(Protocol *proto_gen, const char *name,
4284 const objc_property_attribute_t *attrs,
4286 BOOL isRequiredProperty, BOOL isInstanceProperty)
4288 protocol_t *proto = newprotocol(proto_gen);
4290 extern class_t OBJC_CLASS_$___IncompleteProtocol;
4291 Class cls = (Class)&OBJC_CLASS_$___IncompleteProtocol;
4296 rwlock_write(&runtimeLock);
4298 if (proto->isa != cls) {
4299 _objc_inform("protocol_addProperty: protocol '%s' is not "
4300 "under construction!", proto->name);
4301 rwlock_unlock_write(&runtimeLock);
4305 if (isRequiredProperty && isInstanceProperty) {
4306 _protocol_addProperty(&proto->instanceProperties, name, attrs, count);
4308 //else if (isRequiredProperty && !isInstanceProperty) {
4309 // _protocol_addProperty(&proto->classProperties, name, attrs, count);
4310 //} else if (!isRequiredProperty && isInstanceProperty) {
4311 // _protocol_addProperty(&proto->optionalInstanceProperties, name, attrs, count);
4312 //} else /* !isRequiredProperty && !isInstanceProperty) */ {
4313 // _protocol_addProperty(&proto->optionalClassProperties, name, attrs, count);
4316 rwlock_unlock_write(&runtimeLock);
4320 /***********************************************************************
4322 * Returns pointers to all classes.
4323 * This requires all classes be realized, which is regretfully non-lazy.
4324 * Locking: acquires runtimeLock
4325 **********************************************************************/
4327 objc_getClassList(Class *buffer, int bufferLen)
4329 rwlock_write(&runtimeLock);
4331 realizeAllClasses();
4336 NXHashTable *classes = realizedClasses();
4337 int allCount = NXCountHashTable(classes);
4340 rwlock_unlock_write(&runtimeLock);
4345 state = NXInitHashState(classes);
4346 while (count < bufferLen &&
4347 NXNextHashState(classes, &state, (void **)&cls))
4349 buffer[count++] = (Class)cls;
4352 rwlock_unlock_write(&runtimeLock);
4358 /***********************************************************************
4359 * objc_copyClassList
4360 * Returns pointers to all classes.
4361 * This requires all classes be realized, which is regretfully non-lazy.
4363 * outCount may be NULL. *outCount is the number of classes returned.
4364 * If the returned array is not NULL, it is NULL-terminated and must be
4365 * freed with free().
4366 * Locking: write-locks runtimeLock
4367 **********************************************************************/
4369 objc_copyClassList(unsigned int *outCount)
4371 rwlock_write(&runtimeLock);
4373 realizeAllClasses();
4375 Class *result = NULL;
4376 NXHashTable *classes = realizedClasses();
4377 unsigned int count = NXCountHashTable(classes);
4381 NXHashState state = NXInitHashState(classes);
4382 result = (Class *)malloc((1+count) * sizeof(Class));
4384 while (NXNextHashState(classes, &state, (void **)&cls)) {
4385 result[count++] = (Class)cls;
4387 result[count] = NULL;
4390 rwlock_unlock_write(&runtimeLock);
4392 if (outCount) *outCount = count;
4397 /***********************************************************************
4398 * objc_copyProtocolList
4399 * Returns pointers to all protocols.
4400 * Locking: read-locks runtimeLock
4401 **********************************************************************/
4402 Protocol * __unsafe_unretained *
4403 objc_copyProtocolList(unsigned int *outCount)
4405 rwlock_read(&runtimeLock);
4407 unsigned int count, i;
4411 NXMapTable *protocol_map = protocols();
4414 count = NXCountMapTable(protocol_map);
4416 rwlock_unlock_read(&runtimeLock);
4417 if (outCount) *outCount = 0;
4421 result = (Protocol **)calloc(1 + count, sizeof(Protocol *));
4424 state = NXInitMapState(protocol_map);
4425 while (NXNextMapState(protocol_map, &state,
4426 (const void **)&name, (const void **)&proto))
4428 result[i++] = proto;
4432 assert(i == count+1);
4434 rwlock_unlock_read(&runtimeLock);
4436 if (outCount) *outCount = count;
4441 /***********************************************************************
4443 * Get a protocol by name, or return NULL
4444 * Locking: read-locks runtimeLock
4445 **********************************************************************/
4446 Protocol *objc_getProtocol(const char *name)
4448 rwlock_read(&runtimeLock);
4449 Protocol *result = (Protocol *)NXMapGet(protocols(), name);
4450 rwlock_unlock_read(&runtimeLock);
4455 /***********************************************************************
4456 * class_copyMethodList
4458 * Locking: read-locks runtimeLock
4459 **********************************************************************/
4461 class_copyMethodList(Class cls_gen, unsigned int *outCount)
4463 class_t *cls = newcls(cls_gen);
4464 unsigned int count = 0;
4465 Method *result = NULL;
4468 if (outCount) *outCount = 0;
4472 rwlock_read(&runtimeLock);
4474 assert(isRealized(cls));
4476 FOREACH_METHOD_LIST(mlist, cls, {
4477 count += mlist->count;
4482 result = (Method *)malloc((count + 1) * sizeof(Method));
4485 FOREACH_METHOD_LIST(mlist, cls, {
4487 for (i = 0; i < mlist->count; i++) {
4488 Method aMethod = (Method)method_list_nth(mlist, i);
4489 if (ignoreSelector(method_getName(aMethod))) {
4493 result[m++] = aMethod;
4499 rwlock_unlock_read(&runtimeLock);
4501 if (outCount) *outCount = count;
4506 /***********************************************************************
4507 * class_copyIvarList
4509 * Locking: read-locks runtimeLock
4510 **********************************************************************/
4512 class_copyIvarList(Class cls_gen, unsigned int *outCount)
4514 class_t *cls = newcls(cls_gen);
4515 const ivar_list_t *ivars;
4516 Ivar *result = NULL;
4517 unsigned int count = 0;
4521 if (outCount) *outCount = 0;
4525 rwlock_read(&runtimeLock);
4527 assert(isRealized(cls));
4529 if ((ivars = cls->data()->ro->ivars) && ivars->count) {
4530 result = (Ivar *)malloc((ivars->count+1) * sizeof(Ivar));
4532 for (i = 0; i < ivars->count; i++) {
4533 ivar_t *ivar = ivar_list_nth(ivars, i);
4534 if (!ivar->offset) continue; // anonymous bitfield
4535 result[count++] = (Ivar)ivar;
4537 result[count] = NULL;
4540 rwlock_unlock_read(&runtimeLock);
4542 if (outCount) *outCount = count;
4547 /***********************************************************************
4548 * class_copyPropertyList. Returns a heap block containing the
4549 * properties declared in the class, or NULL if the class
4550 * declares no properties. Caller must free the block.
4551 * Does not copy any superclass's properties.
4552 * Locking: read-locks runtimeLock
4553 **********************************************************************/
4555 class_copyPropertyList(Class cls_gen, unsigned int *outCount)
4557 class_t *cls = newcls(cls_gen);
4558 chained_property_list *plist;
4559 unsigned int count = 0;
4560 property_t **result = NULL;
4563 if (outCount) *outCount = 0;
4567 rwlock_read(&runtimeLock);
4569 assert(isRealized(cls));
4571 for (plist = cls->data()->properties; plist; plist = plist->next) {
4572 count += plist->count;
4577 result = (property_t **)malloc((count + 1) * sizeof(property_t *));
4580 for (plist = cls->data()->properties; plist; plist = plist->next) {
4582 for (i = 0; i < plist->count; i++) {
4583 result[p++] = &plist->list[i];
4589 rwlock_unlock_read(&runtimeLock);
4591 if (outCount) *outCount = count;
4592 return (objc_property_t *)result;
4596 /***********************************************************************
4597 * _class_getLoadMethod
4599 * Called only from add_class_to_loadable_list.
4600 * Locking: runtimeLock must be read- or write-locked by the caller.
4601 **********************************************************************/
4603 _class_getLoadMethod(Class cls_gen)
4605 rwlock_assert_locked(&runtimeLock);
4607 class_t *cls = newcls(cls_gen);
4608 const method_list_t *mlist;
4611 assert(isRealized(cls));
4612 assert(isRealized(cls->isa));
4613 assert(!isMetaClass(cls));
4614 assert(isMetaClass(cls->isa));
4616 mlist = cls->isa->data()->ro->baseMethods;
4617 if (mlist) for (i = 0; i < mlist->count; i++) {
4618 method_t *m = method_list_nth(mlist, i);
4619 if (0 == strcmp((const char *)m->name, "load")) {
4628 /***********************************************************************
4630 * Returns a category's name.
4632 **********************************************************************/
4634 _category_getName(Category cat)
4636 return newcategory(cat)->name;
4640 /***********************************************************************
4641 * _category_getClassName
4642 * Returns a category's class's name
4643 * Called only from add_category_to_loadable_list and
4644 * remove_category_from_loadable_list.
4645 * Locking: runtimeLock must be read- or write-locked by the caller
4646 **********************************************************************/
4648 _category_getClassName(Category cat)
4650 rwlock_assert_locked(&runtimeLock);
4651 return getName(remapClass(newcategory(cat)->cls));
4655 /***********************************************************************
4656 * _category_getClass
4657 * Returns a category's class
4658 * Called only by call_category_loads.
4659 * Locking: read-locks runtimeLock
4660 **********************************************************************/
4662 _category_getClass(Category cat)
4664 rwlock_read(&runtimeLock);
4665 class_t *result = remapClass(newcategory(cat)->cls);
4666 assert(isRealized(result)); // ok for call_category_loads' usage
4667 rwlock_unlock_read(&runtimeLock);
4668 return (Class)result;
4672 /***********************************************************************
4673 * _category_getLoadMethod
4675 * Called only from add_category_to_loadable_list
4676 * Locking: runtimeLock must be read- or write-locked by the caller
4677 **********************************************************************/
4679 _category_getLoadMethod(Category cat)
4681 rwlock_assert_locked(&runtimeLock);
4683 const method_list_t *mlist;
4686 mlist = newcategory(cat)->classMethods;
4687 if (mlist) for (i = 0; i < mlist->count; i++) {
4688 method_t *m = method_list_nth(mlist, i);
4689 if (0 == strcmp((const char *)m->name, "load")) {
4698 /***********************************************************************
4699 * class_copyProtocolList
4701 * Locking: read-locks runtimeLock
4702 **********************************************************************/
4703 Protocol * __unsafe_unretained *
4704 class_copyProtocolList(Class cls_gen, unsigned int *outCount)
4706 class_t *cls = newcls(cls_gen);
4708 const protocol_list_t **p;
4709 unsigned int count = 0;
4711 Protocol **result = NULL;
4714 if (outCount) *outCount = 0;
4718 rwlock_read(&runtimeLock);
4720 assert(isRealized(cls));
4722 for (p = cls->data()->protocols; p && *p; p++) {
4723 count += (uint32_t)(*p)->count;
4727 result = (Protocol **)malloc((count+1) * sizeof(Protocol *));
4729 for (p = cls->data()->protocols; p && *p; p++) {
4730 for (i = 0; i < (*p)->count; i++) {
4731 *r++ = (Protocol *)remapProtocol((*p)->list[i]);
4737 rwlock_unlock_read(&runtimeLock);
4739 if (outCount) *outCount = count;
4744 /***********************************************************************
4745 * _objc_copyClassNamesForImage
4747 * Locking: read-locks runtimeLock
4748 **********************************************************************/
4750 _objc_copyClassNamesForImage(header_info *hi, unsigned int *outCount)
4752 size_t count, i, shift;
4753 classref_t *classlist;
4756 rwlock_read(&runtimeLock);
4758 classlist = _getObjc2ClassList(hi, &count);
4759 names = (const char **)malloc((count+1) * sizeof(const char *));
4762 for (i = 0; i < count; i++) {
4763 class_t *cls = remapClass(classlist[i]);
4765 names[i-shift] = getName(cls);
4767 shift++; // ignored weak-linked class
4771 names[count] = NULL;
4773 rwlock_unlock_read(&runtimeLock);
4775 if (outCount) *outCount = (unsigned int)count;
4780 /***********************************************************************
4784 **********************************************************************/
4786 _class_getCache(Class cls)
4788 return newcls(cls)->cache;
4792 /***********************************************************************
4793 * _class_getInstanceSize
4794 * Uses alignedInstanceSize() to ensure that
4795 * obj + class_getInstanceSize(obj->isa) == object_getIndexedIvars(obj)
4797 **********************************************************************/
4799 _class_getInstanceSize(Class cls)
4802 return alignedInstanceSize(newcls(cls));
4806 unalignedInstanceSize(class_t *cls)
4809 assert(isRealized(cls));
4810 return (uint32_t)cls->data()->ro->instanceSize;
4814 alignedInstanceSize(class_t *cls)
4817 assert(isRealized(cls));
4818 // fixme rdar://5278267
4819 return (uint32_t)((unalignedInstanceSize(cls) + WORD_MASK) & ~WORD_MASK);
4822 /***********************************************************************
4823 * _class_getInstanceStart
4824 * Uses alignedInstanceStart() to ensure that ARR layout strings are
4825 * interpreted relative to the first word aligned ivar of an object.
4827 **********************************************************************/
4830 alignedInstanceStart(class_t *cls)
4833 assert(isRealized(cls));
4834 return (uint32_t)((cls->data()->ro->instanceStart + WORD_MASK) & ~WORD_MASK);
4837 uint32_t _class_getInstanceStart(Class cls_gen) {
4838 class_t *cls = newcls(cls_gen);
4839 return alignedInstanceStart(cls);
4843 /***********************************************************************
4847 **********************************************************************/
4849 class_getVersion(Class cls)
4852 assert(isRealized(newcls(cls)));
4853 return newcls(cls)->data()->version;
4857 /***********************************************************************
4861 **********************************************************************/
4863 _class_setCache(Class cls, Cache cache)
4865 newcls(cls)->cache = cache;
4869 /***********************************************************************
4873 **********************************************************************/
4875 class_setVersion(Class cls, int version)
4878 assert(isRealized(newcls(cls)));
4879 newcls(cls)->data()->version = version;
4883 /***********************************************************************
4886 * Locking: acquires runtimeLock
4887 **********************************************************************/
4888 const char *_class_getName(Class cls)
4890 if (!cls) return "nil";
4891 // fixme hack rwlock_write(&runtimeLock);
4892 const char *name = getName(newcls(cls));
4893 // rwlock_unlock_write(&runtimeLock);
4898 /***********************************************************************
4901 * Locking: runtimeLock must be held by the caller
4902 **********************************************************************/
4904 getName(class_t *cls)
4906 // fixme hack rwlock_assert_writing(&runtimeLock);
4909 if (isRealized(cls)) {
4910 return cls->data()->ro->name;
4912 return ((const class_ro_t *)cls->data())->name;
4916 static method_t *findMethodInSortedMethodList(SEL key, const method_list_t *list)
4918 const method_t * const first = &list->first;
4919 const method_t *base = first;
4920 const method_t *probe;
4921 uintptr_t keyValue = (uintptr_t)key;
4924 for (count = list->count; count != 0; count >>= 1) {
4925 probe = base + (count >> 1);
4927 uintptr_t probeValue = (uintptr_t)probe->name;
4929 if (keyValue == probeValue) {
4930 // `probe` is a match.
4931 // Rewind looking for the *first* occurrence of this value.
4932 // This is required for correct category overrides.
4933 while (probe > first && keyValue == (uintptr_t)probe[-1].name) {
4936 return (method_t *)probe;
4939 if (keyValue > probeValue) {
4948 /***********************************************************************
4949 * getMethodNoSuper_nolock
4951 * Locking: runtimeLock must be read- or write-locked by the caller
4952 **********************************************************************/
4953 static method_t *search_method_list(const method_list_t *mlist, SEL sel)
4955 int methodListIsFixedUp = isMethodListFixedUp(mlist);
4956 int methodListHasExpectedSize = mlist->getEntsize() == sizeof(method_t);
4958 if (__builtin_expect(methodListIsFixedUp && methodListHasExpectedSize, 1)) {
4959 return findMethodInSortedMethodList(sel, mlist);
4961 // Linear search of unsorted method list
4962 method_list_t::method_iterator iter = mlist->begin();
4963 method_list_t::method_iterator end = mlist->end();
4964 for ( ; iter != end; ++iter) {
4965 if (iter->name == sel) return &*iter;
4970 // sanity-check negative results
4971 if (isMethodListFixedUp(mlist)) {
4972 method_list_t::method_iterator iter = mlist->begin();
4973 method_list_t::method_iterator end = mlist->end();
4974 for ( ; iter != end; ++iter) {
4975 if (iter->name == sel) {
4976 _objc_fatal("linear search worked when binary search did not");
4986 getMethodNoSuper_nolock(class_t *cls, SEL sel)
4988 rwlock_assert_locked(&runtimeLock);
4990 assert(isRealized(cls));
4994 FOREACH_METHOD_LIST(mlist, cls, {
4995 method_t *m = search_method_list(mlist, sel);
5003 /***********************************************************************
5004 * _class_getMethodNoSuper
5006 * Locking: read-locks runtimeLock
5007 **********************************************************************/
5009 _class_getMethodNoSuper(Class cls, SEL sel)
5011 rwlock_read(&runtimeLock);
5012 Method result = (Method)getMethodNoSuper_nolock(newcls(cls), sel);
5013 rwlock_unlock_read(&runtimeLock);
5017 /***********************************************************************
5018 * _class_getMethodNoSuper
5019 * For use inside lockForMethodLookup() only.
5020 * Locking: read-locks runtimeLock
5021 **********************************************************************/
5023 _class_getMethodNoSuper_nolock(Class cls, SEL sel)
5025 return (Method)getMethodNoSuper_nolock(newcls(cls), sel);
5029 /***********************************************************************
5032 * Locking: runtimeLock must be read- or write-locked by the caller
5033 **********************************************************************/
5035 getMethod_nolock(class_t *cls, SEL sel)
5039 rwlock_assert_locked(&runtimeLock);
5044 assert(isRealized(cls));
5046 while (cls && ((m = getMethodNoSuper_nolock(cls, sel))) == NULL) {
5047 cls = getSuperclass(cls);
5054 /***********************************************************************
5057 * Locking: read-locks runtimeLock
5058 **********************************************************************/
5059 Method _class_getMethod(Class cls, SEL sel)
5062 rwlock_read(&runtimeLock);
5063 m = (Method)getMethod_nolock(newcls(cls), sel);
5064 rwlock_unlock_read(&runtimeLock);
5069 /***********************************************************************
5070 * ABI-specific lookUpMethod helpers.
5071 * Locking: read- and write-locks runtimeLock.
5072 **********************************************************************/
5073 void lockForMethodLookup(void)
5075 rwlock_read(&runtimeLock);
5077 void unlockForMethodLookup(void)
5079 rwlock_unlock_read(&runtimeLock);
5082 IMP prepareForMethodLookup(Class cls, SEL sel, BOOL init, id obj)
5084 rwlock_assert_unlocked(&runtimeLock);
5086 if (!isRealized(newcls(cls))) {
5087 rwlock_write(&runtimeLock);
5088 realizeClass(newcls(cls));
5089 rwlock_unlock_write(&runtimeLock);
5092 if (init && !_class_isInitialized(cls)) {
5093 _class_initialize (_class_getNonMetaClass(cls, obj));
5094 // If sel == initialize, _class_initialize will send +initialize and
5095 // then the messenger will send +initialize again after this
5096 // procedure finishes. Of course, if this is not being called
5097 // from the messenger then it won't happen. 2778172
5104 /***********************************************************************
5107 * Locking: read-locks runtimeLock
5108 **********************************************************************/
5109 objc_property_t class_getProperty(Class cls_gen, const char *name)
5111 property_t *result = NULL;
5112 chained_property_list *plist;
5113 class_t *cls = newcls(cls_gen);
5115 if (!cls || !name) return NULL;
5117 rwlock_read(&runtimeLock);
5119 assert(isRealized(cls));
5121 for ( ; cls; cls = getSuperclass(cls)) {
5122 for (plist = cls->data()->properties; plist; plist = plist->next) {
5124 for (i = 0; i < plist->count; i++) {
5125 if (0 == strcmp(name, plist->list[i].name)) {
5126 result = &plist->list[i];
5134 rwlock_unlock_read(&runtimeLock);
5136 return (objc_property_t)result;
5140 /***********************************************************************
5142 **********************************************************************/
5143 BOOL _class_isMetaClass(Class cls)
5145 if (!cls) return NO;
5146 return isMetaClass(newcls(cls));
5150 isMetaClass(class_t *cls)
5153 assert(isRealized(cls));
5154 return (cls->data()->ro->flags & RO_META) ? YES : NO;
5157 class_t *getMeta(class_t *cls)
5159 if (isMetaClass(cls)) return cls;
5160 else return cls->isa;
5163 Class _class_getMeta(Class cls)
5165 return (Class)getMeta(newcls(cls));
5168 Class gdb_class_getClass(Class cls)
5170 const char *className = getName(newcls(cls));
5171 if(!className || !strlen(className)) return Nil;
5172 Class rCls = look_up_class(className, NO, NO);
5176 Class gdb_object_getClass(id obj)
5178 Class cls = _object_getClass(obj);
5179 return gdb_class_getClass(cls);
5182 BOOL gdb_objc_isRuntimeLocked()
5184 if (rwlock_try_write(&runtimeLock)) {
5185 rwlock_unlock_write(&runtimeLock);
5189 if (mutex_try_lock(&cacheUpdateLock)) {
5190 mutex_unlock(&cacheUpdateLock);
5197 /***********************************************************************
5199 **********************************************************************/
5201 _class_isInitializing(Class cls_gen)
5203 class_t *cls = newcls(_class_getMeta(cls_gen));
5204 return (cls->data()->flags & RW_INITIALIZING) ? YES : NO;
5208 /***********************************************************************
5210 **********************************************************************/
5212 _class_isInitialized(Class cls_gen)
5214 class_t *cls = newcls(_class_getMeta(cls_gen));
5215 return (cls->data()->flags & RW_INITIALIZED) ? YES : NO;
5219 /***********************************************************************
5221 **********************************************************************/
5223 _class_setInitializing(Class cls_gen)
5225 assert(!_class_isMetaClass(cls_gen));
5226 class_t *cls = newcls(_class_getMeta(cls_gen));
5227 changeInfo(cls, RW_INITIALIZING, 0);
5231 /***********************************************************************
5232 * Locking: write-locks runtimeLock
5233 **********************************************************************/
5235 _class_setInitialized(Class cls_gen)
5240 rwlock_write(&runtimeLock);
5242 assert(!_class_isMetaClass(cls_gen));
5244 cls = newcls(cls_gen);
5245 metacls = getMeta(cls);
5247 // Update vtables (initially postponed pending +initialize completion)
5248 // Do cls first because root metacls is a subclass of root cls
5249 updateVtable(cls, YES);
5250 updateVtable(metacls, YES);
5252 rwlock_unlock_write(&runtimeLock);
5254 changeInfo(metacls, RW_INITIALIZED, RW_INITIALIZING);
5258 /***********************************************************************
5260 **********************************************************************/
5262 _class_shouldGrowCache(Class cls)
5264 return YES; // fixme good or bad for memory use?
5268 /***********************************************************************
5270 **********************************************************************/
5272 _class_setGrowCache(Class cls, BOOL grow)
5274 // fixme good or bad for memory use?
5278 /***********************************************************************
5282 **********************************************************************/
5284 _class_isLoadable(Class cls)
5286 assert(isRealized(newcls(cls)));
5287 return YES; // any class registered for +load is definitely loadable
5291 /***********************************************************************
5293 **********************************************************************/
5295 hasCxxStructors(class_t *cls)
5297 // this DOES check superclasses too, because addSubclass()
5298 // propagates the flag from the superclass.
5299 assert(isRealized(cls));
5300 return (cls->data()->flags & RW_HAS_CXX_STRUCTORS) ? YES : NO;
5304 _class_hasCxxStructors(Class cls)
5306 return hasCxxStructors(newcls(cls));
5310 /***********************************************************************
5312 **********************************************************************/
5314 _class_shouldFinalizeOnMainThread(Class cls)
5316 assert(isRealized(newcls(cls)));
5317 return (newcls(cls)->data()->flags & RW_FINALIZE_ON_MAIN_THREAD) ? YES : NO;
5321 /***********************************************************************
5323 **********************************************************************/
5325 _class_setFinalizeOnMainThread(Class cls)
5327 assert(isRealized(newcls(cls)));
5328 changeInfo(newcls(cls), RW_FINALIZE_ON_MAIN_THREAD, 0);
5332 /***********************************************************************
5333 * _class_instancesHaveAssociatedObjects
5334 * May manipulate unrealized future classes in the CF-bridged case.
5335 **********************************************************************/
5337 _class_instancesHaveAssociatedObjects(Class cls_gen)
5339 class_t *cls = newcls(cls_gen);
5340 assert(isFuture(cls) || isRealized(cls));
5341 return (cls->data()->flags & RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS) ? YES : NO;
5345 /***********************************************************************
5346 * _class_setInstancesHaveAssociatedObjects
5347 * May manipulate unrealized future classes in the CF-bridged case.
5348 **********************************************************************/
5350 _class_setInstancesHaveAssociatedObjects(Class cls_gen)
5352 class_t *cls = newcls(cls_gen);
5353 assert(isFuture(cls) || isRealized(cls));
5354 changeInfo(cls, RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS, 0);
5358 /***********************************************************************
5359 * _class_usesAutomaticRetainRelease
5360 * Returns YES if class was compiled with -fobjc-arc
5361 **********************************************************************/
5362 BOOL _class_usesAutomaticRetainRelease(Class cls_gen)
5364 class_t *cls = newcls(cls_gen);
5365 return (cls->data()->ro->flags & RO_IS_ARR) ? YES : NO;
5369 /***********************************************************************
5370 * Return YES if sel is used by retain/release implementors
5371 **********************************************************************/
5372 static bool isRRSelector(SEL sel)
5374 return (sel == SEL_retain || sel == SEL_release ||
5375 sel == SEL_autorelease || sel == SEL_retainCount);
5379 /***********************************************************************
5380 * Return YES if sel is used by allocWithZone implementors
5381 **********************************************************************/
5382 static bool isAWZSelector(SEL sel)
5384 return (sel == SEL_allocWithZone);
5388 /***********************************************************************
5389 * Mark this class and all of its subclasses as implementors or
5390 * inheritors of custom RR (retain/release/autorelease/retainCount)
5391 **********************************************************************/
5392 void class_t::setHasCustomRR(bool inherited)
5394 rwlock_assert_writing(&runtimeLock);
5396 if (hasCustomRR()) return;
5398 FOREACH_REALIZED_CLASS_AND_SUBCLASS(c, this, {
5399 if (PrintCustomRR && !c->hasCustomRR()) {
5400 _objc_inform("CUSTOM RR: %s%s%s", getName(c),
5401 isMetaClass(c) ? " (meta)" : "",
5402 (inherited || c != this) ? " (inherited)" : "");
5404 #if CLASS_FAST_FLAGS_VIA_RW_DATA
5405 c->data_NEVER_USE |= (uintptr_t)1;
5407 c->data()->flags |= RW_HAS_CUSTOM_RR;
5413 /***********************************************************************
5414 * Mark this class and all of its subclasses as implementors or
5415 * inheritors of custom allocWithZone:
5416 **********************************************************************/
5417 void class_t::setHasCustomAWZ(bool inherited )
5419 rwlock_assert_writing(&runtimeLock);
5421 if (hasCustomAWZ()) return;
5423 FOREACH_REALIZED_CLASS_AND_SUBCLASS(c, this, {
5424 if (PrintCustomAWZ && !c->hasCustomAWZ()) {
5425 _objc_inform("CUSTOM AWZ: %s%s%s", getName(c),
5426 isMetaClass(c) ? " (meta)" : "",
5427 (inherited || c != this) ? " (inherited)" : "");
5429 #if CLASS_FAST_FLAGS_VIA_RW_DATA
5430 c->data_NEVER_USE |= (uintptr_t)2;
5432 c->data()->flags |= RW_HAS_CUSTOM_AWZ;
5438 /***********************************************************************
5439 * Update custom RR and AWZ when a method changes its IMP
5440 **********************************************************************/
5442 updateCustomRR_AWZ(class_t *cls, method_t *meth)
5444 // In almost all cases, IMP swizzling does not affect custom RR/AWZ bits.
5445 // The class is already marked for custom RR/AWZ, so changing the IMP
5446 // does not transition from non-custom to custom.
5448 // The only cases where IMP swizzling can affect the RR/AWZ bits is
5449 // if the swizzled method is one of the methods that is assumed to be
5450 // non-custom. These special cases come from attachMethodLists().
5451 // We look for such cases here if we do not know the affected class.
5453 if (isRRSelector(meth->name)) {
5455 cls->setHasCustomRR();
5457 // Don't know the class.
5458 // The only special case is class NSObject.
5459 FOREACH_METHOD_LIST(mlist, classNSObject(), {
5460 for (uint32_t i = 0; i < mlist->count; i++) {
5461 if (meth == method_list_nth(mlist, i)) {
5462 // Yep, they're swizzling NSObject.
5463 classNSObject()->setHasCustomRR();
5470 else if (isAWZSelector(meth->name)) {
5472 cls->setHasCustomAWZ();
5474 // Don't know the class.
5475 // The only special case is metaclass NSObject.
5476 FOREACH_METHOD_LIST(mlist, classNSObject()->isa, {
5477 for (uint32_t i = 0; i < mlist->count; i++) {
5478 if (meth == method_list_nth(mlist, i)) {
5479 // Yep, they're swizzling metaclass NSObject.
5480 classNSObject()->isa->setHasCustomRR();
5489 /***********************************************************************
5491 * fixme assert realized to get superclass remapping?
5492 **********************************************************************/
5494 _class_getSuperclass(Class cls)
5496 return (Class)getSuperclass(newcls(cls));
5500 getSuperclass(class_t *cls)
5502 if (!cls) return NULL;
5503 return cls->superclass;
5507 /***********************************************************************
5508 * class_getIvarLayout
5509 * Called by the garbage collector.
5510 * The class must be NULL or already realized.
5512 **********************************************************************/
5514 class_getIvarLayout(Class cls_gen)
5516 class_t *cls = newcls(cls_gen);
5517 if (cls) return cls->data()->ro->ivarLayout;
5522 /***********************************************************************
5523 * class_getWeakIvarLayout
5524 * Called by the garbage collector.
5525 * The class must be NULL or already realized.
5527 **********************************************************************/
5529 class_getWeakIvarLayout(Class cls_gen)
5531 class_t *cls = newcls(cls_gen);
5532 if (cls) return cls->data()->ro->weakIvarLayout;
5537 /***********************************************************************
5538 * class_setIvarLayout
5539 * Changes the class's GC scan layout.
5540 * NULL layout means no unscanned ivars
5541 * The class must be under construction.
5542 * fixme: sanity-check layout vs instance size?
5543 * fixme: sanity-check layout vs superclass?
5544 * Locking: acquires runtimeLock
5545 **********************************************************************/
5547 class_setIvarLayout(Class cls_gen, const uint8_t *layout)
5549 class_t *cls = newcls(cls_gen);
5552 rwlock_write(&runtimeLock);
5554 // Can only change layout of in-construction classes.
5555 // note: if modifications to post-construction classes were
5556 // allowed, there would be a race below (us vs. concurrent GC scan)
5557 if (!(cls->data()->flags & RW_CONSTRUCTING)) {
5558 _objc_inform("*** Can't set ivar layout for already-registered "
5559 "class '%s'", getName(cls));
5560 rwlock_unlock_write(&runtimeLock);
5564 class_ro_t *ro_w = make_ro_writeable(cls->data());
5566 try_free(ro_w->ivarLayout);
5567 ro_w->ivarLayout = _ustrdup_internal(layout);
5569 rwlock_unlock_write(&runtimeLock);
5572 // SPI: Instance-specific object layout.
5575 _class_setIvarLayoutAccessor(Class cls_gen, const uint8_t* (*accessor) (id object)) {
5576 class_t *cls = newcls(cls_gen);
5579 rwlock_write(&runtimeLock);
5581 class_ro_t *ro_w = make_ro_writeable(cls->data());
5583 // FIXME: this really isn't safe to free if there are instances of this class already.
5584 if (!(cls->data()->flags & RW_HAS_INSTANCE_SPECIFIC_LAYOUT)) try_free(ro_w->ivarLayout);
5585 ro_w->ivarLayout = (uint8_t *)accessor;
5586 changeInfo(cls, RW_HAS_INSTANCE_SPECIFIC_LAYOUT, 0);
5588 rwlock_unlock_write(&runtimeLock);
5592 _object_getIvarLayout(Class cls_gen, id object) {
5593 class_t *cls = newcls(cls_gen);
5595 const uint8_t* layout = cls->data()->ro->ivarLayout;
5596 if (cls->data()->flags & RW_HAS_INSTANCE_SPECIFIC_LAYOUT) {
5597 const uint8_t* (*accessor) (id object) = (const uint8_t* (*)(id))layout;
5598 layout = accessor(object);
5605 /***********************************************************************
5606 * class_setWeakIvarLayout
5607 * Changes the class's GC weak layout.
5608 * NULL layout means no weak ivars
5609 * The class must be under construction.
5610 * fixme: sanity-check layout vs instance size?
5611 * fixme: sanity-check layout vs superclass?
5612 * Locking: acquires runtimeLock
5613 **********************************************************************/
5615 class_setWeakIvarLayout(Class cls_gen, const uint8_t *layout)
5617 class_t *cls = newcls(cls_gen);
5620 rwlock_write(&runtimeLock);
5622 // Can only change layout of in-construction classes.
5623 // note: if modifications to post-construction classes were
5624 // allowed, there would be a race below (us vs. concurrent GC scan)
5625 if (!(cls->data()->flags & RW_CONSTRUCTING)) {
5626 _objc_inform("*** Can't set weak ivar layout for already-registered "
5627 "class '%s'", getName(cls));
5628 rwlock_unlock_write(&runtimeLock);
5632 class_ro_t *ro_w = make_ro_writeable(cls->data());
5634 try_free(ro_w->weakIvarLayout);
5635 ro_w->weakIvarLayout = _ustrdup_internal(layout);
5637 rwlock_unlock_write(&runtimeLock);
5641 /***********************************************************************
5642 * _class_getVariable
5644 * Locking: read-locks runtimeLock
5645 **********************************************************************/
5647 _class_getVariable(Class cls, const char *name, Class *memberOf)
5649 rwlock_read(&runtimeLock);
5651 for ( ; cls != Nil; cls = class_getSuperclass(cls)) {
5652 ivar_t *ivar = getIvar(newcls(cls), name);
5654 rwlock_unlock_read(&runtimeLock);
5655 if (memberOf) *memberOf = cls;
5660 rwlock_unlock_read(&runtimeLock);
5666 /***********************************************************************
5667 * class_conformsToProtocol
5669 * Locking: read-locks runtimeLock
5670 **********************************************************************/
5671 BOOL class_conformsToProtocol(Class cls_gen, Protocol *proto_gen)
5673 class_t *cls = newcls(cls_gen);
5674 protocol_t *proto = newprotocol(proto_gen);
5675 const protocol_list_t **plist;
5679 if (!cls_gen) return NO;
5680 if (!proto_gen) return NO;
5682 rwlock_read(&runtimeLock);
5684 assert(isRealized(cls));
5686 for (plist = cls->data()->protocols; plist && *plist; plist++) {
5687 for (i = 0; i < (*plist)->count; i++) {
5688 protocol_t *p = remapProtocol((*plist)->list[i]);
5689 if (p == proto || _protocol_conformsToProtocol_nolock(p, proto)) {
5697 rwlock_unlock_read(&runtimeLock);
5703 /***********************************************************************
5706 * Locking: runtimeLock must be held by the caller
5707 **********************************************************************/
5709 addMethod(class_t *cls, SEL name, IMP imp, const char *types, BOOL replace)
5713 rwlock_assert_writing(&runtimeLock);
5716 assert(isRealized(cls));
5719 if ((m = getMethodNoSuper_nolock(cls, name))) {
5722 result = _method_getImplementation(m);
5724 result = _method_setImplementation(cls, m, imp);
5728 method_list_t *newlist;
5729 newlist = (method_list_t *)_calloc_internal(sizeof(*newlist), 1);
5730 newlist->entsize_NEVER_USE = (uint32_t)sizeof(method_t) | fixed_up_method_list;
5732 newlist->first.name = name;
5733 newlist->first.types = strdup(types);
5734 if (!ignoreSelector(name)) {
5735 newlist->first.imp = imp;
5737 newlist->first.imp = (IMP)&_objc_ignored_method;
5740 BOOL vtablesAffected = NO;
5741 attachMethodLists(cls, &newlist, 1, NO, NO, &vtablesAffected);
5743 if (vtablesAffected) flushVtables(cls);
5753 class_addMethod(Class cls, SEL name, IMP imp, const char *types)
5755 if (!cls) return NO;
5757 rwlock_write(&runtimeLock);
5758 IMP old = addMethod(newcls(cls), name, imp, types ?: "", NO);
5759 rwlock_unlock_write(&runtimeLock);
5760 return old ? NO : YES;
5765 class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
5767 if (!cls) return NULL;
5769 rwlock_write(&runtimeLock);
5770 IMP old = addMethod(newcls(cls), name, imp, types ?: "", YES);
5771 rwlock_unlock_write(&runtimeLock);
5776 /***********************************************************************
5778 * Adds an ivar to a class.
5779 * Locking: acquires runtimeLock
5780 **********************************************************************/
5782 class_addIvar(Class cls_gen, const char *name, size_t size,
5783 uint8_t alignment, const char *type)
5785 class_t *cls = newcls(cls_gen);
5787 if (!cls) return NO;
5789 if (!type) type = "";
5790 if (name && 0 == strcmp(name, "")) name = NULL;
5792 rwlock_write(&runtimeLock);
5794 assert(isRealized(cls));
5796 // No class variables
5797 if (isMetaClass(cls)) {
5798 rwlock_unlock_write(&runtimeLock);
5802 // Can only add ivars to in-construction classes.
5803 if (!(cls->data()->flags & RW_CONSTRUCTING)) {
5804 rwlock_unlock_write(&runtimeLock);
5808 // Check for existing ivar with this name, unless it's anonymous.
5809 // Check for too-big ivar.
5810 // fixme check for superclass ivar too?
5811 if ((name && getIvar(cls, name)) || size > UINT32_MAX) {
5812 rwlock_unlock_write(&runtimeLock);
5816 class_ro_t *ro_w = make_ro_writeable(cls->data());
5818 // fixme allocate less memory here
5820 ivar_list_t *oldlist, *newlist;
5821 if ((oldlist = (ivar_list_t *)cls->data()->ro->ivars)) {
5822 size_t oldsize = ivar_list_size(oldlist);
5823 newlist = (ivar_list_t *)
5824 _calloc_internal(oldsize + oldlist->entsize, 1);
5825 memcpy(newlist, oldlist, oldsize);
5826 _free_internal(oldlist);
5828 newlist = (ivar_list_t *)
5829 _calloc_internal(sizeof(ivar_list_t), 1);
5830 newlist->entsize = (uint32_t)sizeof(ivar_t);
5833 uint32_t offset = unalignedInstanceSize(cls);
5834 uint32_t alignMask = (1<<alignment)-1;
5835 offset = (offset + alignMask) & ~alignMask;
5837 ivar_t *ivar = ivar_list_nth(newlist, newlist->count++);
5838 ivar->offset = (uintptr_t *)_malloc_internal(sizeof(*ivar->offset));
5839 *ivar->offset = offset;
5840 ivar->name = name ? _strdup_internal(name) : NULL;
5841 ivar->type = _strdup_internal(type);
5842 ivar->alignment = alignment;
5843 ivar->size = (uint32_t)size;
5845 ro_w->ivars = newlist;
5846 ro_w->instanceSize = (uint32_t)(offset + size);
5848 // Ivar layout updated in registerClass.
5850 rwlock_unlock_write(&runtimeLock);
5856 /***********************************************************************
5858 * Adds a protocol to a class.
5859 * Locking: acquires runtimeLock
5860 **********************************************************************/
5861 BOOL class_addProtocol(Class cls_gen, Protocol *protocol_gen)
5863 class_t *cls = newcls(cls_gen);
5864 protocol_t *protocol = newprotocol(protocol_gen);
5865 protocol_list_t *plist;
5866 const protocol_list_t **plistp;
5868 if (!cls) return NO;
5869 if (class_conformsToProtocol(cls_gen, protocol_gen)) return NO;
5871 rwlock_write(&runtimeLock);
5873 assert(isRealized(cls));
5876 plist = (protocol_list_t *)
5877 _malloc_internal(sizeof(protocol_list_t) + sizeof(protocol_t *));
5879 plist->list[0] = (protocol_ref_t)protocol;
5881 unsigned int count = 0;
5882 for (plistp = cls->data()->protocols; plistp && *plistp; plistp++) {
5886 cls->data()->protocols = (const protocol_list_t **)
5887 _realloc_internal(cls->data()->protocols,
5888 (count+2) * sizeof(protocol_list_t *));
5889 cls->data()->protocols[count] = plist;
5890 cls->data()->protocols[count+1] = NULL;
5894 rwlock_unlock_write(&runtimeLock);
5900 /***********************************************************************
5902 * Adds a property to a class.
5903 * Locking: acquires runtimeLock
5904 **********************************************************************/
5906 _class_addProperty(Class cls_gen, const char *name,
5907 const objc_property_attribute_t *attrs, unsigned int count,
5910 class_t *cls = newcls(cls_gen);
5911 chained_property_list *plist;
5913 if (!cls) return NO;
5914 if (!name) return NO;
5916 property_t *prop = class_getProperty(cls_gen, name);
5917 if (prop && !replace) {
5918 // already exists, refuse to replace
5923 rwlock_write(&runtimeLock);
5924 try_free(prop->attributes);
5925 prop->attributes = copyPropertyAttributeString(attrs, count);
5926 rwlock_unlock_write(&runtimeLock);
5930 rwlock_write(&runtimeLock);
5932 assert(isRealized(cls));
5934 plist = (chained_property_list *)
5935 _malloc_internal(sizeof(*plist) + sizeof(plist->list[0]));
5937 plist->list[0].name = _strdup_internal(name);
5938 plist->list[0].attributes = copyPropertyAttributeString(attrs, count);
5940 plist->next = cls->data()->properties;
5941 cls->data()->properties = plist;
5943 rwlock_unlock_write(&runtimeLock);
5950 class_addProperty(Class cls_gen, const char *name,
5951 const objc_property_attribute_t *attrs, unsigned int n)
5953 return _class_addProperty(cls_gen, name, attrs, n, NO);
5957 class_replaceProperty(Class cls_gen, const char *name,
5958 const objc_property_attribute_t *attrs, unsigned int n)
5960 _class_addProperty(cls_gen, name, attrs, n, YES);
5964 /***********************************************************************
5966 * Look up a class by name, and realize it.
5967 * Locking: acquires runtimeLock
5968 **********************************************************************/
5970 look_up_class(const char *name,
5971 BOOL includeUnconnected __attribute__((unused)),
5972 BOOL includeClassHandler __attribute__((unused)))
5974 if (!name) return nil;
5976 rwlock_read(&runtimeLock);
5977 class_t *result = getClass(name);
5978 BOOL unrealized = result && !isRealized(result);
5979 rwlock_unlock_read(&runtimeLock);
5981 rwlock_write(&runtimeLock);
5982 realizeClass(result);
5983 rwlock_unlock_write(&runtimeLock);
5989 /***********************************************************************
5990 * objc_duplicateClass
5992 * Locking: acquires runtimeLock
5993 **********************************************************************/
5995 objc_duplicateClass(Class original_gen, const char *name,
5998 class_t *original = newcls(original_gen);
6001 rwlock_write(&runtimeLock);
6003 assert(isRealized(original));
6004 assert(!isMetaClass(original));
6006 duplicate = (class_t *)
6007 _calloc_class(alignedInstanceSize(original->isa) + extraBytes);
6008 if (unalignedInstanceSize(original->isa) < sizeof(class_t)) {
6009 _objc_inform("busted! %s\n", original->data()->ro->name);
6013 duplicate->isa = original->isa;
6014 duplicate->superclass = original->superclass;
6015 duplicate->cache = (Cache)&_objc_empty_cache;
6016 duplicate->vtable = &_objc_empty_vtable;
6018 duplicate->setData((class_rw_t *)_calloc_internal(sizeof(*original->data()), 1));
6019 duplicate->data()->flags = (original->data()->flags | RW_COPIED_RO) & ~RW_SPECIALIZED_VTABLE;
6020 duplicate->data()->version = original->data()->version;
6021 duplicate->data()->firstSubclass = NULL;
6022 duplicate->data()->nextSiblingClass = NULL;
6024 duplicate->data()->ro = (class_ro_t *)
6025 _memdup_internal(original->data()->ro, sizeof(*original->data()->ro));
6026 *(char **)&duplicate->data()->ro->name = _strdup_internal(name);
6028 if (original->data()->flags & RW_METHOD_ARRAY) {
6029 duplicate->data()->method_lists = (method_list_t **)
6030 _memdup_internal(original->data()->method_lists,
6031 malloc_size(original->data()->method_lists));
6032 method_list_t **mlistp;
6033 for (mlistp = duplicate->data()->method_lists; *mlistp; mlistp++) {
6034 *mlistp = (method_list_t *)
6035 _memdup_internal(*mlistp, method_list_size(*mlistp));
6038 if (original->data()->method_list) {
6039 duplicate->data()->method_list = (method_list_t *)
6040 _memdup_internal(original->data()->method_list,
6041 method_list_size(original->data()->method_list));
6045 // fixme dies when categories are added to the base
6046 duplicate->data()->properties = original->data()->properties;
6047 duplicate->data()->protocols = original->data()->protocols;
6049 if (duplicate->superclass) {
6050 addSubclass(duplicate->superclass, duplicate);
6053 // Don't methodize class - construction above is correct
6055 addNamedClass(duplicate, duplicate->data()->ro->name);
6056 addRealizedClass(duplicate);
6057 // no: duplicate->isa == original->isa
6058 // addRealizedMetaclass(duplicate->isa);
6060 if (PrintConnecting) {
6061 _objc_inform("CLASS: realizing class '%s' (duplicate of %s) %p %p",
6062 name, original->data()->ro->name,
6063 duplicate, duplicate->data()->ro);
6066 rwlock_unlock_write(&runtimeLock);
6068 return (Class)duplicate;
6071 /***********************************************************************
6072 * objc_initializeClassPair
6073 * Locking: runtimeLock must be write-locked by the caller
6074 **********************************************************************/
6076 // &UnsetLayout is the default ivar layout during class construction
6077 static const uint8_t UnsetLayout = 0;
6079 static void objc_initializeClassPair_internal(Class superclass_gen, const char *name, Class cls_gen, Class meta_gen)
6081 rwlock_assert_writing(&runtimeLock);
6083 class_t *superclass = newcls(superclass_gen);
6084 class_t *cls = newcls(cls_gen);
6085 class_t *meta = newcls(meta_gen);
6086 class_ro_t *cls_ro_w, *meta_ro_w;
6088 cls->setData((class_rw_t *)_calloc_internal(sizeof(class_rw_t), 1));
6089 meta->setData((class_rw_t *)_calloc_internal(sizeof(class_rw_t), 1));
6090 cls_ro_w = (class_ro_t *)_calloc_internal(sizeof(class_ro_t), 1);
6091 meta_ro_w = (class_ro_t *)_calloc_internal(sizeof(class_ro_t), 1);
6092 cls->data()->ro = cls_ro_w;
6093 meta->data()->ro = meta_ro_w;
6096 cls->cache = (Cache)&_objc_empty_cache;
6097 meta->cache = (Cache)&_objc_empty_cache;
6098 cls->vtable = &_objc_empty_vtable;
6099 meta->vtable = &_objc_empty_vtable;
6101 cls->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED;
6102 meta->data()->flags = RW_CONSTRUCTING | RW_COPIED_RO | RW_REALIZED;
6103 cls->data()->version = 0;
6104 meta->data()->version = 7;
6106 cls_ro_w->flags = 0;
6107 meta_ro_w->flags = RO_META;
6109 cls_ro_w->flags |= RO_ROOT;
6110 meta_ro_w->flags |= RO_ROOT;
6113 cls_ro_w->instanceStart = unalignedInstanceSize(superclass);
6114 meta_ro_w->instanceStart = unalignedInstanceSize(superclass->isa);
6115 cls_ro_w->instanceSize = cls_ro_w->instanceStart;
6116 meta_ro_w->instanceSize = meta_ro_w->instanceStart;
6118 cls_ro_w->instanceStart = 0;
6119 meta_ro_w->instanceStart = (uint32_t)sizeof(class_t);
6120 cls_ro_w->instanceSize = (uint32_t)sizeof(id); // just an isa
6121 meta_ro_w->instanceSize = meta_ro_w->instanceStart;
6124 cls_ro_w->name = _strdup_internal(name);
6125 meta_ro_w->name = _strdup_internal(name);
6127 cls_ro_w->ivarLayout = &UnsetLayout;
6128 cls_ro_w->weakIvarLayout = &UnsetLayout;
6130 // Connect to superclasses and metaclasses
6133 meta->isa = superclass->isa->isa;
6134 cls->superclass = superclass;
6135 meta->superclass = superclass->isa;
6136 addSubclass(superclass, cls);
6137 addSubclass(superclass->isa, meta);
6140 cls->superclass = Nil;
6141 meta->superclass = cls;
6142 addSubclass(cls, meta);
6146 /***********************************************************************
6147 * objc_initializeClassPair
6148 **********************************************************************/
6149 Class objc_initializeClassPair(Class superclass_gen, const char *name, Class cls_gen, Class meta_gen)
6151 class_t *superclass = newcls(superclass_gen);
6153 rwlock_write(&runtimeLock);
6156 // Common superclass integrity checks with objc_allocateClassPair
6158 if (getClass(name)) {
6159 rwlock_unlock_write(&runtimeLock);
6162 // fixme reserve class against simultaneous allocation
6164 if (superclass) assert(isRealized(superclass));
6166 if (superclass && superclass->data()->flags & RW_CONSTRUCTING) {
6167 // Can't make subclass of an in-construction class
6168 rwlock_unlock_write(&runtimeLock);
6173 // just initialize what was supplied
6174 objc_initializeClassPair_internal(superclass_gen, name, cls_gen, meta_gen);
6176 rwlock_unlock_write(&runtimeLock);
6180 /***********************************************************************
6181 * objc_allocateClassPair
6183 * Locking: acquires runtimeLock
6184 **********************************************************************/
6185 Class objc_allocateClassPair(Class superclass_gen, const char *name,
6188 class_t *superclass = newcls(superclass_gen);
6191 rwlock_write(&runtimeLock);
6194 // Common superclass integrity checks with objc_initializeClassPair
6196 if (getClass(name)) {
6197 rwlock_unlock_write(&runtimeLock);
6200 // fixme reserve class against simmultaneous allocation
6202 if (superclass) assert(isRealized(superclass));
6204 if (superclass && superclass->data()->flags & RW_CONSTRUCTING) {
6205 // Can't make subclass of an in-construction class
6206 rwlock_unlock_write(&runtimeLock);
6212 // Allocate new classes.
6213 size_t size = sizeof(class_t);
6214 size_t metasize = sizeof(class_t);
6216 size = alignedInstanceSize(superclass->isa);
6217 metasize = alignedInstanceSize(superclass->isa->isa);
6219 cls = _calloc_class(size + extraBytes);
6220 meta = _calloc_class(metasize + extraBytes);
6222 objc_initializeClassPair_internal(superclass_gen, name, cls, meta);
6224 rwlock_unlock_write(&runtimeLock);
6230 /***********************************************************************
6231 * objc_registerClassPair
6233 * Locking: acquires runtimeLock
6234 **********************************************************************/
6235 void objc_registerClassPair(Class cls_gen)
6237 class_t *cls = newcls(cls_gen);
6239 rwlock_write(&runtimeLock);
6241 if ((cls->data()->flags & RW_CONSTRUCTED) ||
6242 (cls->isa->data()->flags & RW_CONSTRUCTED))
6244 _objc_inform("objc_registerClassPair: class '%s' was already "
6245 "registered!", cls->data()->ro->name);
6246 rwlock_unlock_write(&runtimeLock);
6250 if (!(cls->data()->flags & RW_CONSTRUCTING) ||
6251 !(cls->isa->data()->flags & RW_CONSTRUCTING))
6253 _objc_inform("objc_registerClassPair: class '%s' was not "
6254 "allocated with objc_allocateClassPair!",
6255 cls->data()->ro->name);
6256 rwlock_unlock_write(&runtimeLock);
6260 // Build ivar layouts
6262 class_t *supercls = getSuperclass(cls);
6263 class_ro_t *ro_w = (class_ro_t *)cls->data()->ro;
6265 if (ro_w->ivarLayout != &UnsetLayout) {
6266 // Class builder already called class_setIvarLayout.
6268 else if (!supercls) {
6269 // Root class. Scan conservatively (should be isa ivar only).
6270 ro_w->ivarLayout = NULL;
6272 else if (ro_w->ivars == NULL) {
6273 // No local ivars. Use superclass's layouts.
6275 _ustrdup_internal(supercls->data()->ro->ivarLayout);
6278 // Has local ivars. Build layouts based on superclass.
6279 layout_bitmap bitmap =
6280 layout_bitmap_create(supercls->data()->ro->ivarLayout,
6281 unalignedInstanceSize(supercls),
6282 unalignedInstanceSize(cls), NO);
6284 for (i = 0; i < ro_w->ivars->count; i++) {
6285 ivar_t *ivar = ivar_list_nth(ro_w->ivars, i);
6286 if (!ivar->offset) continue; // anonymous bitfield
6288 layout_bitmap_set_ivar(bitmap, ivar->type, *ivar->offset);
6290 ro_w->ivarLayout = layout_string_create(bitmap);
6291 layout_bitmap_free(bitmap);
6294 if (ro_w->weakIvarLayout != &UnsetLayout) {
6295 // Class builder already called class_setWeakIvarLayout.
6297 else if (!supercls) {
6298 // Root class. No weak ivars (should be isa ivar only).
6299 ro_w->weakIvarLayout = NULL;
6301 else if (ro_w->ivars == NULL) {
6302 // No local ivars. Use superclass's layout.
6303 ro_w->weakIvarLayout =
6304 _ustrdup_internal(supercls->data()->ro->weakIvarLayout);
6307 // Has local ivars. Build layout based on superclass.
6308 // No way to add weak ivars yet.
6309 ro_w->weakIvarLayout =
6310 _ustrdup_internal(supercls->data()->ro->weakIvarLayout);
6314 // Clear "under construction" bit, set "done constructing" bit
6315 cls->data()->flags &= ~RW_CONSTRUCTING;
6316 cls->isa->data()->flags &= ~RW_CONSTRUCTING;
6317 cls->data()->flags |= RW_CONSTRUCTED;
6318 cls->isa->data()->flags |= RW_CONSTRUCTED;
6320 // Add to named and realized classes
6321 addNamedClass(cls, cls->data()->ro->name);
6322 addRealizedClass(cls);
6323 addRealizedMetaclass(cls->isa);
6324 addNonMetaClass(cls);
6326 rwlock_unlock_write(&runtimeLock);
6330 /***********************************************************************
6332 * Disconnect a class from other data structures.
6333 * Exception: does not remove the class from the +load list
6334 * Call this before free_class.
6335 * Locking: runtimeLock must be held by the caller.
6336 **********************************************************************/
6337 static void detach_class(class_t *cls, BOOL isMeta)
6339 rwlock_assert_writing(&runtimeLock);
6341 // categories not yet attached to this class
6342 category_list *cats;
6343 cats = unattachedCategoriesForClass(cls);
6344 if (cats) free(cats);
6346 // superclass's subclass list
6347 if (isRealized(cls)) {
6348 class_t *supercls = getSuperclass(cls);
6350 removeSubclass(supercls, cls);
6354 // class tables and +load queue
6356 removeNamedClass(cls, getName(cls));
6357 removeRealizedClass(cls);
6358 removeNonMetaClass(cls);
6360 removeRealizedMetaclass(cls);
6365 /***********************************************************************
6367 * Frees a class's data structures.
6368 * Call this after detach_class.
6369 * Locking: runtimeLock must be held by the caller
6370 **********************************************************************/
6371 static void free_class(class_t *cls)
6373 rwlock_assert_writing(&runtimeLock);
6375 if (! isRealized(cls)) return;
6379 // Dereferences the cache contents; do this before freeing methods
6380 if (cls->cache != (Cache)&_objc_empty_cache) _cache_free(cls->cache);
6382 FOREACH_METHOD_LIST(mlist, cls, {
6383 for (i = 0; i < mlist->count; i++) {
6384 method_t *m = method_list_nth(mlist, i);
6389 if (cls->data()->flags & RW_METHOD_ARRAY) {
6390 try_free(cls->data()->method_lists);
6393 const ivar_list_t *ilist = cls->data()->ro->ivars;
6395 for (i = 0; i < ilist->count; i++) {
6396 const ivar_t *ivar = ivar_list_nth(ilist, i);
6397 try_free(ivar->offset);
6398 try_free(ivar->name);
6399 try_free(ivar->type);
6404 const protocol_list_t **plistp;
6405 for (plistp = cls->data()->protocols; plistp && *plistp; plistp++) {
6408 try_free(cls->data()->protocols);
6410 const chained_property_list *proplist = cls->data()->properties;
6412 for (i = 0; i < proplist->count; i++) {
6413 const property_t *prop = proplist->list+i;
6414 try_free(prop->name);
6415 try_free(prop->attributes);
6418 const chained_property_list *temp = proplist;
6419 proplist = proplist->next;
6424 if (cls->vtable != &_objc_empty_vtable &&
6425 cls->data()->flags & RW_SPECIALIZED_VTABLE) try_free(cls->vtable);
6426 try_free(cls->data()->ro->ivarLayout);
6427 try_free(cls->data()->ro->weakIvarLayout);
6428 try_free(cls->data()->ro->name);
6429 try_free(cls->data()->ro);
6430 try_free(cls->data());
6435 void objc_disposeClassPair(Class cls_gen)
6437 class_t *cls = newcls(cls_gen);
6439 rwlock_write(&runtimeLock);
6441 if (!(cls->data()->flags & (RW_CONSTRUCTED|RW_CONSTRUCTING)) ||
6442 !(cls->isa->data()->flags & (RW_CONSTRUCTED|RW_CONSTRUCTING)))
6444 // class not allocated with objc_allocateClassPair
6445 // disposing still-unregistered class is OK!
6446 _objc_inform("objc_disposeClassPair: class '%s' was not "
6447 "allocated with objc_allocateClassPair!",
6448 cls->data()->ro->name);
6449 rwlock_unlock_write(&runtimeLock);
6453 if (isMetaClass(cls)) {
6454 _objc_inform("objc_disposeClassPair: class '%s' is a metaclass, "
6455 "not a class!", cls->data()->ro->name);
6456 rwlock_unlock_write(&runtimeLock);
6460 // Shouldn't have any live subclasses.
6461 if (cls->data()->firstSubclass) {
6462 _objc_inform("objc_disposeClassPair: class '%s' still has subclasses, "
6463 "including '%s'!", cls->data()->ro->name,
6464 getName(cls->data()->firstSubclass));
6466 if (cls->isa->data()->firstSubclass) {
6467 _objc_inform("objc_disposeClassPair: class '%s' still has subclasses, "
6468 "including '%s'!", cls->data()->ro->name,
6469 getName(cls->isa->data()->firstSubclass));
6472 // don't remove_class_from_loadable_list()
6473 // - it's not there and we don't have the lock
6474 detach_class(cls->isa, YES);
6475 detach_class(cls, NO);
6476 free_class(cls->isa);
6479 rwlock_unlock_write(&runtimeLock);
6483 /***********************************************************************
6484 * class_createInstance
6487 **********************************************************************/
6489 _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone)
6490 __attribute__((always_inline));
6493 _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone)
6495 if (!cls) return nil;
6497 assert(isRealized(newcls(cls)));
6499 size_t size = alignedInstanceSize(newcls(cls)) + extraBytes;
6501 // CF requires all object be at least 16 bytes.
6502 if (size < 16) size = 16;
6507 obj = (id)auto_zone_allocate_object(gc_zone, size,
6508 AUTO_OBJECT_SCANNED, 0, 1);
6512 obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
6514 obj = (id)calloc(1, size);
6516 if (!obj) return nil;
6518 obj->isa = cls; // need not be object_setClass
6520 if (_class_hasCxxStructors(cls)) {
6521 obj = _objc_constructOrFree(cls, obj);
6529 class_createInstance(Class cls, size_t extraBytes)
6531 return _class_createInstanceFromZone(cls, extraBytes, NULL);
6534 /***********************************************************************
6535 * class_createInstances
6538 **********************************************************************/
6540 class_createInstances(Class cls, size_t extraBytes,
6541 id *results, unsigned num_requested)
6543 return _class_createInstancesFromZone(cls, extraBytes, NULL,
6544 results, num_requested);
6547 static BOOL classOrSuperClassesUseARR(Class cls) {
6549 if (_class_usesAutomaticRetainRelease(cls)) return true;
6550 cls = class_getSuperclass(cls);
6555 static void arr_fixup_copied_references(id newObject, id oldObject)
6557 // use ARR layouts to correctly copy the references from old object to new, both strong and weak.
6558 Class cls = oldObject->isa;
6560 if (_class_usesAutomaticRetainRelease(cls)) {
6561 // FIXME: align the instance start to nearest id boundary. This currently handles the case where
6562 // the the compiler folds a leading BOOL (char, short, etc.) into the alignment slop of a superclass.
6563 size_t instanceStart = _class_getInstanceStart(cls);
6564 const uint8_t *strongLayout = class_getIvarLayout(cls);
6566 id *newPtr = (id *)((char*)newObject + instanceStart);
6568 while ((byte = *strongLayout++)) {
6569 unsigned skips = (byte >> 4);
6570 unsigned scans = (byte & 0x0F);
6573 // ensure strong references are properly retained.
6574 id value = *newPtr++;
6575 if (value) objc_retain(value);
6579 const uint8_t *weakLayout = class_getWeakIvarLayout(cls);
6580 // fix up weak references if any.
6582 id *newPtr = (id *)((char*)newObject + instanceStart), *oldPtr = (id *)((char*)oldObject + instanceStart);
6584 while ((byte = *weakLayout++)) {
6585 unsigned skips = (byte >> 4);
6586 unsigned weaks = (byte & 0x0F);
6587 newPtr += skips, oldPtr += skips;
6590 objc_storeWeak(newPtr, objc_loadWeak(oldPtr));
6596 cls = class_getSuperclass(cls);
6600 /***********************************************************************
6601 * object_copyFromZone
6604 **********************************************************************/
6606 _object_copyFromZone(id oldObj, size_t extraBytes, void *zone)
6611 if (!oldObj) return nil;
6612 if (OBJC_IS_TAGGED_PTR(oldObj)) return oldObj;
6614 size = _class_getInstanceSize(oldObj->isa) + extraBytes;
6617 obj = (id) auto_zone_allocate_object(gc_zone, size,
6618 AUTO_OBJECT_SCANNED, 0, 1);
6622 obj = (id) malloc_zone_calloc((malloc_zone_t *)zone, size, 1);
6624 obj = (id) calloc(1, size);
6626 if (!obj) return nil;
6628 // fixme this doesn't handle C++ ivars correctly (#4619414)
6629 objc_memmove_collectable(obj, oldObj, size);
6633 gc_fixup_weakreferences(obj, oldObj);
6634 else if (classOrSuperClassesUseARR(obj->isa))
6635 arr_fixup_copied_references(obj, oldObj);
6637 if (classOrSuperClassesUseARR(obj->isa))
6638 arr_fixup_copied_references(obj, oldObj);
6645 /***********************************************************************
6649 **********************************************************************/
6651 object_copy(id oldObj, size_t extraBytes)
6653 return _object_copyFromZone(oldObj, extraBytes, malloc_default_zone());
6657 #if !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)
6659 /***********************************************************************
6660 * class_createInstanceFromZone
6663 **********************************************************************/
6665 class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone)
6667 return _class_createInstanceFromZone(cls, extraBytes, zone);
6670 /***********************************************************************
6671 * object_copyFromZone
6674 **********************************************************************/
6676 object_copyFromZone(id oldObj, size_t extraBytes, void *zone)
6678 return _object_copyFromZone(oldObj, extraBytes, zone);
6684 /***********************************************************************
6685 * objc_destructInstance
6686 * Destroys an instance without freeing memory.
6687 * Calls C++ destructors.
6688 * Calls ARR ivar cleanup.
6689 * Removes associative references.
6690 * Returns `obj`. Does nothing if `obj` is nil.
6691 * Be warned that GC DOES NOT CALL THIS. If you edit this, also edit finalize.
6692 * CoreFoundation and other clients do call this under GC.
6693 **********************************************************************/
6694 void *objc_destructInstance(id obj)
6697 Class isa_gen = _object_getClass(obj);
6698 class_t *isa = newcls(isa_gen);
6700 // Read all of the flags at once for performance.
6701 bool cxx = hasCxxStructors(isa);
6702 bool assoc = !UseGC && _class_instancesHaveAssociatedObjects(isa_gen);
6704 // This order is important.
6705 if (cxx) object_cxxDestruct(obj);
6706 if (assoc) _object_remove_assocations(obj);
6708 if (!UseGC) objc_clear_deallocating(obj);
6715 /***********************************************************************
6719 **********************************************************************/
6721 object_dispose(id obj)
6723 if (!obj) return nil;
6725 objc_destructInstance(obj);
6729 auto_zone_retain(gc_zone, obj); // gc free expects rc==1
6739 /***********************************************************************
6740 * _objc_getFreedObjectClass
6743 **********************************************************************/
6744 Class _objc_getFreedObjectClass (void)
6751 OBJC_EXTERN id objc_msgSend_fixedup(id, SEL, ...);
6752 OBJC_EXTERN id objc_msgSendSuper2_fixedup(id, SEL, ...);
6753 OBJC_EXTERN id objc_msgSend_stret_fixedup(id, SEL, ...);
6754 OBJC_EXTERN id objc_msgSendSuper2_stret_fixedup(id, SEL, ...);
6755 #if defined(__i386__) || defined(__x86_64__)
6756 OBJC_EXTERN id objc_msgSend_fpret_fixedup(id, SEL, ...);
6758 #if defined(__x86_64__)
6759 OBJC_EXTERN id objc_msgSend_fp2ret_fixedup(id, SEL, ...);
6762 /***********************************************************************
6763 * _objc_fixupMessageRef
6764 * Fixes up message ref *msg.
6765 * obj is the receiver. supr is NULL for non-super messages
6766 * Locking: acquires runtimeLock
6767 **********************************************************************/
6769 _objc_fixupMessageRef(id obj, struct objc_super2 *supr, message_ref_t *msg)
6777 rwlock_assert_unlocked(&runtimeLock);
6780 // normal message - search obj->isa for the method implementation
6781 isa = (class_t *) _object_getClass(obj);
6783 if (!isRealized(isa)) {
6784 // obj is a class object, isa is its metaclass
6786 rwlock_write(&runtimeLock);
6787 cls = realizeClass((class_t *)obj);
6788 rwlock_unlock_write(&runtimeLock);
6790 // shouldn't have instances of unrealized classes!
6791 assert(isMetaClass(isa));
6792 // shouldn't be relocating classes here!
6793 assert(cls == (class_t *)obj);
6797 // this is objc_msgSend_super, and supr->current_class->superclass
6798 // is the class to search for the method implementation
6799 assert(isRealized((class_t *)supr->current_class));
6800 isa = getSuperclass((class_t *)supr->current_class);
6803 msg->sel = sel_registerName((const char *)msg->sel);
6805 if (ignoreSelector(msg->sel)) {
6806 // ignored selector - bypass dispatcher
6807 msg->imp = (IMP)&vtable_ignored;
6808 imp = (IMP)&_objc_ignored_method;
6811 else if (msg->imp == (IMP)&objc_msgSend_fixup &&
6812 (vtableIndex = vtable_getIndex(msg->sel)) >= 0)
6815 msg->imp = vtableTrampolines[vtableIndex];
6816 imp = isa->vtable[vtableIndex];
6820 // ordinary dispatch
6821 imp = lookUpMethod((Class)isa, msg->sel, YES/*initialize*/, YES/*cache*/, obj);
6823 if (msg->imp == (IMP)&objc_msgSend_fixup) {
6824 msg->imp = (IMP)&objc_msgSend_fixedup;
6826 else if (msg->imp == (IMP)&objc_msgSendSuper2_fixup) {
6827 msg->imp = (IMP)&objc_msgSendSuper2_fixedup;
6829 else if (msg->imp == (IMP)&objc_msgSend_stret_fixup) {
6830 msg->imp = (IMP)&objc_msgSend_stret_fixedup;
6832 else if (msg->imp == (IMP)&objc_msgSendSuper2_stret_fixup) {
6833 msg->imp = (IMP)&objc_msgSendSuper2_stret_fixedup;
6835 #if defined(__i386__) || defined(__x86_64__)
6836 else if (msg->imp == (IMP)&objc_msgSend_fpret_fixup) {
6837 msg->imp = (IMP)&objc_msgSend_fpret_fixedup;
6840 #if defined(__x86_64__)
6841 else if (msg->imp == (IMP)&objc_msgSend_fp2ret_fixup) {
6842 msg->imp = (IMP)&objc_msgSend_fp2ret_fixedup;
6846 // The ref may already have been fixed up, either by another thread
6847 // or by +initialize via lookUpMethod above.
6859 static class_t *setSuperclass(class_t *cls, class_t *newSuper)
6863 rwlock_assert_writing(&runtimeLock);
6865 assert(isRealized(cls));
6866 assert(isRealized(newSuper));
6868 oldSuper = cls->superclass;
6869 removeSubclass(oldSuper, cls);
6870 removeSubclass(oldSuper->isa, cls->isa);
6872 cls->superclass = newSuper;
6873 cls->isa->superclass = newSuper->isa;
6874 addSubclass(newSuper, cls);
6875 addSubclass(newSuper->isa, cls->isa);
6877 flushCaches(cls->isa);
6878 flushVtables(cls->isa);
6886 Class class_setSuperclass(Class cls_gen, Class newSuper_gen)
6888 class_t *cls = newcls(cls_gen);
6889 class_t *newSuper = newcls(newSuper_gen);
6892 rwlock_write(&runtimeLock);
6893 oldSuper = setSuperclass(cls, newSuper);
6894 rwlock_unlock_write(&runtimeLock);
6896 return (Class)oldSuper;