]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-class-old.mm
e07080b43d294c6e320d6ae738df494a29d91d49
[apple/objc4.git] / runtime / objc-class-old.mm
1 /*
2 * Copyright (c) 1999-2009 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /***********************************************************************
25 * objc-class-old.m
26 * Support for old-ABI classes, methods, and categories.
27 **********************************************************************/
28
29 #if !__OBJC2__
30
31 #include "objc-private.h"
32 #include "objc-runtime-old.h"
33 #include "objc-file-old.h"
34 #include "objc-cache-old.h"
35
36 static Method _class_getMethod(Class cls, SEL sel);
37 static Method _class_getMethodNoSuper(Class cls, SEL sel);
38 static Method _class_getMethodNoSuper_nolock(Class cls, SEL sel);
39 static void flush_caches(Class cls, bool flush_meta);
40
41
42 // Freed objects have their isa set to point to this dummy class.
43 // This avoids the need to check for Nil classes in the messenger.
44 static const void* freedObjectClass[12] =
45 {
46 Nil, // isa
47 Nil, // superclass
48 "FREED(id)", // name
49 0, // version
50 0, // info
51 0, // instance_size
52 nil, // ivars
53 nil, // methodLists
54 (Cache) &_objc_empty_cache, // cache
55 nil, // protocols
56 nil, // ivar_layout;
57 nil // ext
58 };
59
60
61 /***********************************************************************
62 * _class_getFreedObjectClass. Return a pointer to the dummy freed
63 * object class. Freed objects get their isa pointers replaced with
64 * a pointer to the freedObjectClass, so that we can catch usages of
65 * the freed object.
66 **********************************************************************/
67 static Class _class_getFreedObjectClass(void)
68 {
69 return (Class)freedObjectClass;
70 }
71
72
73 /***********************************************************************
74 * _objc_getFreedObjectClass. Return a pointer to the dummy freed
75 * object class. Freed objects get their isa pointers replaced with
76 * a pointer to the freedObjectClass, so that we can catch usages of
77 * the freed object.
78 **********************************************************************/
79 Class _objc_getFreedObjectClass(void)
80 {
81 return _class_getFreedObjectClass();
82 }
83
84
85 static void allocateExt(Class cls)
86 {
87 if (! (cls->info & CLS_EXT)) {
88 _objc_inform("class '%s' needs to be recompiled", cls->name);
89 return;
90 }
91 if (!cls->ext) {
92 uint32_t size = (uint32_t)sizeof(old_class_ext);
93 cls->ext = (old_class_ext *)calloc(size, 1);
94 cls->ext->size = size;
95 }
96 }
97
98
99 static inline old_method *_findNamedMethodInList(old_method_list * mlist, const char *meth_name) {
100 int i;
101 if (!mlist) return nil;
102 if (ignoreSelectorNamed(meth_name)) return nil;
103 for (i = 0; i < mlist->method_count; i++) {
104 old_method *m = &mlist->method_list[i];
105 if (0 == strcmp((const char *)(m->method_name), meth_name)) {
106 return m;
107 }
108 }
109 return nil;
110 }
111
112
113 /***********************************************************************
114 * Method list fixup markers.
115 * mlist->obsolete == fixed_up_method_list marks method lists with real SELs
116 * versus method lists with un-uniqued char*.
117 * PREOPTIMIZED VERSION:
118 * Fixed-up method lists get mlist->obsolete == OBJC_FIXED_UP
119 * dyld shared cache sets this for method lists it preoptimizes.
120 * UN-PREOPTIMIZED VERSION
121 * Fixed-up method lists get mlist->obsolete == OBJC_FIXED_UP_outside_dyld
122 * dyld shared cache uses OBJC_FIXED_UP, but those aren't trusted.
123 **********************************************************************/
124 #define OBJC_FIXED_UP ((void *)1771)
125 #define OBJC_FIXED_UP_outside_dyld ((void *)1773)
126 static void *fixed_up_method_list = OBJC_FIXED_UP;
127
128 // sel_init() decided that selectors in the dyld shared cache are untrustworthy
129 void disableSharedCacheOptimizations(void)
130 {
131 fixed_up_method_list = OBJC_FIXED_UP_outside_dyld;
132 }
133
134 /***********************************************************************
135 * fixupSelectorsInMethodList
136 * Uniques selectors in the given method list.
137 * Also replaces imps for GC-ignored selectors
138 * The given method list must be non-nil and not already fixed-up.
139 * If the class was loaded from a bundle:
140 * fixes up the given list in place with heap-allocated selector strings
141 * If the class was not from a bundle:
142 * allocates a copy of the method list, fixes up the copy, and returns
143 * the copy. The given list is unmodified.
144 *
145 * If cls is already in use, methodListLock must be held by the caller.
146 **********************************************************************/
147 static old_method_list *fixupSelectorsInMethodList(Class cls, old_method_list *mlist)
148 {
149 int i;
150 size_t size;
151 old_method *method;
152 old_method_list *old_mlist;
153
154 if ( ! mlist ) return nil;
155 if ( mlist->obsolete == fixed_up_method_list ) {
156 // method list OK
157 } else {
158 bool isBundle = cls->info & CLS_FROM_BUNDLE;
159 if (!isBundle) {
160 old_mlist = mlist;
161 size = sizeof(old_method_list) - sizeof(old_method) + old_mlist->method_count * sizeof(old_method);
162 mlist = (old_method_list *)malloc(size);
163 memmove(mlist, old_mlist, size);
164 } else {
165 // Mach-O bundles are fixed up in place.
166 // This prevents leaks when a bundle is unloaded.
167 }
168 sel_lock();
169 for ( i = 0; i < mlist->method_count; i += 1 ) {
170 method = &mlist->method_list[i];
171 method->method_name =
172 sel_registerNameNoLock((const char *)method->method_name, isBundle); // Always copy selector data from bundles.
173
174 if (ignoreSelector(method->method_name)) {
175 method->method_imp = (IMP)&_objc_ignored_method;
176 }
177 }
178 sel_unlock();
179 mlist->obsolete = fixed_up_method_list;
180 }
181 return mlist;
182 }
183
184
185 /***********************************************************************
186 * nextMethodList
187 * Returns successive method lists from the given class.
188 * Method lists are returned in method search order (i.e. highest-priority
189 * implementations first).
190 * All necessary method list fixups are performed, so the
191 * returned method list is fully-constructed.
192 *
193 * If cls is already in use, methodListLock must be held by the caller.
194 * For full thread-safety, methodListLock must be continuously held by the
195 * caller across all calls to nextMethodList(). If the lock is released,
196 * the bad results listed in class_nextMethodList() may occur.
197 *
198 * void *iterator = nil;
199 * old_method_list *mlist;
200 * mutex_locker_t lock(methodListLock);
201 * while ((mlist = nextMethodList(cls, &iterator))) {
202 * // do something with mlist
203 * }
204 **********************************************************************/
205 static old_method_list *nextMethodList(Class cls,
206 void **it)
207 {
208 uintptr_t index = *(uintptr_t *)it;
209 old_method_list **resultp;
210
211 if (index == 0) {
212 // First call to nextMethodList.
213 if (!cls->methodLists) {
214 resultp = nil;
215 } else if (cls->info & CLS_NO_METHOD_ARRAY) {
216 resultp = (old_method_list **)&cls->methodLists;
217 } else {
218 resultp = &cls->methodLists[0];
219 if (!*resultp || *resultp == END_OF_METHODS_LIST) {
220 resultp = nil;
221 }
222 }
223 } else {
224 // Subsequent call to nextMethodList.
225 if (!cls->methodLists) {
226 resultp = nil;
227 } else if (cls->info & CLS_NO_METHOD_ARRAY) {
228 resultp = nil;
229 } else {
230 resultp = &cls->methodLists[index];
231 if (!*resultp || *resultp == END_OF_METHODS_LIST) {
232 resultp = nil;
233 }
234 }
235 }
236
237 // resultp now is nil, meaning there are no more method lists,
238 // OR the address of the method list pointer to fix up and return.
239
240 if (resultp) {
241 if (*resultp) {
242 *resultp = fixupSelectorsInMethodList(cls, *resultp);
243 }
244 *it = (void *)(index + 1);
245 return *resultp;
246 } else {
247 *it = 0;
248 return nil;
249 }
250 }
251
252
253 /* These next three functions are the heart of ObjC method lookup.
254 * If the class is currently in use, methodListLock must be held by the caller.
255 */
256 static inline old_method *_findMethodInList(old_method_list * mlist, SEL sel) {
257 int i;
258 if (!mlist) return nil;
259 for (i = 0; i < mlist->method_count; i++) {
260 old_method *m = &mlist->method_list[i];
261 if (m->method_name == sel) {
262 return m;
263 }
264 }
265 return nil;
266 }
267
268 static inline old_method * _findMethodInClass(Class cls, SEL sel) __attribute__((always_inline));
269 static inline old_method * _findMethodInClass(Class cls, SEL sel) {
270 // Flattened version of nextMethodList(). The optimizer doesn't
271 // do a good job with hoisting the conditionals out of the loop.
272 // Conceptually, this looks like:
273 // while ((mlist = nextMethodList(cls, &iterator))) {
274 // old_method *m = _findMethodInList(mlist, sel);
275 // if (m) return m;
276 // }
277
278 if (!cls->methodLists) {
279 // No method lists.
280 return nil;
281 }
282 else if (cls->info & CLS_NO_METHOD_ARRAY) {
283 // One method list.
284 old_method_list **mlistp;
285 mlistp = (old_method_list **)&cls->methodLists;
286 *mlistp = fixupSelectorsInMethodList(cls, *mlistp);
287 return _findMethodInList(*mlistp, sel);
288 }
289 else {
290 // Multiple method lists.
291 old_method_list **mlistp;
292 for (mlistp = cls->methodLists;
293 *mlistp != nil && *mlistp != END_OF_METHODS_LIST;
294 mlistp++)
295 {
296 old_method *m;
297 *mlistp = fixupSelectorsInMethodList(cls, *mlistp);
298 m = _findMethodInList(*mlistp, sel);
299 if (m) return m;
300 }
301 return nil;
302 }
303 }
304
305 static inline old_method * _getMethod(Class cls, SEL sel) {
306 for (; cls; cls = cls->superclass) {
307 old_method *m;
308 m = _findMethodInClass(cls, sel);
309 if (m) return m;
310 }
311 return nil;
312 }
313
314
315 // fixme for gc debugging temporary use
316 IMP findIMPInClass(Class cls, SEL sel)
317 {
318 old_method *m = _findMethodInClass(cls, sel);
319 if (m) return m->method_imp;
320 else return nil;
321 }
322
323
324 /***********************************************************************
325 * _freedHandler.
326 **********************************************************************/
327 static void _freedHandler(id obj, SEL sel)
328 {
329 __objc_error (obj, "message %s sent to freed object=%p",
330 sel_getName(sel), (void*)obj);
331 }
332
333
334 /***********************************************************************
335 * log_and_fill_cache
336 * Log this method call. If the logger permits it, fill the method cache.
337 * cls is the method whose cache should be filled.
338 * implementer is the class that owns the implementation in question.
339 **********************************************************************/
340 static void
341 log_and_fill_cache(Class cls, Class implementer, Method meth, SEL sel)
342 {
343 #if SUPPORT_MESSAGE_LOGGING
344 if (objcMsgLogEnabled) {
345 bool cacheIt = logMessageSend(implementer->isMetaClass(),
346 cls->nameForLogging(),
347 implementer->nameForLogging(),
348 sel);
349 if (!cacheIt) return;
350 }
351 #endif
352 _cache_fill (cls, meth, sel);
353 }
354
355
356 /***********************************************************************
357 * _class_lookupMethodAndLoadCache.
358 * Method lookup for dispatchers ONLY. OTHER CODE SHOULD USE lookUpImp().
359 * This lookup avoids optimistic cache scan because the dispatcher
360 * already tried that.
361 **********************************************************************/
362 IMP _class_lookupMethodAndLoadCache3(id obj, SEL sel, Class cls)
363 {
364 return lookUpImpOrForward(cls, sel, obj,
365 YES/*initialize*/, NO/*cache*/, YES/*resolver*/);
366 }
367
368
369 /***********************************************************************
370 * lookUpImpOrForward.
371 * The standard IMP lookup.
372 * initialize==NO tries to avoid +initialize (but sometimes fails)
373 * cache==NO skips optimistic unlocked lookup (but uses cache elsewhere)
374 * Most callers should use initialize==YES and cache==YES.
375 * inst is an instance of cls or a subclass thereof, or nil if none is known.
376 * If cls is an un-initialized metaclass then a non-nil inst is faster.
377 * May return _objc_msgForward_impcache. IMPs destined for external use
378 * must be converted to _objc_msgForward or _objc_msgForward_stret.
379 * If you don't want forwarding at all, use lookUpImpOrNil() instead.
380 **********************************************************************/
381 IMP lookUpImpOrForward(Class cls, SEL sel, id inst,
382 bool initialize, bool cache, bool resolver)
383 {
384 Class curClass;
385 IMP methodPC = nil;
386 Method meth;
387 bool triedResolver = NO;
388
389 methodListLock.assertUnlocked();
390
391 // Optimistic cache lookup
392 if (cache) {
393 methodPC = _cache_getImp(cls, sel);
394 if (methodPC) return methodPC;
395 }
396
397 // Check for freed class
398 if (cls == _class_getFreedObjectClass())
399 return (IMP) _freedHandler;
400
401 // Check for +initialize
402 if (initialize && !cls->isInitialized()) {
403 _class_initialize (_class_getNonMetaClass(cls, inst));
404 // If sel == initialize, _class_initialize will send +initialize and
405 // then the messenger will send +initialize again after this
406 // procedure finishes. Of course, if this is not being called
407 // from the messenger then it won't happen. 2778172
408 }
409
410 // The lock is held to make method-lookup + cache-fill atomic
411 // with respect to method addition. Otherwise, a category could
412 // be added but ignored indefinitely because the cache was re-filled
413 // with the old value after the cache flush on behalf of the category.
414 retry:
415 methodListLock.lock();
416
417 // Ignore GC selectors
418 if (ignoreSelector(sel)) {
419 methodPC = _cache_addIgnoredEntry(cls, sel);
420 goto done;
421 }
422
423 // Try this class's cache.
424
425 methodPC = _cache_getImp(cls, sel);
426 if (methodPC) goto done;
427
428 // Try this class's method lists.
429
430 meth = _class_getMethodNoSuper_nolock(cls, sel);
431 if (meth) {
432 log_and_fill_cache(cls, cls, meth, sel);
433 methodPC = method_getImplementation(meth);
434 goto done;
435 }
436
437 // Try superclass caches and method lists.
438
439 curClass = cls;
440 while ((curClass = curClass->superclass)) {
441 // Superclass cache.
442 meth = _cache_getMethod(curClass, sel, _objc_msgForward_impcache);
443 if (meth) {
444 if (meth != (Method)1) {
445 // Found the method in a superclass. Cache it in this class.
446 log_and_fill_cache(cls, curClass, meth, sel);
447 methodPC = method_getImplementation(meth);
448 goto done;
449 }
450 else {
451 // Found a forward:: entry in a superclass.
452 // Stop searching, but don't cache yet; call method
453 // resolver for this class first.
454 break;
455 }
456 }
457
458 // Superclass method list.
459 meth = _class_getMethodNoSuper_nolock(curClass, sel);
460 if (meth) {
461 log_and_fill_cache(cls, curClass, meth, sel);
462 methodPC = method_getImplementation(meth);
463 goto done;
464 }
465 }
466
467 // No implementation found. Try method resolver once.
468
469 if (resolver && !triedResolver) {
470 methodListLock.unlock();
471 _class_resolveMethod(cls, sel, inst);
472 triedResolver = YES;
473 goto retry;
474 }
475
476 // No implementation found, and method resolver didn't help.
477 // Use forwarding.
478
479 _cache_addForwardEntry(cls, sel);
480 methodPC = _objc_msgForward_impcache;
481
482 done:
483 methodListLock.unlock();
484
485 // paranoia: look for ignored selectors with non-ignored implementations
486 assert(!(ignoreSelector(sel) && methodPC != (IMP)&_objc_ignored_method));
487
488 return methodPC;
489 }
490
491
492 /***********************************************************************
493 * lookUpImpOrNil.
494 * Like lookUpImpOrForward, but returns nil instead of _objc_msgForward_impcache
495 **********************************************************************/
496 IMP lookUpImpOrNil(Class cls, SEL sel, id inst,
497 bool initialize, bool cache, bool resolver)
498 {
499 IMP imp = lookUpImpOrForward(cls, sel, inst, initialize, cache, resolver);
500 if (imp == _objc_msgForward_impcache) return nil;
501 else return imp;
502 }
503
504
505 /***********************************************************************
506 * lookupMethodInClassAndLoadCache.
507 * Like _class_lookupMethodAndLoadCache, but does not search superclasses.
508 * Caches and returns objc_msgForward if the method is not found in the class.
509 **********************************************************************/
510 IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel)
511 {
512 Method meth;
513 IMP imp;
514
515 // fixme this still has the method list vs method cache race
516 // because it doesn't hold a lock across lookup+cache_fill,
517 // but it's only used for .cxx_construct/destruct and we assume
518 // categories don't change them.
519
520 // Search cache first.
521 imp = _cache_getImp(cls, sel);
522 if (imp) return imp;
523
524 // Cache miss. Search method list.
525
526 meth = _class_getMethodNoSuper(cls, sel);
527
528 if (meth) {
529 // Hit in method list. Cache it.
530 _cache_fill(cls, meth, sel);
531 return method_getImplementation(meth);
532 } else {
533 // Miss in method list. Cache objc_msgForward.
534 _cache_addForwardEntry(cls, sel);
535 return _objc_msgForward_impcache;
536 }
537 }
538
539
540 /***********************************************************************
541 * class_getVariable. Return the named instance variable.
542 **********************************************************************/
543
544 Ivar _class_getVariable(Class cls, const char *name, Class *memberOf)
545 {
546 for (; cls != Nil; cls = cls->superclass) {
547 int i;
548
549 // Skip class having no ivars
550 if (!cls->ivars) continue;
551
552 for (i = 0; i < cls->ivars->ivar_count; i++) {
553 // Check this ivar's name. Be careful because the
554 // compiler generates ivar entries with nil ivar_name
555 // (e.g. for anonymous bit fields).
556 old_ivar *ivar = &cls->ivars->ivar_list[i];
557 if (ivar->ivar_name && 0 == strcmp(name, ivar->ivar_name)) {
558 if (memberOf) *memberOf = cls;
559 return (Ivar)ivar;
560 }
561 }
562 }
563
564 // Not found
565 return nil;
566 }
567
568
569 old_property *
570 property_list_nth(const old_property_list *plist, uint32_t i)
571 {
572 return (old_property *)(i*plist->entsize + (char *)&plist->first);
573 }
574
575 old_property **
576 copyPropertyList(old_property_list *plist, unsigned int *outCount)
577 {
578 old_property **result = nil;
579 unsigned int count = 0;
580
581 if (plist) {
582 count = plist->count;
583 }
584
585 if (count > 0) {
586 unsigned int i;
587 result = (old_property **)malloc((count+1) * sizeof(old_property *));
588
589 for (i = 0; i < count; i++) {
590 result[i] = property_list_nth(plist, i);
591 }
592 result[i] = nil;
593 }
594
595 if (outCount) *outCount = count;
596 return result;
597 }
598
599
600 static old_property_list *
601 nextPropertyList(Class cls, uintptr_t *indexp)
602 {
603 old_property_list *result = nil;
604
605 classLock.assertLocked();
606 if (! ((cls->info & CLS_EXT) && cls->ext)) {
607 // No class ext
608 result = nil;
609 } else if (!cls->ext->propertyLists) {
610 // No property lists
611 result = nil;
612 } else if (cls->info & CLS_NO_PROPERTY_ARRAY) {
613 // Only one property list
614 if (*indexp == 0) {
615 result = (old_property_list *)cls->ext->propertyLists;
616 } else {
617 result = nil;
618 }
619 } else {
620 // More than one property list
621 result = cls->ext->propertyLists[*indexp];
622 }
623
624 if (result) {
625 ++*indexp;
626 return result;
627 } else {
628 *indexp = 0;
629 return nil;
630 }
631 }
632
633
634 /***********************************************************************
635 * class_getIvarLayout
636 * nil means all-scanned. "" means non-scanned.
637 **********************************************************************/
638 const uint8_t *
639 class_getIvarLayout(Class cls)
640 {
641 if (cls && (cls->info & CLS_EXT)) {
642 return cls->ivar_layout;
643 } else {
644 return nil; // conservative scan
645 }
646 }
647
648
649 /***********************************************************************
650 * class_getWeakIvarLayout
651 * nil means no weak ivars.
652 **********************************************************************/
653 const uint8_t *
654 class_getWeakIvarLayout(Class cls)
655 {
656 if (cls && (cls->info & CLS_EXT) && cls->ext) {
657 return cls->ext->weak_ivar_layout;
658 } else {
659 return nil; // no weak ivars
660 }
661 }
662
663
664 /***********************************************************************
665 * class_setIvarLayout
666 * nil means all-scanned. "" means non-scanned.
667 **********************************************************************/
668 void class_setIvarLayout(Class cls, const uint8_t *layout)
669 {
670 if (!cls) return;
671
672 if (! (cls->info & CLS_EXT)) {
673 _objc_inform("class '%s' needs to be recompiled", cls->name);
674 return;
675 }
676
677 // fixme leak
678 cls->ivar_layout = ustrdupMaybeNil(layout);
679 }
680
681 // SPI: Instance-specific object layout.
682
683 void _class_setIvarLayoutAccessor(Class cls, const uint8_t* (*accessor) (id object)) {
684 if (!cls) return;
685
686 if (! (cls->info & CLS_EXT)) {
687 _objc_inform("class '%s' needs to be recompiled", cls->name);
688 return;
689 }
690
691 // fixme leak
692 cls->ivar_layout = (const uint8_t *)accessor;
693 cls->setInfo(CLS_HAS_INSTANCE_SPECIFIC_LAYOUT);
694 }
695
696 const uint8_t *_object_getIvarLayout(Class cls, id object) {
697 if (cls && (cls->info & CLS_EXT)) {
698 const uint8_t* layout = cls->ivar_layout;
699 if (cls->info & CLS_HAS_INSTANCE_SPECIFIC_LAYOUT) {
700 const uint8_t* (*accessor) (id object) = (const uint8_t* (*)(id))layout;
701 layout = accessor(object);
702 }
703 return layout;
704 } else {
705 return nil;
706 }
707 }
708
709 /***********************************************************************
710 * class_setWeakIvarLayout
711 * nil means no weak ivars.
712 **********************************************************************/
713 void class_setWeakIvarLayout(Class cls, const uint8_t *layout)
714 {
715 if (!cls) return;
716
717 mutex_locker_t lock(classLock);
718
719 allocateExt(cls);
720
721 // fixme leak
722 cls->ext->weak_ivar_layout = ustrdupMaybeNil(layout);
723 }
724
725
726 /***********************************************************************
727 * class_setVersion. Record the specified version with the class.
728 **********************************************************************/
729 void class_setVersion(Class cls, int version)
730 {
731 if (!cls) return;
732 cls->version = version;
733 }
734
735 /***********************************************************************
736 * class_getVersion. Return the version recorded with the class.
737 **********************************************************************/
738 int class_getVersion(Class cls)
739 {
740 if (!cls) return 0;
741 return (int)cls->version;
742 }
743
744
745 /***********************************************************************
746 * class_getName.
747 **********************************************************************/
748 const char *class_getName(Class cls)
749 {
750 if (!cls) return "nil";
751 else return cls->demangledName();
752 }
753
754
755 /***********************************************************************
756 * _class_getNonMetaClass.
757 * Return the ordinary class for this class or metaclass.
758 * Used by +initialize.
759 **********************************************************************/
760 Class _class_getNonMetaClass(Class cls, id obj)
761 {
762 // fixme ick
763 if (cls->isMetaClass()) {
764 if (cls->info & CLS_CONSTRUCTING) {
765 // Class is under construction and isn't in the class_hash,
766 // so objc_getClass doesn't work.
767 cls = obj; // fixme this may be nil in some paths
768 }
769 else if (strncmp(cls->name, "_%", 2) == 0) {
770 // Posee's meta's name is smashed and isn't in the class_hash,
771 // so objc_getClass doesn't work.
772 const char *baseName = strchr(cls->name, '%'); // get posee's real name
773 cls = objc_getClass(baseName);
774 }
775 else {
776 cls = objc_getClass(cls->name);
777 }
778 assert(cls);
779 }
780
781 return cls;
782 }
783
784
785 Cache _class_getCache(Class cls)
786 {
787 return cls->cache;
788 }
789
790 void _class_setCache(Class cls, Cache cache)
791 {
792 cls->cache = cache;
793 }
794
795 const char *_category_getName(Category cat)
796 {
797 return oldcategory(cat)->category_name;
798 }
799
800 const char *_category_getClassName(Category cat)
801 {
802 return oldcategory(cat)->class_name;
803 }
804
805 Class _category_getClass(Category cat)
806 {
807 return objc_getClass(oldcategory(cat)->class_name);
808 }
809
810 IMP _category_getLoadMethod(Category cat)
811 {
812 old_method_list *mlist = oldcategory(cat)->class_methods;
813 if (mlist) {
814 return lookupNamedMethodInMethodList(mlist, "load");
815 } else {
816 return nil;
817 }
818 }
819
820
821
822 /***********************************************************************
823 * class_nextMethodList.
824 * External version of nextMethodList().
825 *
826 * This function is not fully thread-safe. A series of calls to
827 * class_nextMethodList() may fail if methods are added to or removed
828 * from the class between calls.
829 * If methods are added between calls to class_nextMethodList(), it may
830 * return previously-returned method lists again, and may fail to return
831 * newly-added lists.
832 * If methods are removed between calls to class_nextMethodList(), it may
833 * omit surviving method lists or simply crash.
834 **********************************************************************/
835 OBJC_EXPORT struct objc_method_list *class_nextMethodList(Class cls, void **it)
836 {
837 OBJC_WARN_DEPRECATED;
838
839 mutex_locker_t lock(methodListLock);
840 return (struct objc_method_list *) nextMethodList(cls, it);
841 }
842
843
844 /***********************************************************************
845 * class_addMethods.
846 *
847 * Formerly class_addInstanceMethods ()
848 **********************************************************************/
849 OBJC_EXPORT void class_addMethods(Class cls, struct objc_method_list *meths)
850 {
851 OBJC_WARN_DEPRECATED;
852
853 // Add the methods.
854 {
855 mutex_locker_t lock(methodListLock);
856 _objc_insertMethods(cls, (old_method_list *)meths, nil);
857 }
858
859 // Must flush when dynamically adding methods. No need to flush
860 // all the class method caches. If cls is a meta class, though,
861 // this will still flush it and any of its sub-meta classes.
862 flush_caches (cls, NO);
863 }
864
865
866 /***********************************************************************
867 * class_removeMethods.
868 **********************************************************************/
869 OBJC_EXPORT void class_removeMethods(Class cls, struct objc_method_list *meths)
870 {
871 OBJC_WARN_DEPRECATED;
872
873 // Remove the methods
874 {
875 mutex_locker_t lock(methodListLock);
876 _objc_removeMethods(cls, (old_method_list *)meths);
877 }
878
879 // Must flush when dynamically removing methods. No need to flush
880 // all the class method caches. If cls is a meta class, though,
881 // this will still flush it and any of its sub-meta classes.
882 flush_caches (cls, NO);
883 }
884
885 /***********************************************************************
886 * lookupNamedMethodInMethodList
887 * Only called to find +load/-.cxx_construct/-.cxx_destruct methods,
888 * without fixing up the entire method list.
889 * The class is not yet in use, so methodListLock is not taken.
890 **********************************************************************/
891 IMP lookupNamedMethodInMethodList(old_method_list *mlist, const char *meth_name)
892 {
893 old_method *m;
894 m = meth_name ? _findNamedMethodInList(mlist, meth_name) : nil;
895 return (m ? m->method_imp : nil);
896 }
897
898 static Method _class_getMethod(Class cls, SEL sel)
899 {
900 mutex_locker_t lock(methodListLock);
901 return (Method)_getMethod(cls, sel);
902 }
903
904 static Method _class_getMethodNoSuper(Class cls, SEL sel)
905 {
906 mutex_locker_t lock(methodListLock);
907 return (Method)_findMethodInClass(cls, sel);
908 }
909
910 static Method _class_getMethodNoSuper_nolock(Class cls, SEL sel)
911 {
912 methodListLock.assertLocked();
913 return (Method)_findMethodInClass(cls, sel);
914 }
915
916
917 /***********************************************************************
918 * class_getInstanceMethod. Return the instance method for the
919 * specified class and selector.
920 **********************************************************************/
921 Method class_getInstanceMethod(Class cls, SEL sel)
922 {
923 if (!cls || !sel) return nil;
924
925 // This deliberately avoids +initialize because it historically did so.
926
927 // This implementation is a bit weird because it's the only place that
928 // wants a Method instead of an IMP.
929
930 Method meth;
931 meth = _cache_getMethod(cls, sel, _objc_msgForward_impcache);
932 if (meth == (Method)1) {
933 // Cache contains forward:: . Stop searching.
934 return nil;
935 } else if (meth) {
936 return meth;
937 }
938
939 // Search method lists, try method resolver, etc.
940 lookUpImpOrNil(cls, sel, nil,
941 NO/*initialize*/, NO/*cache*/, YES/*resolver*/);
942
943 meth = _cache_getMethod(cls, sel, _objc_msgForward_impcache);
944 if (meth == (Method)1) {
945 // Cache contains forward:: . Stop searching.
946 return nil;
947 } else if (meth) {
948 return meth;
949 }
950
951 return _class_getMethod(cls, sel);
952 }
953
954
955 BOOL class_conformsToProtocol(Class cls, Protocol *proto_gen)
956 {
957 old_protocol *proto = oldprotocol(proto_gen);
958
959 if (!cls) return NO;
960 if (!proto) return NO;
961
962 if (cls->ISA()->version >= 3) {
963 old_protocol_list *list;
964 for (list = cls->protocols; list != nil; list = list->next) {
965 int i;
966 for (i = 0; i < list->count; i++) {
967 if (list->list[i] == proto) return YES;
968 if (protocol_conformsToProtocol((Protocol *)list->list[i], proto_gen)) return YES;
969 }
970 if (cls->ISA()->version <= 4) break;
971 }
972 }
973 return NO;
974 }
975
976
977 static NXMapTable * posed_class_hash = nil;
978
979 /***********************************************************************
980 * objc_getOrigClass.
981 **********************************************************************/
982 extern "C"
983 Class _objc_getOrigClass(const char *name)
984 {
985 // Look for class among the posers
986 {
987 mutex_locker_t lock(classLock);
988 if (posed_class_hash) {
989 Class cls = (Class) NXMapGet (posed_class_hash, name);
990 if (cls) return cls;
991 }
992 }
993
994 // Not a poser. Do a normal lookup.
995 Class cls = objc_getClass (name);
996 if (cls) return cls;
997
998 _objc_inform ("class `%s' not linked into application", name);
999 return nil;
1000 }
1001
1002 Class objc_getOrigClass(const char *name)
1003 {
1004 OBJC_WARN_DEPRECATED;
1005 return _objc_getOrigClass(name);
1006 }
1007
1008 /***********************************************************************
1009 * _objc_addOrigClass. This function is only used from class_poseAs.
1010 * Registers the original class names, before they get obscured by
1011 * posing, so that [super ..] will work correctly from categories
1012 * in posing classes and in categories in classes being posed for.
1013 **********************************************************************/
1014 static void _objc_addOrigClass (Class origClass)
1015 {
1016 mutex_locker_t lock(classLock);
1017
1018 // Create the poser's hash table on first use
1019 if (!posed_class_hash)
1020 {
1021 posed_class_hash = NXCreateMapTable(NXStrValueMapPrototype, 8);
1022 }
1023
1024 // Add the named class iff it is not already there (or collides?)
1025 if (NXMapGet (posed_class_hash, origClass->name) == 0)
1026 NXMapInsert (posed_class_hash, origClass->name, origClass);
1027 }
1028
1029
1030 /***********************************************************************
1031 * change_class_references
1032 * Change classrefs and superclass pointers from original to imposter
1033 * But if copy!=nil, don't change copy->superclass.
1034 * If changeSuperRefs==YES, also change [super message] classrefs.
1035 * Used by class_poseAs and objc_setFutureClass
1036 * classLock must be locked.
1037 **********************************************************************/
1038 void change_class_references(Class imposter,
1039 Class original,
1040 Class copy,
1041 bool changeSuperRefs)
1042 {
1043 header_info *hInfo;
1044 Class clsObject;
1045 NXHashState state;
1046
1047 // Change all subclasses of the original to point to the imposter.
1048 state = NXInitHashState (class_hash);
1049 while (NXNextHashState (class_hash, &state, (void **) &clsObject))
1050 {
1051 while ((clsObject) && (clsObject != imposter) &&
1052 (clsObject != copy))
1053 {
1054 if (clsObject->superclass == original)
1055 {
1056 clsObject->superclass = imposter;
1057 clsObject->ISA()->superclass = imposter->ISA();
1058 // We must flush caches here!
1059 break;
1060 }
1061
1062 clsObject = clsObject->superclass;
1063 }
1064 }
1065
1066 // Replace the original with the imposter in all class refs
1067 // Major loop - process all headers
1068 for (hInfo = FirstHeader; hInfo != nil; hInfo = hInfo->next)
1069 {
1070 Class *cls_refs;
1071 size_t refCount;
1072 unsigned int index;
1073
1074 // Fix class refs associated with this header
1075 cls_refs = _getObjcClassRefs(hInfo, &refCount);
1076 if (cls_refs) {
1077 for (index = 0; index < refCount; index += 1) {
1078 if (cls_refs[index] == original) {
1079 cls_refs[index] = imposter;
1080 }
1081 }
1082 }
1083 }
1084 }
1085
1086
1087 /***********************************************************************
1088 * class_poseAs.
1089 *
1090 * !!! class_poseAs () does not currently flush any caches.
1091 **********************************************************************/
1092 Class class_poseAs(Class imposter, Class original)
1093 {
1094 char * imposterNamePtr;
1095 Class copy;
1096
1097 OBJC_WARN_DEPRECATED;
1098
1099 // Trivial case is easy
1100 if (imposter == original)
1101 return imposter;
1102
1103 // Imposter must be an immediate subclass of the original
1104 if (imposter->superclass != original) {
1105 __objc_error(imposter,
1106 "[%s poseAs:%s]: target not immediate superclass",
1107 imposter->name, original->name);
1108 }
1109
1110 // Can't pose when you have instance variables (how could it work?)
1111 if (imposter->ivars) {
1112 __objc_error(imposter,
1113 "[%s poseAs:%s]: %s defines new instance variables",
1114 imposter->name, original->name, imposter->name);
1115 }
1116
1117 // Build a string to use to replace the name of the original class.
1118 #if TARGET_OS_WIN32
1119 # define imposterNamePrefix "_%"
1120 imposterNamePtr = malloc(strlen(original->name) + strlen(imposterNamePrefix) + 1);
1121 strcpy(imposterNamePtr, imposterNamePrefix);
1122 strcat(imposterNamePtr, original->name);
1123 # undef imposterNamePrefix
1124 #else
1125 asprintf(&imposterNamePtr, "_%%%s", original->name);
1126 #endif
1127
1128 // We lock the class hashtable, so we are thread safe with respect to
1129 // calls to objc_getClass (). However, the class names are not
1130 // changed atomically, nor are all of the subclasses updated
1131 // atomically. I have ordered the operations so that you will
1132 // never crash, but you may get inconsistent results....
1133
1134 // Register the original class so that [super ..] knows
1135 // exactly which classes are the "original" classes.
1136 _objc_addOrigClass (original);
1137 _objc_addOrigClass (imposter);
1138
1139 // Copy the imposter, so that the imposter can continue
1140 // its normal life in addition to changing the behavior of
1141 // the original. As a hack we don't bother to copy the metaclass.
1142 // For some reason we modify the original rather than the copy.
1143 copy = (Class)malloc(sizeof(objc_class));
1144 memmove(copy, imposter, sizeof(objc_class));
1145
1146 mutex_locker_t lock(classLock);
1147
1148 // Remove both the imposter and the original class.
1149 NXHashRemove (class_hash, imposter);
1150 NXHashRemove (class_hash, original);
1151
1152 NXHashInsert (class_hash, copy);
1153 objc_addRegisteredClass(copy); // imposter & original will rejoin later, just track the new guy
1154
1155 // Mark the imposter as such
1156 imposter->setInfo(CLS_POSING);
1157 imposter->ISA()->setInfo(CLS_POSING);
1158
1159 // Change the name of the imposter to that of the original class.
1160 imposter->name = original->name;
1161 imposter->ISA()->name = original->ISA()->name;
1162
1163 // Also copy the version field to avoid archiving problems.
1164 imposter->version = original->version;
1165
1166 // Change classrefs and superclass pointers
1167 // Don't change copy->superclass
1168 // Don't change [super ...] messages
1169 change_class_references(imposter, original, copy, NO);
1170
1171 // Change the name of the original class.
1172 original->name = imposterNamePtr + 1;
1173 original->ISA()->name = imposterNamePtr;
1174
1175 // Restore the imposter and the original class with their new names.
1176 NXHashInsert (class_hash, imposter);
1177 NXHashInsert (class_hash, original);
1178
1179 return imposter;
1180 }
1181
1182
1183 /***********************************************************************
1184 * _objc_flush_caches. Flush the instance and class method caches
1185 * of cls and all its subclasses.
1186 *
1187 * Specifying Nil for the class "all classes."
1188 **********************************************************************/
1189 static void flush_caches(Class target, bool flush_meta)
1190 {
1191 bool collectALot = (target == nil);
1192 NXHashState state;
1193 Class clsObject;
1194 #ifdef OBJC_INSTRUMENTED
1195 unsigned int classesVisited;
1196 unsigned int subclassCount;
1197 #endif
1198
1199 mutex_locker_t lock(classLock);
1200 mutex_locker_t lock2(cacheUpdateLock);
1201
1202 // Leaf classes are fastest because there are no subclass caches to flush.
1203 // fixme instrument
1204 if (target && (target->info & CLS_LEAF)) {
1205 _cache_flush (target);
1206
1207 if (target->ISA() && (target->ISA()->info & CLS_LEAF)) {
1208 _cache_flush (target->ISA());
1209 return; // done
1210 } else {
1211 // Reset target and handle it by one of the methods below.
1212 target = target->ISA();
1213 flush_meta = NO;
1214 // NOT done
1215 }
1216 }
1217
1218 state = NXInitHashState(class_hash);
1219
1220 // Handle nil and root instance class specially: flush all
1221 // instance and class method caches. Nice that this
1222 // loop is linear vs the N-squared loop just below.
1223 if (!target || !target->superclass)
1224 {
1225 #ifdef OBJC_INSTRUMENTED
1226 LinearFlushCachesCount += 1;
1227 classesVisited = 0;
1228 subclassCount = 0;
1229 #endif
1230 // Traverse all classes in the hash table
1231 while (NXNextHashState(class_hash, &state, (void**)&clsObject))
1232 {
1233 Class metaClsObject;
1234 #ifdef OBJC_INSTRUMENTED
1235 classesVisited += 1;
1236 #endif
1237
1238 // Skip class that is known not to be a subclass of this root
1239 // (the isa pointer of any meta class points to the meta class
1240 // of the root).
1241 // NOTE: When is an isa pointer of a hash tabled class ever nil?
1242 metaClsObject = clsObject->ISA();
1243 if (target && metaClsObject && target->ISA() != metaClsObject->ISA()) {
1244 continue;
1245 }
1246
1247 #ifdef OBJC_INSTRUMENTED
1248 subclassCount += 1;
1249 #endif
1250
1251 _cache_flush (clsObject);
1252 if (flush_meta && metaClsObject != nil) {
1253 _cache_flush (metaClsObject);
1254 }
1255 }
1256 #ifdef OBJC_INSTRUMENTED
1257 LinearFlushCachesVisitedCount += classesVisited;
1258 if (classesVisited > MaxLinearFlushCachesVisitedCount)
1259 MaxLinearFlushCachesVisitedCount = classesVisited;
1260 IdealFlushCachesCount += subclassCount;
1261 if (subclassCount > MaxIdealFlushCachesCount)
1262 MaxIdealFlushCachesCount = subclassCount;
1263 #endif
1264
1265 goto done;
1266 }
1267
1268 // Outer loop - flush any cache that could now get a method from
1269 // cls (i.e. the cache associated with cls and any of its subclasses).
1270 #ifdef OBJC_INSTRUMENTED
1271 NonlinearFlushCachesCount += 1;
1272 classesVisited = 0;
1273 subclassCount = 0;
1274 #endif
1275 while (NXNextHashState(class_hash, &state, (void**)&clsObject))
1276 {
1277 Class clsIter;
1278
1279 #ifdef OBJC_INSTRUMENTED
1280 NonlinearFlushCachesClassCount += 1;
1281 #endif
1282
1283 // Inner loop - Process a given class
1284 clsIter = clsObject;
1285 while (clsIter)
1286 {
1287
1288 #ifdef OBJC_INSTRUMENTED
1289 classesVisited += 1;
1290 #endif
1291 // Flush clsObject instance method cache if
1292 // clsObject is a subclass of cls, or is cls itself
1293 // Flush the class method cache if that was asked for
1294 if (clsIter == target)
1295 {
1296 #ifdef OBJC_INSTRUMENTED
1297 subclassCount += 1;
1298 #endif
1299 _cache_flush (clsObject);
1300 if (flush_meta)
1301 _cache_flush (clsObject->ISA());
1302
1303 break;
1304
1305 }
1306
1307 // Flush clsObject class method cache if cls is
1308 // the meta class of clsObject or of one
1309 // of clsObject's superclasses
1310 else if (clsIter->ISA() == target)
1311 {
1312 #ifdef OBJC_INSTRUMENTED
1313 subclassCount += 1;
1314 #endif
1315 _cache_flush (clsObject->ISA());
1316 break;
1317 }
1318
1319 // Move up superclass chain
1320 // else if (clsIter->isInitialized())
1321 clsIter = clsIter->superclass;
1322
1323 // clsIter is not initialized, so its cache
1324 // must be empty. This happens only when
1325 // clsIter == clsObject, because
1326 // superclasses are initialized before
1327 // subclasses, and this loop traverses
1328 // from sub- to super- classes.
1329 // else
1330 // break;
1331 }
1332 }
1333 #ifdef OBJC_INSTRUMENTED
1334 NonlinearFlushCachesVisitedCount += classesVisited;
1335 if (classesVisited > MaxNonlinearFlushCachesVisitedCount)
1336 MaxNonlinearFlushCachesVisitedCount = classesVisited;
1337 IdealFlushCachesCount += subclassCount;
1338 if (subclassCount > MaxIdealFlushCachesCount)
1339 MaxIdealFlushCachesCount = subclassCount;
1340 #endif
1341
1342
1343 done:
1344 if (collectALot) {
1345 _cache_collect(true);
1346 }
1347 }
1348
1349
1350 void _objc_flush_caches(Class target)
1351 {
1352 flush_caches(target, YES);
1353 }
1354
1355
1356
1357 /***********************************************************************
1358 * flush_marked_caches. Flush the method cache of any class marked
1359 * CLS_FLUSH_CACHE (and all subclasses thereof)
1360 * fixme instrument
1361 **********************************************************************/
1362 void flush_marked_caches(void)
1363 {
1364 Class cls;
1365 Class supercls;
1366 NXHashState state;
1367
1368 mutex_locker_t lock(classLock);
1369 mutex_locker_t lock2(cacheUpdateLock);
1370
1371 state = NXInitHashState(class_hash);
1372 while (NXNextHashState(class_hash, &state, (void**)&cls)) {
1373 for (supercls = cls; supercls; supercls = supercls->superclass) {
1374 if (supercls->info & CLS_FLUSH_CACHE) {
1375 _cache_flush(cls);
1376 break;
1377 }
1378 }
1379
1380 for (supercls = cls->ISA(); supercls; supercls = supercls->superclass) {
1381 if (supercls->info & CLS_FLUSH_CACHE) {
1382 _cache_flush(cls->ISA());
1383 break;
1384 }
1385 }
1386 }
1387
1388 state = NXInitHashState(class_hash);
1389 while (NXNextHashState(class_hash, &state, (void**)&cls)) {
1390 if (cls->info & CLS_FLUSH_CACHE) {
1391 cls->clearInfo(CLS_FLUSH_CACHE);
1392 }
1393 if (cls->ISA()->info & CLS_FLUSH_CACHE) {
1394 cls->ISA()->clearInfo(CLS_FLUSH_CACHE);
1395 }
1396 }
1397 }
1398
1399
1400 /***********************************************************************
1401 * get_base_method_list
1402 * Returns the method list containing the class's own methods,
1403 * ignoring any method lists added by categories or class_addMethods.
1404 * Called only by add_class_to_loadable_list.
1405 * Does not hold methodListLock because add_class_to_loadable_list
1406 * does not manipulate in-use classes.
1407 **********************************************************************/
1408 static old_method_list *get_base_method_list(Class cls)
1409 {
1410 old_method_list **ptr;
1411
1412 if (!cls->methodLists) return nil;
1413 if (cls->info & CLS_NO_METHOD_ARRAY) return (old_method_list *)cls->methodLists;
1414 ptr = cls->methodLists;
1415 if (!*ptr || *ptr == END_OF_METHODS_LIST) return nil;
1416 while ( *ptr != 0 && *ptr != END_OF_METHODS_LIST ) { ptr++; }
1417 --ptr;
1418 return *ptr;
1419 }
1420
1421
1422 static IMP _class_getLoadMethod_nocheck(Class cls)
1423 {
1424 old_method_list *mlist;
1425 mlist = get_base_method_list(cls->ISA());
1426 if (mlist) {
1427 return lookupNamedMethodInMethodList (mlist, "load");
1428 }
1429 return nil;
1430 }
1431
1432
1433 bool _class_hasLoadMethod(Class cls)
1434 {
1435 if (cls->ISA()->info & CLS_HAS_LOAD_METHOD) return YES;
1436 return _class_getLoadMethod_nocheck(cls);
1437 }
1438
1439
1440 /***********************************************************************
1441 * objc_class::getLoadMethod
1442 * Returns cls's +load implementation, or nil if it doesn't have one.
1443 **********************************************************************/
1444 IMP objc_class::getLoadMethod()
1445 {
1446 if (ISA()->info & CLS_HAS_LOAD_METHOD) {
1447 return _class_getLoadMethod_nocheck((Class)this);
1448 }
1449 return nil;
1450 }
1451
1452 BOOL _class_usesAutomaticRetainRelease(Class cls)
1453 {
1454 return NO;
1455 }
1456
1457 uint32_t _class_getInstanceStart(Class cls)
1458 {
1459 _objc_fatal("_class_getInstanceStart() unimplemented for fragile instance variables");
1460 return 0; // PCB: never used just provided for ARR consistency.
1461 }
1462
1463 ptrdiff_t ivar_getOffset(Ivar ivar)
1464 {
1465 return oldivar(ivar)->ivar_offset;
1466 }
1467
1468 const char *ivar_getName(Ivar ivar)
1469 {
1470 return oldivar(ivar)->ivar_name;
1471 }
1472
1473 const char *ivar_getTypeEncoding(Ivar ivar)
1474 {
1475 return oldivar(ivar)->ivar_type;
1476 }
1477
1478
1479 IMP method_getImplementation(Method m)
1480 {
1481 if (!m) return nil;
1482 return oldmethod(m)->method_imp;
1483 }
1484
1485 SEL method_getName(Method m)
1486 {
1487 if (!m) return nil;
1488 return oldmethod(m)->method_name;
1489 }
1490
1491 const char *method_getTypeEncoding(Method m)
1492 {
1493 if (!m) return nil;
1494 return oldmethod(m)->method_types;
1495 }
1496
1497 unsigned int method_getSizeOfArguments(Method m)
1498 {
1499 OBJC_WARN_DEPRECATED;
1500 if (!m) return 0;
1501 return encoding_getSizeOfArguments(method_getTypeEncoding(m));
1502 }
1503
1504 unsigned int method_getArgumentInfo(Method m, int arg,
1505 const char **type, int *offset)
1506 {
1507 OBJC_WARN_DEPRECATED;
1508 if (!m) return 0;
1509 return encoding_getArgumentInfo(method_getTypeEncoding(m),
1510 arg, type, offset);
1511 }
1512
1513
1514 static spinlock_t impLock;
1515
1516 IMP method_setImplementation(Method m_gen, IMP imp)
1517 {
1518 IMP old;
1519 old_method *m = oldmethod(m_gen);
1520 if (!m) return nil;
1521 if (!imp) return nil;
1522
1523 if (ignoreSelector(m->method_name)) {
1524 // Ignored methods stay ignored
1525 return m->method_imp;
1526 }
1527
1528 impLock.lock();
1529 old = m->method_imp;
1530 m->method_imp = imp;
1531 impLock.unlock();
1532 return old;
1533 }
1534
1535
1536 void method_exchangeImplementations(Method m1_gen, Method m2_gen)
1537 {
1538 IMP m1_imp;
1539 old_method *m1 = oldmethod(m1_gen);
1540 old_method *m2 = oldmethod(m2_gen);
1541 if (!m1 || !m2) return;
1542
1543 if (ignoreSelector(m1->method_name) || ignoreSelector(m2->method_name)) {
1544 // Ignored methods stay ignored. Now they're both ignored.
1545 m1->method_imp = (IMP)&_objc_ignored_method;
1546 m2->method_imp = (IMP)&_objc_ignored_method;
1547 return;
1548 }
1549
1550 impLock.lock();
1551 m1_imp = m1->method_imp;
1552 m1->method_imp = m2->method_imp;
1553 m2->method_imp = m1_imp;
1554 impLock.unlock();
1555 }
1556
1557
1558 struct objc_method_description * method_getDescription(Method m)
1559 {
1560 if (!m) return nil;
1561 return (struct objc_method_description *)oldmethod(m);
1562 }
1563
1564
1565 const char *property_getName(objc_property_t prop)
1566 {
1567 return oldproperty(prop)->name;
1568 }
1569
1570 const char *property_getAttributes(objc_property_t prop)
1571 {
1572 return oldproperty(prop)->attributes;
1573 }
1574
1575 objc_property_attribute_t *property_copyAttributeList(objc_property_t prop,
1576 unsigned int *outCount)
1577 {
1578 if (!prop) {
1579 if (outCount) *outCount = 0;
1580 return nil;
1581 }
1582
1583 mutex_locker_t lock(classLock);
1584 return copyPropertyAttributeList(oldproperty(prop)->attributes,outCount);
1585 }
1586
1587 char * property_copyAttributeValue(objc_property_t prop, const char *name)
1588 {
1589 if (!prop || !name || *name == '\0') return nil;
1590
1591 mutex_locker_t lock(classLock);
1592 return copyPropertyAttributeValue(oldproperty(prop)->attributes, name);
1593 }
1594
1595
1596 /***********************************************************************
1597 * class_addMethod
1598 **********************************************************************/
1599 static IMP _class_addMethod(Class cls, SEL name, IMP imp,
1600 const char *types, bool replace)
1601 {
1602 old_method *m;
1603 IMP result = nil;
1604
1605 if (!types) types = "";
1606
1607 mutex_locker_t lock(methodListLock);
1608
1609 if ((m = _findMethodInClass(cls, name))) {
1610 // already exists
1611 // fixme atomic
1612 result = method_getImplementation((Method)m);
1613 if (replace) {
1614 method_setImplementation((Method)m, imp);
1615 }
1616 } else {
1617 // fixme could be faster
1618 old_method_list *mlist =
1619 (old_method_list *)calloc(sizeof(old_method_list), 1);
1620 mlist->obsolete = fixed_up_method_list;
1621 mlist->method_count = 1;
1622 mlist->method_list[0].method_name = name;
1623 mlist->method_list[0].method_types = strdup(types);
1624 if (!ignoreSelector(name)) {
1625 mlist->method_list[0].method_imp = imp;
1626 } else {
1627 mlist->method_list[0].method_imp = (IMP)&_objc_ignored_method;
1628 }
1629
1630 _objc_insertMethods(cls, mlist, nil);
1631 if (!(cls->info & CLS_CONSTRUCTING)) {
1632 flush_caches(cls, NO);
1633 } else {
1634 // in-construction class has no subclasses
1635 flush_cache(cls);
1636 }
1637 result = nil;
1638 }
1639
1640 return result;
1641 }
1642
1643
1644 /***********************************************************************
1645 * class_addMethod
1646 **********************************************************************/
1647 BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
1648 {
1649 IMP old;
1650 if (!cls) return NO;
1651
1652 old = _class_addMethod(cls, name, imp, types, NO);
1653 return !old;
1654 }
1655
1656
1657 /***********************************************************************
1658 * class_replaceMethod
1659 **********************************************************************/
1660 IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
1661 {
1662 if (!cls) return nil;
1663
1664 return _class_addMethod(cls, name, imp, types, YES);
1665 }
1666
1667
1668 /***********************************************************************
1669 * class_addIvar
1670 **********************************************************************/
1671 BOOL class_addIvar(Class cls, const char *name, size_t size,
1672 uint8_t alignment, const char *type)
1673 {
1674 bool result = YES;
1675
1676 if (!cls) return NO;
1677 if (ISMETA(cls)) return NO;
1678 if (!(cls->info & CLS_CONSTRUCTING)) return NO;
1679
1680 if (!type) type = "";
1681 if (name && 0 == strcmp(name, "")) name = nil;
1682
1683 mutex_locker_t lock(classLock);
1684
1685 // Check for existing ivar with this name
1686 // fixme check superclasses?
1687 if (cls->ivars) {
1688 int i;
1689 for (i = 0; i < cls->ivars->ivar_count; i++) {
1690 if (0 == strcmp(cls->ivars->ivar_list[i].ivar_name, name)) {
1691 result = NO;
1692 break;
1693 }
1694 }
1695 }
1696
1697 if (result) {
1698 old_ivar_list *old = cls->ivars;
1699 size_t oldSize;
1700 int newCount;
1701 old_ivar *ivar;
1702 size_t alignBytes;
1703 size_t misalign;
1704
1705 if (old) {
1706 oldSize = sizeof(old_ivar_list) +
1707 (old->ivar_count - 1) * sizeof(old_ivar);
1708 newCount = 1 + old->ivar_count;
1709 } else {
1710 oldSize = sizeof(old_ivar_list) - sizeof(old_ivar);
1711 newCount = 1;
1712 }
1713
1714 // allocate new ivar list
1715 cls->ivars = (old_ivar_list *)
1716 calloc(oldSize+sizeof(old_ivar), 1);
1717 if (old) memcpy(cls->ivars, old, oldSize);
1718 if (old && malloc_size(old)) free(old);
1719 cls->ivars->ivar_count = newCount;
1720 ivar = &cls->ivars->ivar_list[newCount-1];
1721
1722 // set ivar name and type
1723 ivar->ivar_name = strdup(name);
1724 ivar->ivar_type = strdup(type);
1725
1726 // align if necessary
1727 alignBytes = 1 << alignment;
1728 misalign = cls->instance_size % alignBytes;
1729 if (misalign) cls->instance_size += (long)(alignBytes - misalign);
1730
1731 // set ivar offset and increase instance size
1732 ivar->ivar_offset = (int)cls->instance_size;
1733 cls->instance_size += (long)size;
1734 }
1735
1736 return result;
1737 }
1738
1739
1740 /***********************************************************************
1741 * class_addProtocol
1742 **********************************************************************/
1743 BOOL class_addProtocol(Class cls, Protocol *protocol_gen)
1744 {
1745 old_protocol *protocol = oldprotocol(protocol_gen);
1746 old_protocol_list *plist;
1747
1748 if (!cls) return NO;
1749 if (class_conformsToProtocol(cls, protocol_gen)) return NO;
1750
1751 mutex_locker_t lock(classLock);
1752
1753 // fixme optimize - protocol list doesn't escape?
1754 plist = (old_protocol_list*)calloc(sizeof(old_protocol_list), 1);
1755 plist->count = 1;
1756 plist->list[0] = protocol;
1757 plist->next = cls->protocols;
1758 cls->protocols = plist;
1759
1760 // fixme metaclass?
1761
1762 return YES;
1763 }
1764
1765
1766 /***********************************************************************
1767 * _class_addProperties
1768 * Internal helper to add properties to a class.
1769 * Used by category attachment and class_addProperty()
1770 * Locking: acquires classLock
1771 **********************************************************************/
1772 bool
1773 _class_addProperties(Class cls,
1774 old_property_list *additions)
1775 {
1776 old_property_list *newlist;
1777
1778 if (!(cls->info & CLS_EXT)) return NO;
1779
1780 newlist = (old_property_list *)
1781 memdup(additions, sizeof(*newlist) - sizeof(newlist->first)
1782 + (additions->entsize * additions->count));
1783
1784 mutex_locker_t lock(classLock);
1785
1786 allocateExt(cls);
1787 if (!cls->ext->propertyLists) {
1788 // cls has no properties - simply use this list
1789 cls->ext->propertyLists = (old_property_list **)newlist;
1790 cls->setInfo(CLS_NO_PROPERTY_ARRAY);
1791 }
1792 else if (cls->info & CLS_NO_PROPERTY_ARRAY) {
1793 // cls has one property list - make a new array
1794 old_property_list **newarray = (old_property_list **)
1795 malloc(3 * sizeof(*newarray));
1796 newarray[0] = newlist;
1797 newarray[1] = (old_property_list *)cls->ext->propertyLists;
1798 newarray[2] = nil;
1799 cls->ext->propertyLists = newarray;
1800 cls->clearInfo(CLS_NO_PROPERTY_ARRAY);
1801 }
1802 else {
1803 // cls has a property array - make a bigger one
1804 old_property_list **newarray;
1805 int count = 0;
1806 while (cls->ext->propertyLists[count]) count++;
1807 newarray = (old_property_list **)
1808 malloc((count+2) * sizeof(*newarray));
1809 newarray[0] = newlist;
1810 memcpy(&newarray[1], &cls->ext->propertyLists[0],
1811 count * sizeof(*newarray));
1812 newarray[count+1] = nil;
1813 free(cls->ext->propertyLists);
1814 cls->ext->propertyLists = newarray;
1815 }
1816
1817 return YES;
1818 }
1819
1820
1821 /***********************************************************************
1822 * class_addProperty
1823 * Adds a property to a class. Returns NO if the proeprty already exists.
1824 * Locking: acquires classLock
1825 **********************************************************************/
1826 static bool
1827 _class_addProperty(Class cls, const char *name,
1828 const objc_property_attribute_t *attrs, unsigned int count,
1829 bool replace)
1830 {
1831 if (!cls) return NO;
1832 if (!name) return NO;
1833
1834 old_property *prop = oldproperty(class_getProperty(cls, name));
1835 if (prop && !replace) {
1836 // already exists, refuse to replace
1837 return NO;
1838 }
1839 else if (prop) {
1840 // replace existing
1841 mutex_locker_t lock(classLock);
1842 try_free(prop->attributes);
1843 prop->attributes = copyPropertyAttributeString(attrs, count);
1844 return YES;
1845 }
1846 else {
1847 // add new
1848 old_property_list proplist;
1849 proplist.entsize = sizeof(old_property);
1850 proplist.count = 1;
1851 proplist.first.name = strdup(name);
1852 proplist.first.attributes = copyPropertyAttributeString(attrs, count);
1853
1854 return _class_addProperties(cls, &proplist);
1855 }
1856 }
1857
1858 BOOL
1859 class_addProperty(Class cls, const char *name,
1860 const objc_property_attribute_t *attrs, unsigned int n)
1861 {
1862 return _class_addProperty(cls, name, attrs, n, NO);
1863 }
1864
1865 void
1866 class_replaceProperty(Class cls, const char *name,
1867 const objc_property_attribute_t *attrs, unsigned int n)
1868 {
1869 _class_addProperty(cls, name, attrs, n, YES);
1870 }
1871
1872
1873 /***********************************************************************
1874 * class_copyProtocolList. Returns a heap block containing the
1875 * protocols implemented by the class, or nil if the class
1876 * implements no protocols. Caller must free the block.
1877 * Does not copy any superclass's protocols.
1878 **********************************************************************/
1879 Protocol * __unsafe_unretained *
1880 class_copyProtocolList(Class cls, unsigned int *outCount)
1881 {
1882 old_protocol_list *plist;
1883 Protocol **result = nil;
1884 unsigned int count = 0;
1885 unsigned int p;
1886
1887 if (!cls) {
1888 if (outCount) *outCount = 0;
1889 return nil;
1890 }
1891
1892 mutex_locker_t lock(classLock);
1893
1894 for (plist = cls->protocols; plist != nil; plist = plist->next) {
1895 count += (int)plist->count;
1896 }
1897
1898 if (count > 0) {
1899 result = (Protocol **)malloc((count+1) * sizeof(Protocol *));
1900
1901 for (p = 0, plist = cls->protocols;
1902 plist != nil;
1903 plist = plist->next)
1904 {
1905 int i;
1906 for (i = 0; i < plist->count; i++) {
1907 result[p++] = (Protocol *)plist->list[i];
1908 }
1909 }
1910 result[p] = nil;
1911 }
1912
1913 if (outCount) *outCount = count;
1914 return result;
1915 }
1916
1917
1918 /***********************************************************************
1919 * class_getProperty. Return the named property.
1920 **********************************************************************/
1921 objc_property_t class_getProperty(Class cls, const char *name)
1922 {
1923 if (!cls || !name) return nil;
1924
1925 mutex_locker_t lock(classLock);
1926
1927 for (; cls; cls = cls->superclass) {
1928 uintptr_t iterator = 0;
1929 old_property_list *plist;
1930 while ((plist = nextPropertyList(cls, &iterator))) {
1931 uint32_t i;
1932 for (i = 0; i < plist->count; i++) {
1933 old_property *p = property_list_nth(plist, i);
1934 if (0 == strcmp(name, p->name)) {
1935 return (objc_property_t)p;
1936 }
1937 }
1938 }
1939 }
1940
1941 return nil;
1942 }
1943
1944
1945 /***********************************************************************
1946 * class_copyPropertyList. Returns a heap block containing the
1947 * properties declared in the class, or nil if the class
1948 * declares no properties. Caller must free the block.
1949 * Does not copy any superclass's properties.
1950 **********************************************************************/
1951 objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
1952 {
1953 old_property_list *plist;
1954 uintptr_t iterator = 0;
1955 old_property **result = nil;
1956 unsigned int count = 0;
1957 unsigned int p, i;
1958
1959 if (!cls) {
1960 if (outCount) *outCount = 0;
1961 return nil;
1962 }
1963
1964 mutex_locker_t lock(classLock);
1965
1966 iterator = 0;
1967 while ((plist = nextPropertyList(cls, &iterator))) {
1968 count += plist->count;
1969 }
1970
1971 if (count > 0) {
1972 result = (old_property **)malloc((count+1) * sizeof(old_property *));
1973
1974 p = 0;
1975 iterator = 0;
1976 while ((plist = nextPropertyList(cls, &iterator))) {
1977 for (i = 0; i < plist->count; i++) {
1978 result[p++] = property_list_nth(plist, i);
1979 }
1980 }
1981 result[p] = nil;
1982 }
1983
1984 if (outCount) *outCount = count;
1985 return (objc_property_t *)result;
1986 }
1987
1988
1989 /***********************************************************************
1990 * class_copyMethodList. Returns a heap block containing the
1991 * methods implemented by the class, or nil if the class
1992 * implements no methods. Caller must free the block.
1993 * Does not copy any superclass's methods.
1994 **********************************************************************/
1995 Method *class_copyMethodList(Class cls, unsigned int *outCount)
1996 {
1997 old_method_list *mlist;
1998 void *iterator = nil;
1999 Method *result = nil;
2000 unsigned int count = 0;
2001 unsigned int m;
2002
2003 if (!cls) {
2004 if (outCount) *outCount = 0;
2005 return nil;
2006 }
2007
2008 mutex_locker_t lock(methodListLock);
2009
2010 iterator = nil;
2011 while ((mlist = nextMethodList(cls, &iterator))) {
2012 count += mlist->method_count;
2013 }
2014
2015 if (count > 0) {
2016 result = (Method *)malloc((count+1) * sizeof(Method));
2017
2018 m = 0;
2019 iterator = nil;
2020 while ((mlist = nextMethodList(cls, &iterator))) {
2021 int i;
2022 for (i = 0; i < mlist->method_count; i++) {
2023 Method aMethod = (Method)&mlist->method_list[i];
2024 if (ignoreSelector(method_getName(aMethod))) {
2025 count--;
2026 continue;
2027 }
2028 result[m++] = aMethod;
2029 }
2030 }
2031 result[m] = nil;
2032 }
2033
2034 if (outCount) *outCount = count;
2035 return result;
2036 }
2037
2038
2039 /***********************************************************************
2040 * class_copyIvarList. Returns a heap block containing the
2041 * ivars declared in the class, or nil if the class
2042 * declares no ivars. Caller must free the block.
2043 * Does not copy any superclass's ivars.
2044 **********************************************************************/
2045 Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
2046 {
2047 Ivar *result = nil;
2048 unsigned int count = 0;
2049 int i;
2050
2051 if (!cls) {
2052 if (outCount) *outCount = 0;
2053 return nil;
2054 }
2055
2056 if (cls->ivars) {
2057 count = cls->ivars->ivar_count;
2058 }
2059
2060 if (count > 0) {
2061 result = (Ivar *)malloc((count+1) * sizeof(Ivar));
2062
2063 for (i = 0; i < cls->ivars->ivar_count; i++) {
2064 result[i] = (Ivar)&cls->ivars->ivar_list[i];
2065 }
2066 result[i] = nil;
2067 }
2068
2069 if (outCount) *outCount = count;
2070 return result;
2071 }
2072
2073
2074 /***********************************************************************
2075 * objc_allocateClass.
2076 **********************************************************************/
2077
2078 void set_superclass(Class cls, Class supercls, bool cls_is_new)
2079 {
2080 Class meta = cls->ISA();
2081
2082 if (supercls) {
2083 cls->superclass = supercls;
2084 meta->superclass = supercls->ISA();
2085 meta->initIsa(supercls->ISA()->ISA());
2086
2087 // Propagate C++ cdtors from superclass.
2088 if (supercls->info & CLS_HAS_CXX_STRUCTORS) {
2089 if (cls_is_new) cls->info |= CLS_HAS_CXX_STRUCTORS;
2090 else cls->setInfo(CLS_HAS_CXX_STRUCTORS);
2091 }
2092
2093 // Superclass is no longer a leaf for cache flushing
2094 if (supercls->info & CLS_LEAF) {
2095 supercls->clearInfo(CLS_LEAF);
2096 supercls->ISA()->clearInfo(CLS_LEAF);
2097 }
2098 } else {
2099 cls->superclass = Nil; // superclass of root class is nil
2100 meta->superclass = cls; // superclass of root metaclass is root class
2101 meta->initIsa(meta); // metaclass of root metaclass is root metaclass
2102
2103 // Root class is never a leaf for cache flushing, because the
2104 // root metaclass is a subclass. (This could be optimized, but
2105 // is too uncommon to bother.)
2106 cls->clearInfo(CLS_LEAF);
2107 meta->clearInfo(CLS_LEAF);
2108 }
2109 }
2110
2111 // &UnsetLayout is the default ivar layout during class construction
2112 static const uint8_t UnsetLayout = 0;
2113
2114 Class objc_initializeClassPair(Class supercls, const char *name, Class cls, Class meta)
2115 {
2116 // Connect to superclasses and metaclasses
2117 cls->initIsa(meta);
2118 set_superclass(cls, supercls, YES);
2119
2120 // Set basic info
2121 cls->name = strdup(name);
2122 meta->name = strdup(name);
2123 cls->version = 0;
2124 meta->version = 7;
2125 cls->info = CLS_CLASS | CLS_CONSTRUCTING | CLS_EXT | CLS_LEAF;
2126 meta->info = CLS_META | CLS_CONSTRUCTING | CLS_EXT | CLS_LEAF;
2127
2128 // Set instance size based on superclass.
2129 if (supercls) {
2130 cls->instance_size = supercls->instance_size;
2131 meta->instance_size = supercls->ISA()->instance_size;
2132 } else {
2133 cls->instance_size = sizeof(Class); // just an isa
2134 meta->instance_size = sizeof(objc_class);
2135 }
2136
2137 // No ivars. No methods. Empty cache. No protocols. No layout. Empty ext.
2138 cls->ivars = nil;
2139 cls->methodLists = nil;
2140 cls->cache = (Cache)&_objc_empty_cache;
2141 cls->protocols = nil;
2142 cls->ivar_layout = &UnsetLayout;
2143 cls->ext = nil;
2144 allocateExt(cls);
2145 cls->ext->weak_ivar_layout = &UnsetLayout;
2146
2147 meta->ivars = nil;
2148 meta->methodLists = nil;
2149 meta->cache = (Cache)&_objc_empty_cache;
2150 meta->protocols = nil;
2151 meta->ext = nil;
2152
2153 return cls;
2154 }
2155
2156 Class objc_allocateClassPair(Class supercls, const char *name,
2157 size_t extraBytes)
2158 {
2159 Class cls, meta;
2160
2161 if (objc_getClass(name)) return nil;
2162 // fixme reserve class name against simultaneous allocation
2163
2164 if (supercls && (supercls->info & CLS_CONSTRUCTING)) {
2165 // Can't make subclass of an in-construction class
2166 return nil;
2167 }
2168
2169 // Allocate new classes.
2170 if (supercls) {
2171 cls = _calloc_class(supercls->ISA()->alignedInstanceSize() + extraBytes);
2172 meta = _calloc_class(supercls->ISA()->ISA()->alignedInstanceSize() + extraBytes);
2173 } else {
2174 cls = _calloc_class(sizeof(objc_class) + extraBytes);
2175 meta = _calloc_class(sizeof(objc_class) + extraBytes);
2176 }
2177
2178
2179 objc_initializeClassPair(supercls, name, cls, meta);
2180
2181 return cls;
2182 }
2183
2184
2185 void objc_registerClassPair(Class cls)
2186 {
2187 if ((cls->info & CLS_CONSTRUCTED) ||
2188 (cls->ISA()->info & CLS_CONSTRUCTED))
2189 {
2190 _objc_inform("objc_registerClassPair: class '%s' was already "
2191 "registered!", cls->name);
2192 return;
2193 }
2194
2195 if (!(cls->info & CLS_CONSTRUCTING) ||
2196 !(cls->ISA()->info & CLS_CONSTRUCTING))
2197 {
2198 _objc_inform("objc_registerClassPair: class '%s' was not "
2199 "allocated with objc_allocateClassPair!", cls->name);
2200 return;
2201 }
2202
2203 if (ISMETA(cls)) {
2204 _objc_inform("objc_registerClassPair: class '%s' is a metaclass, "
2205 "not a class!", cls->name);
2206 return;
2207 }
2208
2209 mutex_locker_t lock(classLock);
2210
2211 // Build ivar layouts
2212 if (UseGC) {
2213 if (cls->ivar_layout != &UnsetLayout) {
2214 // Class builder already called class_setIvarLayout.
2215 }
2216 else if (!cls->superclass) {
2217 // Root class. Scan conservatively (should be isa ivar only).
2218 cls->ivar_layout = nil;
2219 }
2220 else if (cls->ivars == nil) {
2221 // No local ivars. Use superclass's layout.
2222 cls->ivar_layout =
2223 ustrdupMaybeNil(cls->superclass->ivar_layout);
2224 }
2225 else {
2226 // Has local ivars. Build layout based on superclass.
2227 Class supercls = cls->superclass;
2228 const uint8_t *superlayout =
2229 class_getIvarLayout(supercls);
2230 layout_bitmap bitmap =
2231 layout_bitmap_create(superlayout, supercls->instance_size,
2232 cls->instance_size, NO);
2233 int i;
2234 for (i = 0; i < cls->ivars->ivar_count; i++) {
2235 old_ivar *iv = &cls->ivars->ivar_list[i];
2236 layout_bitmap_set_ivar(bitmap, iv->ivar_type, iv->ivar_offset);
2237 }
2238 cls->ivar_layout = layout_string_create(bitmap);
2239 layout_bitmap_free(bitmap);
2240 }
2241
2242 if (cls->ext->weak_ivar_layout != &UnsetLayout) {
2243 // Class builder already called class_setWeakIvarLayout.
2244 }
2245 else if (!cls->superclass) {
2246 // Root class. No weak ivars (should be isa ivar only)
2247 cls->ext->weak_ivar_layout = nil;
2248 }
2249 else if (cls->ivars == nil) {
2250 // No local ivars. Use superclass's layout.
2251 const uint8_t *weak =
2252 class_getWeakIvarLayout(cls->superclass);
2253 cls->ext->weak_ivar_layout = ustrdupMaybeNil(weak);
2254 }
2255 else {
2256 // Has local ivars. Build layout based on superclass.
2257 // No way to add weak ivars yet.
2258 const uint8_t *weak =
2259 class_getWeakIvarLayout(cls->superclass);
2260 cls->ext->weak_ivar_layout = ustrdupMaybeNil(weak);
2261 }
2262 }
2263
2264 // Clear "under construction" bit, set "done constructing" bit
2265 cls->info &= ~CLS_CONSTRUCTING;
2266 cls->ISA()->info &= ~CLS_CONSTRUCTING;
2267 cls->info |= CLS_CONSTRUCTED;
2268 cls->ISA()->info |= CLS_CONSTRUCTED;
2269
2270 NXHashInsertIfAbsent(class_hash, cls);
2271 objc_addRegisteredClass(cls);
2272 //objc_addRegisteredClass(cls->ISA()); if we ever allocate classes from GC
2273 }
2274
2275
2276 Class objc_duplicateClass(Class original, const char *name, size_t extraBytes)
2277 {
2278 unsigned int count, i;
2279 old_method **originalMethods;
2280 old_method_list *duplicateMethods;
2281 // Don't use sizeof(objc_class) here because
2282 // instance_size has historically contained two extra words,
2283 // and instance_size is what objc_getIndexedIvars() actually uses.
2284 Class duplicate =
2285 _calloc_class(original->ISA()->alignedInstanceSize() + extraBytes);
2286
2287 duplicate->initIsa(original->ISA());
2288 duplicate->superclass = original->superclass;
2289 duplicate->name = strdup(name);
2290 duplicate->version = original->version;
2291 duplicate->info = original->info & (CLS_CLASS|CLS_META|CLS_INITIALIZED|CLS_JAVA_HYBRID|CLS_JAVA_CLASS|CLS_HAS_CXX_STRUCTORS|CLS_HAS_LOAD_METHOD);
2292 duplicate->instance_size = original->instance_size;
2293 duplicate->ivars = original->ivars;
2294 // methodLists handled below
2295 duplicate->cache = (Cache)&_objc_empty_cache;
2296 duplicate->protocols = original->protocols;
2297 if (original->info & CLS_EXT) {
2298 duplicate->info |= original->info & (CLS_EXT|CLS_NO_PROPERTY_ARRAY);
2299 duplicate->ivar_layout = original->ivar_layout;
2300 if (original->ext) {
2301 duplicate->ext = (old_class_ext *)malloc(original->ext->size);
2302 memcpy(duplicate->ext, original->ext, original->ext->size);
2303 } else {
2304 duplicate->ext = nil;
2305 }
2306 }
2307
2308 // Method lists are deep-copied so they can be stomped.
2309 originalMethods = (old_method **)class_copyMethodList(original, &count);
2310 if (originalMethods) {
2311 duplicateMethods = (old_method_list *)
2312 calloc(sizeof(old_method_list) +
2313 (count-1)*sizeof(old_method), 1);
2314 duplicateMethods->obsolete = fixed_up_method_list;
2315 duplicateMethods->method_count = count;
2316 for (i = 0; i < count; i++) {
2317 duplicateMethods->method_list[i] = *(originalMethods[i]);
2318 }
2319 duplicate->methodLists = (old_method_list **)duplicateMethods;
2320 duplicate->info |= CLS_NO_METHOD_ARRAY;
2321 free(originalMethods);
2322 }
2323
2324 mutex_locker_t lock(classLock);
2325 NXHashInsert(class_hash, duplicate);
2326 objc_addRegisteredClass(duplicate);
2327
2328 return duplicate;
2329 }
2330
2331
2332 void objc_disposeClassPair(Class cls)
2333 {
2334 if (!(cls->info & (CLS_CONSTRUCTED|CLS_CONSTRUCTING)) ||
2335 !(cls->ISA()->info & (CLS_CONSTRUCTED|CLS_CONSTRUCTING)))
2336 {
2337 // class not allocated with objc_allocateClassPair
2338 // disposing still-unregistered class is OK!
2339 _objc_inform("objc_disposeClassPair: class '%s' was not "
2340 "allocated with objc_allocateClassPair!", cls->name);
2341 return;
2342 }
2343
2344 if (ISMETA(cls)) {
2345 _objc_inform("objc_disposeClassPair: class '%s' is a metaclass, "
2346 "not a class!", cls->name);
2347 return;
2348 }
2349
2350 mutex_locker_t lock(classLock);
2351 NXHashRemove(class_hash, cls);
2352 objc_removeRegisteredClass(cls);
2353 unload_class(cls->ISA());
2354 unload_class(cls);
2355 }
2356
2357
2358 /***********************************************************************
2359 * objc_constructInstance
2360 * Creates an instance of `cls` at the location pointed to by `bytes`.
2361 * `bytes` must point to at least class_getInstanceSize(cls) bytes of
2362 * well-aligned zero-filled memory.
2363 * The new object's isa is set. Any C++ constructors are called.
2364 * Returns `bytes` if successful. Returns nil if `cls` or `bytes` is
2365 * nil, or if C++ constructors fail.
2366 **********************************************************************/
2367 id
2368 objc_constructInstance(Class cls, void *bytes)
2369 {
2370 if (!cls || !bytes) return nil;
2371
2372 id obj = (id)bytes;
2373
2374 obj->initIsa(cls);
2375
2376 if (cls->hasCxxCtor()) {
2377 return object_cxxConstructFromClass(obj, cls);
2378 } else {
2379 return obj;
2380 }
2381 }
2382
2383
2384 /***********************************************************************
2385 * _class_createInstanceFromZone. Allocate an instance of the
2386 * specified class with the specified number of bytes for indexed
2387 * variables, in the specified zone. The isa field is set to the
2388 * class, C++ default constructors are called, and all other fields are zeroed.
2389 **********************************************************************/
2390 id
2391 _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone)
2392 {
2393 void *bytes;
2394 size_t size;
2395
2396 // Can't create something for nothing
2397 if (!cls) return nil;
2398
2399 // Allocate and initialize
2400 size = cls->alignedInstanceSize() + extraBytes;
2401
2402 // CF requires all objects be at least 16 bytes.
2403 if (size < 16) size = 16;
2404
2405 #if SUPPORT_GC
2406 if (UseGC) {
2407 bytes = auto_zone_allocate_object(gc_zone, size,
2408 AUTO_OBJECT_SCANNED, 0, 1);
2409 } else
2410 #endif
2411 if (zone) {
2412 bytes = malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
2413 } else {
2414 bytes = calloc(1, size);
2415 }
2416
2417 return objc_constructInstance(cls, bytes);
2418 }
2419
2420
2421 /***********************************************************************
2422 * _class_createInstance. Allocate an instance of the specified
2423 * class with the specified number of bytes for indexed variables, in
2424 * the default zone, using _class_createInstanceFromZone.
2425 **********************************************************************/
2426 static id _class_createInstance(Class cls, size_t extraBytes)
2427 {
2428 return _class_createInstanceFromZone (cls, extraBytes, nil);
2429 }
2430
2431
2432 static id _object_copyFromZone(id oldObj, size_t extraBytes, void *zone)
2433 {
2434 id obj;
2435 size_t size;
2436
2437 if (!oldObj) return nil;
2438
2439 obj = (*_zoneAlloc)(oldObj->ISA(), extraBytes, zone);
2440 size = oldObj->ISA()->alignedInstanceSize() + extraBytes;
2441
2442 // fixme need C++ copy constructor
2443 objc_memmove_collectable(obj, oldObj, size);
2444
2445 #if SUPPORT_GC
2446 if (UseGC) gc_fixup_weakreferences(obj, oldObj);
2447 #endif
2448
2449 return obj;
2450 }
2451
2452
2453 /***********************************************************************
2454 * objc_destructInstance
2455 * Destroys an instance without freeing memory.
2456 * Calls C++ destructors.
2457 * Removes associative references.
2458 * Returns `obj`. Does nothing if `obj` is nil.
2459 * Be warned that GC DOES NOT CALL THIS. If you edit this, also edit finalize.
2460 * CoreFoundation and other clients do call this under GC.
2461 **********************************************************************/
2462 void *objc_destructInstance(id obj)
2463 {
2464 if (obj) {
2465 Class isa = obj->getIsa();
2466
2467 if (isa->hasCxxDtor()) {
2468 object_cxxDestruct(obj);
2469 }
2470
2471 if (isa->instancesHaveAssociatedObjects()) {
2472 _object_remove_assocations(obj);
2473 }
2474
2475 if (!UseGC) objc_clear_deallocating(obj);
2476 }
2477
2478 return obj;
2479 }
2480
2481 static id
2482 _object_dispose(id anObject)
2483 {
2484 if (anObject==nil) return nil;
2485
2486 objc_destructInstance(anObject);
2487
2488 #if SUPPORT_GC
2489 if (UseGC) {
2490 auto_zone_retain(gc_zone, anObject); // gc free expects rc==1
2491 } else
2492 #endif
2493 {
2494 // only clobber isa for non-gc
2495 anObject->initIsa(_objc_getFreedObjectClass ());
2496 }
2497 free(anObject);
2498 return nil;
2499 }
2500
2501 static id _object_copy(id oldObj, size_t extraBytes)
2502 {
2503 void *z = malloc_zone_from_ptr(oldObj);
2504 return _object_copyFromZone(oldObj, extraBytes,
2505 z ? z : malloc_default_zone());
2506 }
2507
2508 static id _object_reallocFromZone(id anObject, size_t nBytes, void *zone)
2509 {
2510 id newObject;
2511 Class tmp;
2512
2513 if (anObject == nil)
2514 __objc_error(nil, "reallocating nil object");
2515
2516 if (anObject->ISA() == _objc_getFreedObjectClass ())
2517 __objc_error(anObject, "reallocating freed object");
2518
2519 if (nBytes < anObject->ISA()->alignedInstanceSize())
2520 __objc_error(anObject, "(%s, %zu) requested size too small",
2521 object_getClassName(anObject), nBytes);
2522
2523 // fixme need C++ copy constructor
2524 // fixme GC copy
2525 // Make sure not to modify space that has been declared free
2526 tmp = anObject->ISA();
2527 anObject->initIsa(_objc_getFreedObjectClass ());
2528 newObject = (id)malloc_zone_realloc((malloc_zone_t *)zone, anObject, nBytes);
2529 if (newObject) {
2530 newObject->initIsa(tmp);
2531 } else {
2532 // realloc failed, anObject is still alive
2533 anObject->initIsa(tmp);
2534 }
2535 return newObject;
2536 }
2537
2538
2539 static id _object_realloc(id anObject, size_t nBytes)
2540 {
2541 void *z = malloc_zone_from_ptr(anObject);
2542 return _object_reallocFromZone(anObject,
2543 nBytes,
2544 z ? z : malloc_default_zone());
2545 }
2546
2547 id (*_alloc)(Class, size_t) = _class_createInstance;
2548 id (*_copy)(id, size_t) = _object_copy;
2549 id (*_realloc)(id, size_t) = _object_realloc;
2550 id (*_dealloc)(id) = _object_dispose;
2551 id (*_zoneAlloc)(Class, size_t, void *) = _class_createInstanceFromZone;
2552 id (*_zoneCopy)(id, size_t, void *) = _object_copyFromZone;
2553 id (*_zoneRealloc)(id, size_t, void *) = _object_reallocFromZone;
2554 void (*_error)(id, const char *, va_list) = _objc_error;
2555
2556
2557 id class_createInstance(Class cls, size_t extraBytes)
2558 {
2559 if (UseGC) {
2560 return _class_createInstance(cls, extraBytes);
2561 } else {
2562 return (*_alloc)(cls, extraBytes);
2563 }
2564 }
2565
2566 id class_createInstanceFromZone(Class cls, size_t extraBytes, void *z)
2567 {
2568 OBJC_WARN_DEPRECATED;
2569 if (UseGC) {
2570 return _class_createInstanceFromZone(cls, extraBytes, z);
2571 } else {
2572 return (*_zoneAlloc)(cls, extraBytes, z);
2573 }
2574 }
2575
2576 unsigned class_createInstances(Class cls, size_t extraBytes,
2577 id *results, unsigned num_requested)
2578 {
2579 if (UseGC || _alloc == &_class_createInstance) {
2580 return _class_createInstancesFromZone(cls, extraBytes, nil,
2581 results, num_requested);
2582 } else {
2583 // _alloc in use, which isn't understood by the batch allocator
2584 return 0;
2585 }
2586 }
2587
2588 id object_copy(id obj, size_t extraBytes)
2589 {
2590 if (UseGC) return _object_copy(obj, extraBytes);
2591 else return (*_copy)(obj, extraBytes);
2592 }
2593
2594 id object_copyFromZone(id obj, size_t extraBytes, void *z)
2595 {
2596 OBJC_WARN_DEPRECATED;
2597 if (UseGC) return _object_copyFromZone(obj, extraBytes, z);
2598 else return (*_zoneCopy)(obj, extraBytes, z);
2599 }
2600
2601 id object_dispose(id obj)
2602 {
2603 if (UseGC) return _object_dispose(obj);
2604 else return (*_dealloc)(obj);
2605 }
2606
2607 id object_realloc(id obj, size_t nBytes)
2608 {
2609 OBJC_WARN_DEPRECATED;
2610 if (UseGC) return _object_realloc(obj, nBytes);
2611 else return (*_realloc)(obj, nBytes);
2612 }
2613
2614 id object_reallocFromZone(id obj, size_t nBytes, void *z)
2615 {
2616 OBJC_WARN_DEPRECATED;
2617 if (UseGC) return _object_reallocFromZone(obj, nBytes, z);
2618 else return (*_zoneRealloc)(obj, nBytes, z);
2619 }
2620
2621
2622 /***********************************************************************
2623 * object_getIndexedIvars.
2624 **********************************************************************/
2625 void *object_getIndexedIvars(id obj)
2626 {
2627 // ivars are tacked onto the end of the object
2628 if (!obj) return nil;
2629 if (obj->isTaggedPointer()) return nil;
2630 return ((char *) obj) + obj->ISA()->alignedInstanceSize();
2631 }
2632
2633
2634 // ProKit SPI
2635 Class class_setSuperclass(Class cls, Class newSuper)
2636 {
2637 Class oldSuper = cls->superclass;
2638 set_superclass(cls, newSuper, NO);
2639 flush_caches(cls, YES);
2640 return oldSuper;
2641 }
2642 #endif