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