]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-class-old.m
objc4-371.tar.gz
[apple/objc4.git] / runtime / objc-class-old.m
1 /*
2 * Copyright (c) 1999-2007 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 #define OLD 1
32 #import "objc-private.h"
33 #import "objc-rtp.h"
34 #import "hashtable2.h"
35 #import "maptable.h"
36
37 #include <sys/param.h>
38 #include <assert.h>
39
40 // Lock for method list access and modification.
41 // Protects methodLists fields, method arrays, and CLS_NO_METHOD_ARRAY bits.
42 // Classes not yet in use do not need to take this lock.
43 __private_extern__ OBJC_DECLARE_LOCK(methodListLock);
44
45
46 // Freed objects have their isa set to point to this dummy class.
47 // This avoids the need to check for Nil classes in the messenger.
48 static const struct old_class freedObjectClass =
49 {
50 Nil, // isa
51 Nil, // super_class
52 "FREED(id)", // name
53 0, // version
54 0, // info
55 0, // instance_size
56 NULL, // ivars
57 NULL, // methodLists
58 (Cache) &_objc_empty_cache, // cache
59 NULL // protocols
60 };
61
62 static const struct old_class nonexistentObjectClass =
63 {
64 Nil, // isa
65 Nil, // super_class
66 "NONEXISTENT(id)", // name
67 0, // version
68 0, // info
69 0, // instance_size
70 NULL, // ivars
71 NULL, // methodLists
72 (Cache) &_objc_empty_cache, // cache
73 NULL // protocols
74 };
75
76
77 /***********************************************************************
78 * _class_getFreedObjectClass. Return a pointer to the dummy freed
79 * object class. Freed objects get their isa pointers replaced with
80 * a pointer to the freedObjectClass, so that we can catch usages of
81 * the freed object.
82 **********************************************************************/
83 __private_extern__ Class _class_getFreedObjectClass(void)
84 {
85 return (Class)&freedObjectClass;
86 }
87
88
89 /***********************************************************************
90 * _class_getNonexistentClass. Return a pointer to the dummy nonexistent
91 * object class. This is used when, for example, mapping the class
92 * refs for an image, and the class can not be found, so that we can
93 * catch later uses of the non-existent class.
94 **********************************************************************/
95 __private_extern__ Class _class_getNonexistentObjectClass(void)
96 {
97 return (Class)&nonexistentObjectClass;
98 }
99
100
101 /***********************************************************************
102 * _objc_getFreedObjectClass. Return a pointer to the dummy freed
103 * object class. Freed objects get their isa pointers replaced with
104 * a pointer to the freedObjectClass, so that we can catch usages of
105 * the freed object.
106 **********************************************************************/
107 Class _objc_getFreedObjectClass(void)
108 {
109 return _class_getFreedObjectClass();
110 }
111
112
113 static void allocateExt(struct old_class *cls)
114 {
115 if (! (cls->info & CLS_EXT)) {
116 _objc_inform("class '%s' needs to be recompiled", cls->name);
117 return;
118 }
119 if (!cls->ext) {
120 uint32_t size = (uint32_t)sizeof(struct old_class_ext);
121 cls->ext = _calloc_internal(size, 1);
122 cls->ext->size = size;
123 }
124 }
125
126
127 static inline struct old_method *_findNamedMethodInList(struct old_method_list * mlist, const char *meth_name) {
128 int i;
129 if (!mlist) return NULL;
130 for (i = 0; i < mlist->method_count; i++) {
131 struct old_method *m = &mlist->method_list[i];
132 if (*((const char *)m->method_name) == *meth_name && 0 == strcmp((const char *)(m->method_name), meth_name)) {
133 return m;
134 }
135 }
136 return NULL;
137 }
138
139
140 /***********************************************************************
141 * fixupSelectorsInMethodList
142 * Uniques selectors in the given method list.
143 * Also replaces imps for GC-ignored selectors
144 * The given method list must be non-NULL and not already fixed-up.
145 * If the class was loaded from a bundle:
146 * fixes up the given list in place with heap-allocated selector strings
147 * If the class was not from a bundle:
148 * allocates a copy of the method list, fixes up the copy, and returns
149 * the copy. The given list is unmodified.
150 *
151 * If cls is already in use, methodListLock must be held by the caller.
152 **********************************************************************/
153 static struct old_method_list *fixupSelectorsInMethodList(struct old_class *cls, struct old_method_list *mlist)
154 {
155 int i;
156 size_t size;
157 struct old_method *method;
158 struct old_method_list *old_mlist;
159
160 if ( ! mlist ) return NULL;
161 if ( mlist->obsolete != _OBJC_FIXED_UP ) {
162 BOOL isBundle = (cls->info & CLS_FROM_BUNDLE) ? YES : NO;
163 if (!isBundle) {
164 old_mlist = mlist;
165 size = sizeof(struct old_method_list) - sizeof(struct old_method) + old_mlist->method_count * sizeof(struct old_method);
166 mlist = _malloc_internal(size);
167 memmove(mlist, old_mlist, size);
168 } else {
169 // Mach-O bundles are fixed up in place.
170 // This prevents leaks when a bundle is unloaded.
171 }
172 sel_lock();
173 for ( i = 0; i < mlist->method_count; i += 1 ) {
174 method = &mlist->method_list[i];
175 method->method_name =
176 sel_registerNameNoLock((const char *)method->method_name, isBundle); // Always copy selector data from bundles.
177
178 if (method->method_name == (SEL)kRTAddress_ignoredSelector) {
179 method->method_imp = (IMP)&_objc_ignored_method;
180 }
181 }
182 sel_unlock();
183 mlist->obsolete = _OBJC_FIXED_UP;
184 }
185 return mlist;
186 }
187
188
189 /***********************************************************************
190 * nextMethodList
191 * Returns successive method lists from the given class.
192 * Method lists are returned in method search order (i.e. highest-priority
193 * implementations first).
194 * All necessary method list fixups are performed, so the
195 * returned method list is fully-constructed.
196 *
197 * If cls is already in use, methodListLock must be held by the caller.
198 * For full thread-safety, methodListLock must be continuously held by the
199 * caller across all calls to nextMethodList(). If the lock is released,
200 * the bad results listed in class_nextMethodList() may occur.
201 *
202 * void *iterator = NULL;
203 * struct old_method_list *mlist;
204 * OBJC_LOCK(&methodListLock);
205 * while ((mlist = nextMethodList(cls, &iterator))) {
206 * // do something with mlist
207 * }
208 * OBJC_UNLOCK(&methodListLock);
209 **********************************************************************/
210 static struct old_method_list *nextMethodList(struct old_class *cls,
211 void **it)
212 {
213 uintptr_t index = *(uintptr_t *)it;
214 struct old_method_list **resultp;
215
216 if (index == 0) {
217 // First call to nextMethodList.
218 if (!cls->methodLists) {
219 resultp = NULL;
220 } else if (cls->info & CLS_NO_METHOD_ARRAY) {
221 resultp = (struct old_method_list **)&cls->methodLists;
222 } else {
223 resultp = &cls->methodLists[0];
224 if (!*resultp || *resultp == END_OF_METHODS_LIST) {
225 resultp = NULL;
226 }
227 }
228 } else {
229 // Subsequent call to nextMethodList.
230 if (!cls->methodLists) {
231 resultp = NULL;
232 } else if (cls->info & CLS_NO_METHOD_ARRAY) {
233 resultp = NULL;
234 } else {
235 resultp = &cls->methodLists[index];
236 if (!*resultp || *resultp == END_OF_METHODS_LIST) {
237 resultp = NULL;
238 }
239 }
240 }
241
242 // resultp now is NULL, meaning there are no more method lists,
243 // OR the address of the method list pointer to fix up and return.
244
245 if (resultp) {
246 if (*resultp && (*resultp)->obsolete != _OBJC_FIXED_UP) {
247 *resultp = fixupSelectorsInMethodList(cls, *resultp);
248 }
249 *it = (void *)(index + 1);
250 return *resultp;
251 } else {
252 *it = 0;
253 return NULL;
254 }
255 }
256
257
258 /* These next three functions are the heart of ObjC method lookup.
259 * If the class is currently in use, methodListLock must be held by the caller.
260 */
261 static inline struct old_method *_findMethodInList(struct old_method_list * mlist, SEL sel) {
262 int i;
263 if (!mlist) return NULL;
264 for (i = 0; i < mlist->method_count; i++) {
265 struct old_method *m = &mlist->method_list[i];
266 if (m->method_name == sel) {
267 return m;
268 }
269 }
270 return NULL;
271 }
272
273 static inline struct old_method * _findMethodInClass(struct old_class *cls, SEL sel) __attribute__((always_inline));
274 static inline struct old_method * _findMethodInClass(struct old_class *cls, SEL sel) {
275 // Flattened version of nextMethodList(). The optimizer doesn't
276 // do a good job with hoisting the conditionals out of the loop.
277 // Conceptually, this looks like:
278 // while ((mlist = nextMethodList(cls, &iterator))) {
279 // struct old_method *m = _findMethodInList(mlist, sel);
280 // if (m) return m;
281 // }
282
283 if (!cls->methodLists) {
284 // No method lists.
285 return NULL;
286 }
287 else if (cls->info & CLS_NO_METHOD_ARRAY) {
288 // One method list.
289 struct old_method_list **mlistp;
290 mlistp = (struct old_method_list **)&cls->methodLists;
291 if ((*mlistp)->obsolete != _OBJC_FIXED_UP) {
292 *mlistp = fixupSelectorsInMethodList(cls, *mlistp);
293 }
294 return _findMethodInList(*mlistp, sel);
295 }
296 else {
297 // Multiple method lists.
298 struct old_method_list **mlistp;
299 for (mlistp = cls->methodLists;
300 *mlistp != NULL && *mlistp != END_OF_METHODS_LIST;
301 mlistp++)
302 {
303 struct old_method *m;
304 if ((*mlistp)->obsolete != _OBJC_FIXED_UP) {
305 *mlistp = fixupSelectorsInMethodList(cls, *mlistp);
306 }
307 m = _findMethodInList(*mlistp, sel);
308 if (m) return m;
309 }
310 return NULL;
311 }
312 }
313
314 static inline struct old_method * _getMethod(struct old_class *cls, SEL sel) {
315 for (; cls; cls = cls->super_class) {
316 struct old_method *m;
317 m = _findMethodInClass(cls, sel);
318 if (m) return m;
319 }
320 return NULL;
321 }
322
323
324 // fixme for gc debugging temporary use
325 __private_extern__ IMP findIMPInClass(struct old_class *cls, SEL sel)
326 {
327 struct old_method *m = _findMethodInClass(cls, sel);
328 if (m) return m->method_imp;
329 else return NULL;
330 }
331
332
333
334 /***********************************************************************
335 * class_getVariable. Return the named instance variable.
336 **********************************************************************/
337 __private_extern__
338 Ivar _class_getVariable(Class cls_gen, const char *name)
339 {
340 struct old_class *cls = _class_asOld(cls_gen);
341
342 for (; cls != Nil; cls = cls->super_class) {
343 int i;
344
345 // Skip class having no ivars
346 if (!cls->ivars) continue;
347
348 for (i = 0; i < cls->ivars->ivar_count; i++) {
349 // Check this ivar's name. Be careful because the
350 // compiler generates ivar entries with NULL ivar_name
351 // (e.g. for anonymous bit fields).
352 struct old_ivar *ivar = &cls->ivars->ivar_list[i];
353 if (ivar->ivar_name && 0 == strcmp(name, ivar->ivar_name)) {
354 return (Ivar)ivar;
355 }
356 }
357 }
358
359 // Not found
360 return NULL;
361 }
362
363
364 /***********************************************************************
365 * class_getPropertyList. Return the class's property list
366 * Locking: classLock must be held by the caller
367 **********************************************************************/
368 static struct objc_property_list *
369 nextPropertyList(struct old_class *cls, uintptr_t *indexp)
370 {
371 struct objc_property_list *result = NULL;
372
373 OBJC_CHECK_LOCKED(&classLock);
374 if (! ((cls->info & CLS_EXT) && cls->ext)) {
375 // No class ext
376 result = NULL;
377 } else if (!cls->ext->propertyLists) {
378 // No property lists
379 result = NULL;
380 } else if (cls->info & CLS_NO_PROPERTY_ARRAY) {
381 // Only one property list
382 if (*indexp == 0) {
383 result = (struct objc_property_list *)cls->ext->propertyLists;
384 } else {
385 result = NULL;
386 }
387 } else {
388 // More than one property list
389 result = cls->ext->propertyLists[*indexp];
390 }
391
392 if (result) {
393 ++*indexp;
394 return result;
395 } else {
396 *indexp = 0;
397 return NULL;
398 }
399 }
400
401
402 /***********************************************************************
403 * class_getIvarLayout
404 * NULL means all-scanned. "" means non-scanned.
405 **********************************************************************/
406 const char *
407 class_getIvarLayout(Class cls_gen)
408 {
409 struct old_class *cls = _class_asOld(cls_gen);
410 if (cls && (cls->info & CLS_EXT)) {
411 return cls->ivar_layout;
412 } else {
413 return NULL; // conservative scan
414 }
415 }
416
417
418 /***********************************************************************
419 * class_getWeakIvarLayout
420 * NULL means no weak ivars.
421 **********************************************************************/
422 const char *
423 class_getWeakIvarLayout(Class cls_gen)
424 {
425 struct old_class *cls = _class_asOld(cls_gen);
426 if (cls && (cls->info & CLS_EXT) && cls->ext) {
427 return cls->ext->weak_ivar_layout;
428 } else {
429 return NULL; // no weak ivars
430 }
431 }
432
433
434 /***********************************************************************
435 * class_setIvarLayout
436 * NULL means all-scanned. "" means non-scanned.
437 **********************************************************************/
438 void class_setIvarLayout(Class cls_gen, const char *layout)
439 {
440 struct old_class *cls = _class_asOld(cls_gen);
441 if (!cls) return;
442
443 if (! (cls->info & CLS_EXT)) {
444 _objc_inform("class '%s' needs to be recompiled", cls->name);
445 return;
446 }
447
448 // fixme leak
449 cls->ivar_layout = layout ? _strdup_internal(layout) : NULL;
450 }
451
452
453 /***********************************************************************
454 * class_setWeakIvarLayout
455 * NULL means no weak ivars.
456 **********************************************************************/
457 void class_setWeakIvarLayout(Class cls_gen, const char *layout)
458 {
459 struct old_class *cls = _class_asOld(cls_gen);
460 if (!cls) return;
461
462 OBJC_LOCK(&classLock);
463
464 allocateExt(cls);
465
466 // fixme leak
467 cls->ext->weak_ivar_layout = layout ? _strdup_internal(layout) : NULL;
468
469 OBJC_UNLOCK(&classLock);
470 }
471
472
473 /***********************************************************************
474 * _class_changeInfo
475 * Atomically sets and clears some bits in cls's info field.
476 * set and clear must not overlap.
477 **********************************************************************/
478 __private_extern__ void _class_changeInfo(Class cls, long set, long clear)
479 {
480 struct old_class *old = _class_asOld(cls);
481 long newinfo;
482 long oldinfo;
483 do {
484 oldinfo = old->info;
485 newinfo = (oldinfo | set) & ~clear;
486 } while (! OSAtomicCompareAndSwapLong(oldinfo, newinfo, &old->info));
487 }
488
489
490 /***********************************************************************
491 * _class_getInfo
492 * Returns YES iff all set bits in get are also set in cls's info field.
493 **********************************************************************/
494 __private_extern__ BOOL _class_getInfo(Class cls, int get)
495 {
496 struct old_class *old = _class_asOld(cls);
497 return ((old->info & get) == get) ? YES : NO;
498 }
499
500
501 /***********************************************************************
502 * _class_setInfo
503 * Atomically sets some bits in cls's info field.
504 **********************************************************************/
505 __private_extern__ void _class_setInfo(Class cls, long set)
506 {
507 _class_changeInfo(cls, set, 0);
508 }
509
510
511 /***********************************************************************
512 * _class_clearInfo
513 * Atomically clears some bits in cls's info field.
514 **********************************************************************/
515 __private_extern__ void _class_clearInfo(Class cls, long clear)
516 {
517 _class_changeInfo(cls, 0, clear);
518 }
519
520
521 /***********************************************************************
522 * isInitializing
523 * Return YES if cls is currently being initialized.
524 * The initializing bit is stored in the metaclass only.
525 **********************************************************************/
526 __private_extern__ BOOL _class_isInitializing(Class cls)
527 {
528 return _class_getInfo(_class_getMeta(cls), CLS_INITIALIZING);
529 }
530
531
532 /***********************************************************************
533 * isInitialized
534 * Return YES if cls is already initialized.
535 * The initialized bit is stored in the metaclass only.
536 **********************************************************************/
537 __private_extern__ BOOL _class_isInitialized(Class cls)
538 {
539 return _class_getInfo(_class_getMeta(cls), CLS_INITIALIZED);
540 }
541
542
543 /***********************************************************************
544 * setInitializing
545 * Mark cls as initialization in progress.
546 **********************************************************************/
547 __private_extern__ void _class_setInitializing(Class cls)
548 {
549 _class_setInfo(_class_getMeta(cls), CLS_INITIALIZING);
550 }
551
552
553 /***********************************************************************
554 * setInitialized
555 * Atomically mark cls as initialized and not initializing.
556 **********************************************************************/
557 __private_extern__ void _class_setInitialized(Class cls)
558 {
559 _class_changeInfo(_class_getMeta(cls), CLS_INITIALIZED, CLS_INITIALIZING);
560 }
561
562
563 /***********************************************************************
564 * class_setVersion. Record the specified version with the class.
565 **********************************************************************/
566 void class_setVersion(Class cls, int version)
567 {
568 if (!cls) return;
569 cls->version = version;
570 }
571
572 /***********************************************************************
573 * class_getVersion. Return the version recorded with the class.
574 **********************************************************************/
575 int class_getVersion(Class cls)
576 {
577 if (!cls) return 0;
578 return (int)cls->version;
579 }
580
581
582 __private_extern__ Class _class_getMeta(Class cls)
583 {
584 if (_class_getInfo(cls, CLS_META)) return cls;
585 else return ((id)cls)->isa;
586 }
587
588 __private_extern__ BOOL _class_isMetaClass(Class cls)
589 {
590 if (!cls) return NO;
591 return _class_getInfo(cls, CLS_META);
592 }
593
594
595 /***********************************************************************
596 * _class_getNonMetaClass.
597 * Return the ordinary class for this class or metaclass.
598 * Used by +initialize.
599 **********************************************************************/
600 __private_extern__ Class _class_getNonMetaClass(Class cls)
601 {
602 // fixme ick
603 if (_class_isMetaClass(cls)) {
604 if (strncmp(_class_getName(cls), "_%", 2) == 0) {
605 // Posee's meta's name is smashed and isn't in the class_hash,
606 // so objc_getClass doesn't work.
607 char *baseName = strchr(_class_getName(cls), '%'); // get posee's real name
608 cls = objc_getClass(baseName);
609 } else {
610 cls = objc_getClass(_class_getName(cls));
611 }
612 assert(cls);
613 }
614
615 return cls;
616 }
617
618
619 __private_extern__ Class _class_getSuperclass(Class cls)
620 {
621 if (!cls) return nil;
622 return (Class)cls->super_class;
623 }
624
625
626 __private_extern__ Cache _class_getCache(Class cls)
627 {
628 return cls->cache;
629 }
630
631 __private_extern__ void _class_setCache(Class cls, Cache cache)
632 {
633 cls->cache = cache;
634 }
635
636 __private_extern__ size_t _class_getInstanceSize(Class cls)
637 {
638 if (!cls) return 0;
639 return cls->instance_size;
640 }
641
642 __private_extern__ const char * _class_getName(Class cls)
643 {
644 if (!cls) return "nil";
645 return cls->name;
646 }
647
648
649
650 __private_extern__ const char *_category_getName(Category cat)
651 {
652 return _category_asOld(cat)->category_name;
653 }
654
655 __private_extern__ const char *_category_getClassName(Category cat)
656 {
657 return _category_asOld(cat)->class_name;
658 }
659
660 __private_extern__ Class _category_getClass(Category cat)
661 {
662 return objc_getClass(_category_asOld(cat)->class_name);
663 }
664
665 __private_extern__ IMP _category_getLoadMethod(Category cat)
666 {
667 struct old_method_list *mlist = _category_asOld(cat)->class_methods;
668 if (mlist) {
669 return lookupNamedMethodInMethodList(mlist, "load");
670 } else {
671 return NULL;
672 }
673 }
674
675
676
677 /***********************************************************************
678 * class_nextMethodList.
679 * External version of nextMethodList().
680 *
681 * This function is not fully thread-safe. A series of calls to
682 * class_nextMethodList() may fail if methods are added to or removed
683 * from the class between calls.
684 * If methods are added between calls to class_nextMethodList(), it may
685 * return previously-returned method lists again, and may fail to return
686 * newly-added lists.
687 * If methods are removed between calls to class_nextMethodList(), it may
688 * omit surviving method lists or simply crash.
689 **********************************************************************/
690 OBJC_EXPORT struct objc_method_list *class_nextMethodList(Class cls, void **it)
691 {
692 struct old_method_list *result;
693
694 OBJC_WARN_DEPRECATED;
695
696 OBJC_LOCK(&methodListLock);
697 result = nextMethodList(_class_asOld(cls), it);
698 OBJC_UNLOCK(&methodListLock);
699 return (struct objc_method_list *)result;
700 }
701
702
703 /***********************************************************************
704 * class_addMethods.
705 *
706 * Formerly class_addInstanceMethods ()
707 **********************************************************************/
708 OBJC_EXPORT void class_addMethods(Class cls, struct objc_method_list *meths)
709 {
710 OBJC_WARN_DEPRECATED;
711
712 // Add the methods.
713 OBJC_LOCK(&methodListLock);
714 _objc_insertMethods(_class_asOld(cls), (struct old_method_list *)meths, NULL);
715 OBJC_UNLOCK(&methodListLock);
716
717 // Must flush when dynamically adding methods. No need to flush
718 // all the class method caches. If cls is a meta class, though,
719 // this will still flush it and any of its sub-meta classes.
720 flush_caches (cls, NO);
721 }
722
723
724 /***********************************************************************
725 * class_removeMethods.
726 **********************************************************************/
727 OBJC_EXPORT void class_removeMethods(Class cls, struct objc_method_list *meths)
728 {
729 OBJC_WARN_DEPRECATED;
730
731 // Remove the methods
732 OBJC_LOCK(&methodListLock);
733 _objc_removeMethods(_class_asOld(cls), (struct old_method_list *)meths);
734 OBJC_UNLOCK(&methodListLock);
735
736 // Must flush when dynamically removing methods. No need to flush
737 // all the class method caches. If cls is a meta class, though,
738 // this will still flush it and any of its sub-meta classes.
739 flush_caches (cls, NO);
740 }
741
742 /***********************************************************************
743 * lookupNamedMethodInMethodList
744 * Only called to find +load/-.cxx_construct/-.cxx_destruct methods,
745 * without fixing up the entire method list.
746 * The class is not yet in use, so methodListLock is not taken.
747 **********************************************************************/
748 __private_extern__ IMP lookupNamedMethodInMethodList(struct old_method_list *mlist, const char *meth_name)
749 {
750 struct old_method *m;
751 m = meth_name ? _findNamedMethodInList(mlist, meth_name) : NULL;
752 return (m ? m->method_imp : NULL);
753 }
754
755 __private_extern__ Method _class_getMethod(Class cls, SEL sel)
756 {
757 Method result;
758
759 OBJC_LOCK(&methodListLock);
760 result = (Method)_getMethod(_class_asOld(cls), sel);
761 OBJC_UNLOCK(&methodListLock);
762
763 return result;
764 }
765
766 __private_extern__ Method _class_getMethodNoSuper(Class cls, SEL sel)
767 {
768 Method result;
769
770 OBJC_LOCK(&methodListLock);
771 result = (Method)_findMethodInClass(_class_asOld(cls), sel);
772 OBJC_UNLOCK(&methodListLock);
773
774 return result;
775 }
776
777
778 BOOL class_conformsToProtocol(Class cls_gen, Protocol *proto_gen)
779 {
780 struct old_class *cls = oldcls(cls_gen);
781 struct old_protocol *proto = oldprotocol(proto_gen);
782
783 if (cls->isa->version >= 3) {
784 struct old_protocol_list *list;
785 for (list = cls->protocols; list != NULL; list = list->next) {
786 int i;
787 for (i = 0; i < list->count; i++) {
788 if (list->list[i] == proto) return YES;
789 if (protocol_conformsToProtocol((Protocol *)list->list[i], proto_gen)) return YES;
790 }
791 if (cls->isa->version <= 4) break;
792 }
793 }
794 return NO;
795 }
796
797
798 static NXMapTable * posed_class_hash = NULL;
799
800 /***********************************************************************
801 * objc_getOrigClass.
802 **********************************************************************/
803 __private_extern__ Class _objc_getOrigClass(const char *name)
804 {
805 Class ret;
806
807 // Look for class among the posers
808 ret = Nil;
809 OBJC_LOCK(&classLock);
810 if (posed_class_hash)
811 ret = (Class) NXMapGet (posed_class_hash, name);
812 OBJC_UNLOCK(&classLock);
813 if (ret)
814 return ret;
815
816 // Not a poser. Do a normal lookup.
817 ret = objc_getClass (name);
818 if (!ret)
819 _objc_inform ("class `%s' not linked into application", name);
820
821 return ret;
822 }
823
824 Class objc_getOrigClass(const char *name)
825 {
826 OBJC_WARN_DEPRECATED;
827 return _objc_getOrigClass(name);
828 }
829
830 /***********************************************************************
831 * _objc_addOrigClass. This function is only used from class_poseAs.
832 * Registers the original class names, before they get obscured by
833 * posing, so that [super ..] will work correctly from categories
834 * in posing classes and in categories in classes being posed for.
835 **********************************************************************/
836 static void _objc_addOrigClass (struct old_class *origClass)
837 {
838 OBJC_LOCK(&classLock);
839
840 // Create the poser's hash table on first use
841 if (!posed_class_hash)
842 {
843 posed_class_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype,
844 8,
845 _objc_internal_zone ());
846 }
847
848 // Add the named class iff it is not already there (or collides?)
849 if (NXMapGet (posed_class_hash, origClass->name) == 0)
850 NXMapInsert (posed_class_hash, origClass->name, origClass);
851
852 OBJC_UNLOCK(&classLock);
853 }
854
855
856 /***********************************************************************
857 * change_class_references
858 * Change classrefs and superclass pointers from original to imposter
859 * But if copy!=nil, don't change copy->super_class.
860 * If changeSuperRefs==YES, also change [super message] classrefs.
861 * Used by class_poseAs and objc_setFutureClass
862 * classLock must be locked.
863 **********************************************************************/
864 __private_extern__
865 void change_class_references(struct old_class *imposter,
866 struct old_class *original,
867 struct old_class *copy,
868 BOOL changeSuperRefs)
869 {
870 header_info *hInfo;
871 struct old_class *clsObject;
872 NXHashState state;
873
874 // Change all subclasses of the original to point to the imposter.
875 state = NXInitHashState (class_hash);
876 while (NXNextHashState (class_hash, &state, (void **) &clsObject))
877 {
878 while ((clsObject) && (clsObject != imposter) &&
879 (clsObject != copy))
880 {
881 if (clsObject->super_class == original)
882 {
883 clsObject->super_class = imposter;
884 clsObject->isa->super_class = imposter->isa;
885 // We must flush caches here!
886 break;
887 }
888
889 clsObject = clsObject->super_class;
890 }
891 }
892
893 // Replace the original with the imposter in all class refs
894 // Major loop - process all headers
895 for (hInfo = _objc_headerStart(); hInfo != NULL; hInfo = hInfo->next)
896 {
897 struct old_class **cls_refs;
898 size_t refCount;
899 unsigned int index;
900
901 // Fix class refs associated with this header
902 cls_refs = _getObjcClassRefs(hInfo, &refCount);
903 if (cls_refs) {
904 for (index = 0; index < refCount; index += 1) {
905 if (cls_refs[index] == original) {
906 cls_refs[index] = imposter;
907 }
908 }
909 }
910 }
911 }
912
913
914 /***********************************************************************
915 * class_poseAs.
916 *
917 * !!! class_poseAs () does not currently flush any caches.
918 **********************************************************************/
919 Class class_poseAs(Class imposter_gen, Class original_gen)
920 {
921 struct old_class *imposter = _class_asOld(imposter_gen);
922 struct old_class *original = _class_asOld(original_gen);
923 char * imposterNamePtr;
924 struct old_class * copy;
925
926 OBJC_WARN_DEPRECATED;
927
928 // Trivial case is easy
929 if (imposter_gen == original_gen)
930 return imposter_gen;
931
932 // Imposter must be an immediate subclass of the original
933 if (imposter->super_class != original) {
934 __objc_error(imposter_gen,
935 "[%s poseAs:%s]: target not immediate superclass",
936 imposter->name, original->name);
937 }
938
939 // Can't pose when you have instance variables (how could it work?)
940 if (imposter->ivars) {
941 __objc_error(imposter_gen,
942 "[%s poseAs:%s]: %s defines new instance variables",
943 imposter->name, original->name, imposter->name);
944 }
945
946 // Build a string to use to replace the name of the original class.
947 #define imposterNamePrefix "_%"
948 imposterNamePtr = _malloc_internal(strlen(original->name) + strlen(imposterNamePrefix) + 1);
949 strcpy(imposterNamePtr, imposterNamePrefix);
950 strcat(imposterNamePtr, original->name);
951 #undef imposterNamePrefix
952
953 // We lock the class hashtable, so we are thread safe with respect to
954 // calls to objc_getClass (). However, the class names are not
955 // changed atomically, nor are all of the subclasses updated
956 // atomically. I have ordered the operations so that you will
957 // never crash, but you may get inconsistent results....
958
959 // Register the original class so that [super ..] knows
960 // exactly which classes are the "original" classes.
961 _objc_addOrigClass (original);
962 _objc_addOrigClass (imposter);
963
964 // Copy the imposter, so that the imposter can continue
965 // its normal life in addition to changing the behavior of
966 // the original. As a hack we don't bother to copy the metaclass.
967 // For some reason we modify the original rather than the copy.
968 copy = _class_asOld((*_zoneAlloc)((Class)imposter->isa, sizeof(struct old_class), _objc_internal_zone()));
969 memmove(copy, imposter, sizeof(struct old_class));
970
971 OBJC_LOCK(&classLock);
972
973 // Remove both the imposter and the original class.
974 NXHashRemove (class_hash, imposter);
975 NXHashRemove (class_hash, original);
976
977 NXHashInsert (class_hash, copy);
978
979 // Mark the imposter as such
980 _class_setInfo((Class)imposter, CLS_POSING);
981 _class_setInfo((Class)imposter->isa, CLS_POSING);
982
983 // Change the name of the imposter to that of the original class.
984 imposter->name = original->name;
985 imposter->isa->name = original->isa->name;
986
987 // Also copy the version field to avoid archiving problems.
988 imposter->version = original->version;
989
990 // Change classrefs and superclass pointers
991 // Don't change copy->super_class
992 // Don't change [super ...] messages
993 change_class_references(imposter, original, copy, NO);
994
995 // Change the name of the original class.
996 original->name = imposterNamePtr + 1;
997 original->isa->name = imposterNamePtr;
998
999 // Restore the imposter and the original class with their new names.
1000 NXHashInsert (class_hash, imposter);
1001 NXHashInsert (class_hash, original);
1002
1003 OBJC_UNLOCK(&classLock);
1004
1005 return imposter_gen;
1006 }
1007
1008
1009 /***********************************************************************
1010 * flush_caches. Flush the instance and optionally class method caches
1011 * of cls and all its subclasses.
1012 *
1013 * Specifying Nil for the class "all classes."
1014 **********************************************************************/
1015 __private_extern__ void flush_caches(Class target_gen, BOOL flush_meta)
1016 {
1017 NXHashState state;
1018 struct old_class *target = _class_asOld(target_gen);
1019 struct old_class *clsObject;
1020 #ifdef OBJC_INSTRUMENTED
1021 unsigned int classesVisited;
1022 unsigned int subclassCount;
1023 #endif
1024
1025 OBJC_LOCK(&classLock);
1026 OBJC_LOCK(&cacheUpdateLock);
1027
1028 // Leaf classes are fastest because there are no subclass caches to flush.
1029 // fixme instrument
1030 if (target && (target->info & CLS_LEAF)) {
1031 _cache_flush ((Class)target);
1032
1033 if (!flush_meta) {
1034 OBJC_UNLOCK(&cacheUpdateLock);
1035 OBJC_UNLOCK(&classLock);
1036 return; // done
1037 } else if (target->isa && (target->isa->info & CLS_LEAF)) {
1038 _cache_flush ((Class)target->isa);
1039 OBJC_UNLOCK(&cacheUpdateLock);
1040 OBJC_UNLOCK(&classLock);
1041 return; // done
1042 } else {
1043 // Reset target and handle it by one of the methods below.
1044 target = target->isa;
1045 flush_meta = NO;
1046 // NOT done
1047 }
1048 }
1049
1050 state = NXInitHashState(class_hash);
1051
1052 // Handle nil and root instance class specially: flush all
1053 // instance and class method caches. Nice that this
1054 // loop is linear vs the N-squared loop just below.
1055 if (!target || !target->super_class)
1056 {
1057 #ifdef OBJC_INSTRUMENTED
1058 LinearFlushCachesCount += 1;
1059 classesVisited = 0;
1060 subclassCount = 0;
1061 #endif
1062 // Traverse all classes in the hash table
1063 while (NXNextHashState(class_hash, &state, (void**)&clsObject))
1064 {
1065 struct old_class *metaClsObject;
1066 #ifdef OBJC_INSTRUMENTED
1067 classesVisited += 1;
1068 #endif
1069
1070 // Skip class that is known not to be a subclass of this root
1071 // (the isa pointer of any meta class points to the meta class
1072 // of the root).
1073 // NOTE: When is an isa pointer of a hash tabled class ever nil?
1074 metaClsObject = clsObject->isa;
1075 if (target && metaClsObject && target->isa != metaClsObject->isa) {
1076 continue;
1077 }
1078
1079 #ifdef OBJC_INSTRUMENTED
1080 subclassCount += 1;
1081 #endif
1082
1083 _cache_flush ((Class)clsObject);
1084 if (flush_meta && metaClsObject != NULL) {
1085 _cache_flush ((Class)metaClsObject);
1086 }
1087 }
1088 #ifdef OBJC_INSTRUMENTED
1089 LinearFlushCachesVisitedCount += classesVisited;
1090 if (classesVisited > MaxLinearFlushCachesVisitedCount)
1091 MaxLinearFlushCachesVisitedCount = classesVisited;
1092 IdealFlushCachesCount += subclassCount;
1093 if (subclassCount > MaxIdealFlushCachesCount)
1094 MaxIdealFlushCachesCount = subclassCount;
1095 #endif
1096
1097 OBJC_UNLOCK(&cacheUpdateLock);
1098 OBJC_UNLOCK(&classLock);
1099 return;
1100 }
1101
1102 // Outer loop - flush any cache that could now get a method from
1103 // cls (i.e. the cache associated with cls and any of its subclasses).
1104 #ifdef OBJC_INSTRUMENTED
1105 NonlinearFlushCachesCount += 1;
1106 classesVisited = 0;
1107 subclassCount = 0;
1108 #endif
1109 while (NXNextHashState(class_hash, &state, (void**)&clsObject))
1110 {
1111 struct old_class *clsIter;
1112
1113 #ifdef OBJC_INSTRUMENTED
1114 NonlinearFlushCachesClassCount += 1;
1115 #endif
1116
1117 // Inner loop - Process a given class
1118 clsIter = clsObject;
1119 while (clsIter)
1120 {
1121
1122 #ifdef OBJC_INSTRUMENTED
1123 classesVisited += 1;
1124 #endif
1125 // Flush clsObject instance method cache if
1126 // clsObject is a subclass of cls, or is cls itself
1127 // Flush the class method cache if that was asked for
1128 if (clsIter == target)
1129 {
1130 #ifdef OBJC_INSTRUMENTED
1131 subclassCount += 1;
1132 #endif
1133 _cache_flush ((Class)clsObject);
1134 if (flush_meta)
1135 _cache_flush ((Class)clsObject->isa);
1136
1137 break;
1138
1139 }
1140
1141 // Flush clsObject class method cache if cls is
1142 // the meta class of clsObject or of one
1143 // of clsObject's superclasses
1144 else if (clsIter->isa == target)
1145 {
1146 #ifdef OBJC_INSTRUMENTED
1147 subclassCount += 1;
1148 #endif
1149 _cache_flush ((Class)clsObject->isa);
1150 break;
1151 }
1152
1153 // Move up superclass chain
1154 // else if (_class_isInitialized(clsIter))
1155 clsIter = clsIter->super_class;
1156
1157 // clsIter is not initialized, so its cache
1158 // must be empty. This happens only when
1159 // clsIter == clsObject, because
1160 // superclasses are initialized before
1161 // subclasses, and this loop traverses
1162 // from sub- to super- classes.
1163 // else
1164 // break;
1165 }
1166 }
1167 #ifdef OBJC_INSTRUMENTED
1168 NonlinearFlushCachesVisitedCount += classesVisited;
1169 if (classesVisited > MaxNonlinearFlushCachesVisitedCount)
1170 MaxNonlinearFlushCachesVisitedCount = classesVisited;
1171 IdealFlushCachesCount += subclassCount;
1172 if (subclassCount > MaxIdealFlushCachesCount)
1173 MaxIdealFlushCachesCount = subclassCount;
1174 #endif
1175
1176 OBJC_UNLOCK(&cacheUpdateLock);
1177 OBJC_UNLOCK(&classLock);
1178 }
1179
1180
1181 /***********************************************************************
1182 * flush_marked_caches. Flush the method cache of any class marked
1183 * CLS_FLUSH_CACHE (and all subclasses thereof)
1184 * fixme instrument
1185 **********************************************************************/
1186 __private_extern__ void flush_marked_caches(void)
1187 {
1188 struct old_class *cls;
1189 struct old_class *supercls;
1190 NXHashState state;
1191
1192 OBJC_LOCK(&classLock);
1193 OBJC_LOCK(&cacheUpdateLock);
1194
1195 state = NXInitHashState(class_hash);
1196 while (NXNextHashState(class_hash, &state, (void**)&cls)) {
1197 for (supercls = cls; supercls; supercls = supercls->super_class) {
1198 if (supercls->info & CLS_FLUSH_CACHE) {
1199 _cache_flush((Class)cls);
1200 break;
1201 }
1202 }
1203
1204 for (supercls = cls->isa; supercls; supercls = supercls->super_class) {
1205 if (supercls->info & CLS_FLUSH_CACHE) {
1206 _cache_flush((Class)cls->isa);
1207 break;
1208 }
1209 }
1210 }
1211
1212 state = NXInitHashState(class_hash);
1213 while (NXNextHashState(class_hash, &state, (void**)&cls)) {
1214 if (cls->info & CLS_FLUSH_CACHE) {
1215 _class_clearInfo((Class)cls, CLS_FLUSH_CACHE);
1216 }
1217 if (cls->isa->info & CLS_FLUSH_CACHE) {
1218 _class_clearInfo((Class)cls->isa, CLS_FLUSH_CACHE);
1219 }
1220 }
1221
1222 OBJC_UNLOCK(&cacheUpdateLock);
1223 OBJC_UNLOCK(&classLock);
1224 }
1225
1226
1227 /***********************************************************************
1228 * get_base_method_list
1229 * Returns the method list containing the class's own methods,
1230 * ignoring any method lists added by categories or class_addMethods.
1231 * Called only by add_class_to_loadable_list.
1232 * Does not hold methodListLock because add_class_to_loadable_list
1233 * does not manipulate in-use classes.
1234 **********************************************************************/
1235 static struct old_method_list *get_base_method_list(struct old_class *cls)
1236 {
1237 struct old_method_list **ptr;
1238
1239 if (!cls->methodLists) return NULL;
1240 if (cls->info & CLS_NO_METHOD_ARRAY) return (struct old_method_list *)cls->methodLists;
1241 ptr = cls->methodLists;
1242 if (!*ptr || *ptr == END_OF_METHODS_LIST) return NULL;
1243 while ( *ptr != 0 && *ptr != END_OF_METHODS_LIST ) { ptr++; }
1244 --ptr;
1245 return *ptr;
1246 }
1247
1248
1249 static IMP _class_getLoadMethod_nocheck(struct old_class *cls)
1250 {
1251 struct old_method_list *mlist;
1252 mlist = get_base_method_list(cls->isa);
1253 if (mlist) {
1254 return lookupNamedMethodInMethodList (mlist, "load");
1255 }
1256 return NULL;
1257 }
1258
1259
1260 __private_extern__ BOOL _class_hasLoadMethod(Class cls)
1261 {
1262 if (oldcls(cls)->isa->info & CLS_HAS_LOAD_METHOD) return YES;
1263 return (_class_getLoadMethod_nocheck(oldcls(cls)) ? YES : NO);
1264 }
1265
1266
1267 /***********************************************************************
1268 * _class_getLoadMethod
1269 * Returns cls's +load implementation, or NULL if it doesn't have one.
1270 **********************************************************************/
1271 __private_extern__ IMP _class_getLoadMethod(Class cls_gen)
1272 {
1273 struct old_class *cls = _class_asOld(cls_gen);
1274 if (cls->isa->info & CLS_HAS_LOAD_METHOD) {
1275 return _class_getLoadMethod_nocheck(cls);
1276 }
1277 return NULL;
1278 }
1279
1280
1281 __private_extern__ BOOL _class_shouldGrowCache(Class cls)
1282 {
1283 return _class_getInfo(cls, CLS_GROW_CACHE);
1284 }
1285
1286 __private_extern__ void _class_setGrowCache(Class cls, BOOL grow)
1287 {
1288 if (grow) _class_setInfo(cls, CLS_GROW_CACHE);
1289 else _class_clearInfo(cls, CLS_GROW_CACHE);
1290 }
1291
1292 __private_extern__ BOOL _class_hasCxxStructorsNoSuper(Class cls)
1293 {
1294 return _class_getInfo(cls, CLS_HAS_CXX_STRUCTORS);
1295 }
1296
1297 __private_extern__ BOOL _class_shouldFinalizeOnMainThread(Class cls) {
1298 return _class_getInfo(cls, CLS_FINALIZE_ON_MAIN_THREAD);
1299 }
1300
1301 __private_extern__ void _class_setFinalizeOnMainThread(Class cls) {
1302 _class_setInfo(cls, CLS_FINALIZE_ON_MAIN_THREAD);
1303 }
1304
1305
1306 __private_extern__ struct old_ivar *_ivar_asOld(Ivar ivar)
1307 {
1308 return (struct old_ivar *)ivar;
1309 }
1310
1311 ptrdiff_t ivar_getOffset(Ivar ivar)
1312 {
1313 return _ivar_asOld(ivar)->ivar_offset;
1314 }
1315
1316 const char *ivar_getName(Ivar ivar)
1317 {
1318 return _ivar_asOld(ivar)->ivar_name;
1319 }
1320
1321 const char *ivar_getTypeEncoding(Ivar ivar)
1322 {
1323 return _ivar_asOld(ivar)->ivar_type;
1324 }
1325
1326
1327 IMP method_getImplementation(Method m)
1328 {
1329 if (!m) return NULL;
1330 return _method_asOld(m)->method_imp;
1331 }
1332
1333 SEL method_getName(Method m)
1334 {
1335 if (!m) return NULL;
1336 return _method_asOld(m)->method_name;
1337 }
1338
1339 const char *method_getTypeEncoding(Method m)
1340 {
1341 if (!m) return NULL;
1342 return _method_asOld(m)->method_types;
1343 }
1344
1345 IMP method_setImplementation(Method m, IMP imp)
1346 {
1347 IMP old = _method_asOld(m)->method_imp;
1348 _method_asOld(m)->method_imp = imp;
1349 return old;
1350 }
1351
1352
1353 struct objc_method_description * method_getDescription(Method m)
1354 {
1355 if (!m) return NULL;
1356 return (struct objc_method_description *)oldmethod(m);
1357 }
1358
1359
1360 /***********************************************************************
1361 * class_addMethod
1362 **********************************************************************/
1363 static IMP _class_addMethod(Class cls_gen, SEL name, IMP imp,
1364 const char *types, BOOL replace)
1365 {
1366 struct old_class *cls = oldcls(cls_gen);
1367 IMP result = NULL;
1368
1369 if (!types) types = "";
1370
1371 OBJC_LOCK(&methodListLock);
1372
1373 struct old_method *m;
1374 if ((m = _findMethodInClass(cls, name))) {
1375 // already exists
1376 // fixme atomic
1377 result = method_getImplementation((Method)m);
1378 if (replace) {
1379 method_setImplementation((Method)m, imp);
1380 }
1381 } else {
1382 // fixme could be faster
1383 struct old_method_list *mlist =
1384 _calloc_internal(sizeof(struct old_method_list), 1);
1385 mlist->obsolete = _OBJC_FIXED_UP;
1386 mlist->method_count = 1;
1387 mlist->method_list[0].method_name = name;
1388 mlist->method_list[0].method_imp = imp;
1389 mlist->method_list[0].method_types = _strdup_internal(types);
1390
1391 _objc_insertMethods(cls, mlist, NULL);
1392 if (!(cls->info & CLS_CONSTRUCTING)) {
1393 flush_caches((Class)cls, NO);
1394 } else {
1395 // in-construction class has no subclasses
1396 flush_cache((Class)cls);
1397 }
1398 result = NULL;
1399 }
1400
1401 OBJC_UNLOCK(&methodListLock);
1402
1403 return result;
1404 }
1405
1406
1407 /***********************************************************************
1408 * class_addMethod
1409 **********************************************************************/
1410 BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
1411 {
1412 if (!cls) return NO;
1413
1414 IMP old = _class_addMethod(cls, name, imp, types, NO);
1415 return old ? NO : YES;
1416 }
1417
1418
1419 /***********************************************************************
1420 * class_replaceMethod
1421 **********************************************************************/
1422 IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
1423 {
1424 if (!cls) return NULL;
1425
1426 return _class_addMethod(cls, name, imp, types, YES);
1427 }
1428
1429
1430 /***********************************************************************
1431 * class_addIvar
1432 **********************************************************************/
1433 BOOL class_addIvar(Class cls_gen, const char *name, size_t size,
1434 uint8_t alignment, const char *type)
1435 {
1436 struct old_class *cls = oldcls(cls_gen);
1437 BOOL result = YES;
1438
1439 if (!cls) return NO;
1440 if (ISMETA(cls)) return NO;
1441 if (!(cls->info & CLS_CONSTRUCTING)) return NO;
1442
1443 if (!type) type = "";
1444 if (name && 0 == strcmp(name, "")) name = NULL;
1445
1446 OBJC_LOCK(&classLock);
1447
1448 // Check for existing ivar with this name
1449 // fixme check superclasses?
1450 if (cls->ivars) {
1451 int i;
1452 for (i = 0; i < cls->ivars->ivar_count; i++) {
1453 if (0 == strcmp(cls->ivars->ivar_list[i].ivar_name, name)) {
1454 result = NO;
1455 break;
1456 }
1457 }
1458 }
1459
1460 if (result) {
1461 struct old_ivar_list *old = cls->ivars;
1462 size_t oldSize;
1463 int newCount;
1464 struct old_ivar *ivar;
1465 size_t alignBytes;
1466 size_t misalign;
1467
1468 if (old) {
1469 oldSize = sizeof(struct old_ivar_list) +
1470 (old->ivar_count - 1) * sizeof(struct old_ivar);
1471 newCount = 1 + old->ivar_count;
1472 } else {
1473 oldSize = sizeof(struct old_ivar_list) - sizeof(struct old_ivar);
1474 newCount = 1;
1475 }
1476
1477 // allocate new ivar list
1478 cls->ivars = _calloc_internal(oldSize + sizeof(struct old_ivar), 1);
1479 if (old) memcpy(cls->ivars, old, oldSize);
1480 if (old && malloc_size(old)) free(old);
1481 cls->ivars->ivar_count = newCount;
1482 ivar = &cls->ivars->ivar_list[newCount-1];
1483
1484 // set ivar name and type
1485 ivar->ivar_name = _strdup_internal(name);
1486 ivar->ivar_type = _strdup_internal(type);
1487
1488 // align if necessary
1489 alignBytes = 1 << alignment;
1490 misalign = cls->instance_size % alignBytes;
1491 if (misalign) cls->instance_size += alignBytes - misalign;
1492
1493 // set ivar offset and increase instance size
1494 ivar->ivar_offset = (int)cls->instance_size;
1495 cls->instance_size += size;
1496 }
1497
1498 OBJC_UNLOCK(&classLock);
1499
1500 return result;
1501 }
1502
1503
1504 /***********************************************************************
1505 * class_addProtocol
1506 **********************************************************************/
1507 BOOL class_addProtocol(Class cls_gen, Protocol *protocol_gen)
1508 {
1509 struct old_class *cls = oldcls(cls_gen);
1510 struct old_protocol *protocol = oldprotocol(protocol_gen);
1511 struct old_protocol_list *plist;
1512
1513 if (!cls) return NO;
1514 if (class_conformsToProtocol(cls_gen, protocol_gen)) return NO;
1515
1516 OBJC_LOCK(&classLock);
1517
1518 // fixme optimize - protocol list doesn't escape?
1519 plist = _calloc_internal(sizeof(struct old_protocol_list), 1);
1520 plist->count = 1;
1521 plist->list[0] = protocol;
1522 plist->next = cls->protocols;
1523 cls->protocols = plist;
1524
1525 // fixme metaclass?
1526
1527 OBJC_UNLOCK(&classLock);
1528
1529 return YES;
1530 }
1531
1532
1533 /***********************************************************************
1534 * class_addProperty
1535 **********************************************************************/
1536 __private_extern__ void
1537 _class_addProperties(struct old_class *cls,
1538 struct objc_property_list *additions)
1539 {
1540 if (!(cls->info & CLS_EXT)) {
1541 return;
1542 }
1543
1544 struct objc_property_list *newlist =
1545 _memdup_internal(additions, sizeof(*newlist) - sizeof(newlist->first)
1546 + (additions->entsize * additions->count));
1547
1548 OBJC_LOCK(&classLock);
1549
1550 allocateExt(cls);
1551 if (!cls->ext->propertyLists) {
1552 // cls has no properties - simply use this list
1553 cls->ext->propertyLists = (struct objc_property_list **)newlist;
1554 _class_setInfo((Class)cls, CLS_NO_PROPERTY_ARRAY);
1555 }
1556 else if (cls->info & CLS_NO_PROPERTY_ARRAY) {
1557 // cls has one property list - make a new array
1558 struct objc_property_list **newarray =
1559 _malloc_internal(3 * sizeof(*newarray));
1560 newarray[0] = newlist;
1561 newarray[1] = (struct objc_property_list *)cls->ext->propertyLists;
1562 newarray[2] = NULL;
1563 cls->ext->propertyLists = newarray;
1564 _class_clearInfo((Class)cls, CLS_NO_PROPERTY_ARRAY);
1565 }
1566 else {
1567 // cls has a property array - make a bigger one
1568 int count = 0;
1569 while (cls->ext->propertyLists[count]) count++;
1570 struct objc_property_list **newarray =
1571 _malloc_internal((count+2) * sizeof(*newarray));
1572 newarray[0] = newlist;
1573 memcpy(&newarray[1], &cls->ext->propertyLists[0],
1574 count * sizeof(*newarray));
1575 newarray[count+1] = NULL;
1576 free(cls->ext->propertyLists);
1577 cls->ext->propertyLists = newarray;
1578 }
1579
1580 OBJC_UNLOCK(&classLock);
1581 }
1582
1583
1584 /***********************************************************************
1585 * class_copyProtocolList. Returns a heap block containing the
1586 * protocols implemented by the class, or NULL if the class
1587 * implements no protocols. Caller must free the block.
1588 * Does not copy any superclass's protocols.
1589 **********************************************************************/
1590 Protocol **class_copyProtocolList(Class cls_gen, unsigned int *outCount)
1591 {
1592 struct old_class *cls = oldcls(cls_gen);
1593 struct old_protocol_list *plist;
1594 Protocol **result = NULL;
1595 unsigned int count = 0;
1596 unsigned int i, p;
1597
1598 if (!cls) {
1599 if (outCount) *outCount = 0;
1600 return NULL;
1601 }
1602
1603 OBJC_LOCK(&classLock);
1604
1605 for (plist = cls->protocols; plist != NULL; plist = plist->next) {
1606 count += (int)plist->count;
1607 }
1608
1609 if (count > 0) {
1610 result = malloc((count+1) * sizeof(Protocol *));
1611
1612 for (p = 0, plist = cls->protocols;
1613 plist != NULL;
1614 plist = plist->next)
1615 {
1616 for (i = 0; i < plist->count; i++) {
1617 result[p++] = (Protocol *)plist->list[i];
1618 }
1619 }
1620 result[p] = NULL;
1621 }
1622
1623 OBJC_UNLOCK(&classLock);
1624
1625 if (outCount) *outCount = count;
1626 return result;
1627 }
1628
1629
1630 /***********************************************************************
1631 * class_getProperty. Return the named property.
1632 **********************************************************************/
1633 Property class_getProperty(Class cls_gen, const char *name)
1634 {
1635 Property result;
1636 struct old_class *cls = _class_asOld(cls_gen);
1637 if (!cls || !name) return NULL;
1638
1639 OBJC_LOCK(&classLock);
1640
1641 for (result = NULL; cls && !result; cls = cls->super_class) {
1642 uintptr_t iterator = 0;
1643 struct objc_property_list *plist;
1644 while ((plist = nextPropertyList(cls, &iterator))) {
1645 uint32_t i;
1646 for (i = 0; i < plist->count; i++) {
1647 Property p = property_list_nth(plist, i);
1648 if (0 == strcmp(name, p->name)) {
1649 result = p;
1650 goto done;
1651 }
1652 }
1653 }
1654 }
1655
1656 done:
1657 OBJC_UNLOCK(&classLock);
1658
1659 return result;
1660 }
1661
1662
1663 /***********************************************************************
1664 * class_copyPropertyList. Returns a heap block containing the
1665 * properties declared in the class, or NULL if the class
1666 * declares no properties. Caller must free the block.
1667 * Does not copy any superclass's properties.
1668 **********************************************************************/
1669 Property *class_copyPropertyList(Class cls_gen, unsigned int *outCount)
1670 {
1671 struct old_class *cls = oldcls(cls_gen);
1672 struct objc_property_list *plist;
1673 uintptr_t iterator = 0;
1674 Property *result = NULL;
1675 unsigned int count = 0;
1676 unsigned int p, i;
1677
1678 if (!cls) {
1679 if (outCount) *outCount = 0;
1680 return NULL;
1681 }
1682
1683 OBJC_LOCK(&classLock);
1684
1685 iterator = 0;
1686 while ((plist = nextPropertyList(cls, &iterator))) {
1687 count += plist->count;
1688 }
1689
1690 if (count > 0) {
1691 result = malloc((count+1) * sizeof(Property));
1692
1693 p = 0;
1694 iterator = 0;
1695 while ((plist = nextPropertyList(cls, &iterator))) {
1696 for (i = 0; i < plist->count; i++) {
1697 result[p++] = property_list_nth(plist, i);
1698 }
1699 }
1700 result[p] = NULL;
1701 }
1702
1703 OBJC_UNLOCK(&classLock);
1704
1705 if (outCount) *outCount = count;
1706 return result;
1707 }
1708
1709
1710 /***********************************************************************
1711 * class_copyMethodList. Returns a heap block containing the
1712 * methods implemented by the class, or NULL if the class
1713 * implements no methods. Caller must free the block.
1714 * Does not copy any superclass's methods.
1715 **********************************************************************/
1716 Method *class_copyMethodList(Class cls_gen, unsigned int *outCount)
1717 {
1718 struct old_class *cls = oldcls(cls_gen);
1719 struct old_method_list *mlist;
1720 void *iterator = NULL;
1721 Method *result = NULL;
1722 unsigned int count = 0;
1723 unsigned int m, i;
1724
1725 if (!cls) {
1726 if (outCount) *outCount = 0;
1727 return NULL;
1728 }
1729
1730 OBJC_LOCK(&methodListLock);
1731
1732 iterator = NULL;
1733 while ((mlist = nextMethodList(cls, &iterator))) {
1734 count += mlist->method_count;
1735 }
1736
1737 if (count > 0) {
1738 result = malloc((count+1) * sizeof(Method));
1739
1740 m = 0;
1741 iterator = NULL;
1742 while ((mlist = nextMethodList(cls, &iterator))) {
1743 for (i = 0; i < mlist->method_count; i++) {
1744 result[m++] = (Method)&mlist->method_list[i];
1745 }
1746 }
1747 result[m] = NULL;
1748 }
1749
1750 OBJC_UNLOCK(&methodListLock);
1751
1752 if (outCount) *outCount = count;
1753 return result;
1754 }
1755
1756
1757 /***********************************************************************
1758 * class_copyIvarList. Returns a heap block containing the
1759 * ivars declared in the class, or NULL if the class
1760 * declares no ivars. Caller must free the block.
1761 * Does not copy any superclass's ivars.
1762 **********************************************************************/
1763 Ivar *class_copyIvarList(Class cls_gen, unsigned int *outCount)
1764 {
1765 struct old_class *cls = oldcls(cls_gen);
1766 Ivar *result = NULL;
1767 unsigned int count = 0;
1768 unsigned int i;
1769
1770 if (!cls) {
1771 if (outCount) *outCount = 0;
1772 return NULL;
1773 }
1774
1775 if (cls->ivars) {
1776 count = cls->ivars->ivar_count;
1777 }
1778
1779 if (count > 0) {
1780 result = malloc((count+1) * sizeof(Ivar));
1781
1782 for (i = 0; i < cls->ivars->ivar_count; i++) {
1783 result[i] = (Ivar)&cls->ivars->ivar_list[i];
1784 }
1785 result[i] = NULL;
1786 }
1787
1788 if (outCount) *outCount = count;
1789 return result;
1790 }
1791
1792
1793 /***********************************************************************
1794 * objc_allocateClass.
1795 **********************************************************************/
1796 __private_extern__
1797 void set_superclass(struct old_class *cls, struct old_class *supercls)
1798 {
1799 struct old_class *meta = cls->isa;
1800
1801 if (supercls) {
1802 cls->super_class = supercls;
1803 meta->super_class = supercls->isa;
1804 meta->isa = supercls->isa->isa;
1805
1806 // Superclass is no longer a leaf for cache flushing
1807 if (supercls->info & CLS_LEAF) {
1808 _class_clearInfo((Class)supercls, CLS_LEAF);
1809 _class_clearInfo((Class)supercls->isa, CLS_LEAF);
1810 }
1811 } else {
1812 cls->super_class = Nil; // superclass of root class is nil
1813 meta->super_class = cls; // superclass of root metaclass is root class
1814 meta->isa = meta; // metaclass of root metaclass is root metaclass
1815
1816 // Root class is never a leaf for cache flushing, because the
1817 // root metaclass is a subclass. (This could be optimized, but
1818 // is too uncommon to bother.)
1819 _class_clearInfo((Class)cls, CLS_LEAF);
1820 _class_clearInfo((Class)meta, CLS_LEAF);
1821 }
1822 }
1823
1824 Class objc_allocateClassPair(Class superclass_gen, const char *name,
1825 size_t extraBytes)
1826 {
1827 struct old_class *superclass = oldcls(superclass_gen);
1828 struct old_class *cls, *meta;
1829
1830 if (objc_getClass(name)) return NO;
1831 // fixme reserve class name against simultaneous allocation
1832
1833 if (superclass && (superclass->info & CLS_CONSTRUCTING)) {
1834 // Can't make subclass of an in-construction class
1835 return NO;
1836 }
1837
1838 // Allocate new classes.
1839 if (superclass) {
1840 cls = _calloc_internal(superclass->isa->instance_size + extraBytes, 1);
1841 meta = _calloc_internal(superclass->isa->isa->instance_size + extraBytes, 1);
1842 } else {
1843 cls = _calloc_internal(sizeof(struct old_class) + extraBytes, 1);
1844 meta = _calloc_internal(sizeof(struct old_class) + extraBytes, 1);
1845 }
1846
1847 // Connect to superclasses and metaclasses
1848 cls->isa = meta;
1849 set_superclass(cls, superclass);
1850
1851 // Set basic info
1852 cls->name = _strdup_internal(name);
1853 meta->name = _strdup_internal(name);
1854 cls->version = 0;
1855 meta->version = 7;
1856 cls->info = CLS_CLASS | CLS_CONSTRUCTING | CLS_EXT | CLS_LEAF;
1857 meta->info = CLS_META | CLS_CONSTRUCTING | CLS_EXT | CLS_LEAF;
1858
1859 // Set instance size based on superclass.
1860 if (superclass) {
1861 cls->instance_size = superclass->instance_size;
1862 meta->instance_size = superclass->isa->instance_size;
1863 } else {
1864 cls->instance_size = sizeof(struct old_class *); // just an isa
1865 meta->instance_size = sizeof(struct old_class);
1866 }
1867
1868 // No ivars. No methods. Empty cache. No protocols. No layout. No ext.
1869 cls->ivars = NULL;
1870 cls->methodLists = NULL;
1871 cls->cache = (Cache)&_objc_empty_cache;
1872 cls->protocols = NULL;
1873 cls->ext = NULL;
1874
1875 meta->ivars = NULL;
1876 meta->methodLists = NULL;
1877 meta->cache = (Cache)&_objc_empty_cache;
1878 meta->protocols = NULL;
1879 cls->ext = NULL;
1880
1881 return (Class)cls;
1882 }
1883
1884
1885 void objc_registerClassPair(Class cls_gen)
1886 {
1887 struct old_class *cls = oldcls(cls_gen);
1888
1889 if ((cls->info & CLS_CONSTRUCTED) ||
1890 (cls->isa->info & CLS_CONSTRUCTED))
1891 {
1892 _objc_inform("objc_registerClassPair: class '%s' was already "
1893 "registered!", cls->name);
1894 return;
1895 }
1896
1897 if (!(cls->info & CLS_CONSTRUCTING) ||
1898 !(cls->isa->info & CLS_CONSTRUCTING))
1899 {
1900 _objc_inform("objc_registerClassPair: class '%s' was not "
1901 "allocated with objc_allocateClassPair!", cls->name);
1902 return;
1903 }
1904
1905 if (ISMETA(cls)) {
1906 _objc_inform("objc_registerClassPair: class '%s' is a metaclass, "
1907 "not a class!", cls->name);
1908 return;
1909 }
1910
1911 OBJC_LOCK(&classLock);
1912
1913 // Build ivar layouts
1914 if (UseGC) {
1915 if (cls->ivar_layout) {
1916 // Class builder already called class_setIvarLayout.
1917 }
1918 else if (!cls->super_class) {
1919 // Root class. Scan conservatively (should be isa ivar only).
1920 // ivar_layout is already NULL.
1921 }
1922 else if (cls->ivars == NULL) {
1923 // No local ivars. Use superclass's layout.
1924 cls->ivar_layout =
1925 _strdup_internal(cls->super_class->ivar_layout);
1926 }
1927 else {
1928 // Has local ivars. Build layout based on superclass.
1929 struct old_class *supercls = cls->super_class;
1930 unsigned char *superlayout =
1931 (unsigned char *) class_getIvarLayout((Class)supercls);
1932 layout_bitmap bitmap =
1933 layout_bitmap_create(superlayout, supercls->instance_size,
1934 cls->instance_size, NO);
1935 int i;
1936 for (i = 0; i < cls->ivars->ivar_count; i++) {
1937 struct old_ivar *iv = &cls->ivars->ivar_list[i];
1938 layout_bitmap_set_ivar(bitmap, iv->ivar_type, iv->ivar_offset);
1939 }
1940 cls->ivar_layout = (char *)layout_string_create(bitmap);
1941 layout_bitmap_free(bitmap);
1942 }
1943
1944 if (cls->ext && cls->ext->weak_ivar_layout) {
1945 // Class builder already called class_setWeakIvarLayout.
1946 }
1947 else if (!cls->super_class) {
1948 // Root class. No weak ivars (should be isa ivar only)
1949 // weak_ivar_layout is already NULL.
1950 }
1951 else if (cls->ivars == NULL) {
1952 // No local ivars. Use superclass's layout.
1953 const char *weak =
1954 class_getWeakIvarLayout((Class)cls->super_class);
1955 if (weak) {
1956 allocateExt(cls);
1957 cls->ext->weak_ivar_layout = _strdup_internal(weak);
1958 }
1959 }
1960 else {
1961 // Has local ivars. Build layout based on superclass.
1962 // No way to add weak ivars yet.
1963 const char *weak =
1964 class_getWeakIvarLayout((Class)cls->super_class);
1965 if (weak) {
1966 allocateExt(cls);
1967 cls->ext->weak_ivar_layout = _strdup_internal(weak);
1968 }
1969 }
1970 }
1971
1972 // Clear "under construction" bit, set "done constructing" bit
1973 cls->info &= ~CLS_CONSTRUCTING;
1974 cls->isa->info &= ~CLS_CONSTRUCTING;
1975 cls->info |= CLS_CONSTRUCTED;
1976 cls->isa->info |= CLS_CONSTRUCTED;
1977
1978 NXHashInsertIfAbsent(class_hash, cls);
1979
1980 OBJC_UNLOCK(&classLock);
1981 }
1982
1983
1984 Class objc_duplicateClass(Class orig_gen, const char *name, size_t extraBytes)
1985 {
1986 unsigned int count, i;
1987 struct old_method **originalMethods;
1988 struct old_method_list *duplicateMethods;
1989 struct old_class *original = oldcls(orig_gen);
1990 // Don't use sizeof(struct objc_class) here because
1991 // instance_size has historically contained two extra words,
1992 // and instance_size is what objc_getIndexedIvars() actually uses.
1993 struct old_class *duplicate = (struct old_class *)
1994 calloc(original->isa->instance_size + extraBytes, 1);
1995
1996 duplicate->isa = original->isa;
1997 duplicate->super_class = original->super_class;
1998 duplicate->name = strdup(name);
1999 duplicate->version = original->version;
2000 duplicate->info = original->info & (CLS_CLASS|CLS_META|CLS_INITIALIZED|CLS_JAVA_HYBRID|CLS_JAVA_CLASS|CLS_HAS_CXX_STRUCTORS|CLS_HAS_LOAD_METHOD);
2001 duplicate->instance_size = original->instance_size;
2002 duplicate->ivars = original->ivars;
2003 // methodLists handled below
2004 duplicate->cache = (Cache)&_objc_empty_cache;
2005 duplicate->protocols = original->protocols;
2006 if (original->info & CLS_EXT) {
2007 duplicate->info |= original->info & (CLS_EXT|CLS_NO_PROPERTY_ARRAY);
2008 duplicate->ivar_layout = original->ivar_layout;
2009 if (original->ext) {
2010 duplicate->ext = _malloc_internal(original->ext->size);
2011 memcpy(duplicate->ext, original->ext, original->ext->size);
2012 } else {
2013 duplicate->ext = NULL;
2014 }
2015 }
2016
2017 // Method lists are deep-copied so they can be stomped.
2018 originalMethods = (struct old_method **)
2019 class_copyMethodList(orig_gen, &count);
2020 if (originalMethods) {
2021 duplicateMethods = (struct old_method_list *)
2022 calloc(sizeof(struct old_method_list) +
2023 (count-1)*sizeof(struct old_method), 1);
2024 duplicateMethods->obsolete = _OBJC_FIXED_UP;
2025 duplicateMethods->method_count = count;
2026 for (i = 0; i < count; i++) {
2027 duplicateMethods->method_list[i] = *(originalMethods[i]);
2028 }
2029 duplicate->methodLists = (struct old_method_list **)duplicateMethods;
2030 duplicate->info |= CLS_NO_METHOD_ARRAY;
2031 free(originalMethods);
2032 }
2033
2034 OBJC_LOCK(&classLock);
2035 NXHashInsert(class_hash, duplicate);
2036 OBJC_UNLOCK(&classLock);
2037
2038 return (Class)duplicate;
2039 }
2040
2041
2042 void objc_disposeClassPair(Class cls_gen)
2043 {
2044 struct old_class *cls = oldcls(cls_gen);
2045
2046 if (!(cls->info & (CLS_CONSTRUCTED|CLS_CONSTRUCTING)) ||
2047 !(cls->isa->info & (CLS_CONSTRUCTED|CLS_CONSTRUCTING)))
2048 {
2049 // class not allocated with objc_allocateClassPair
2050 // disposing still-unregistered class is OK!
2051 _objc_inform("objc_disposeClassPair: class '%s' was not "
2052 "allocated with objc_allocateClassPair!", cls->name);
2053 return;
2054 }
2055
2056 if (ISMETA(cls)) {
2057 _objc_inform("objc_disposeClassPair: class '%s' is a metaclass, "
2058 "not a class!", cls->name);
2059 return;
2060 }
2061
2062 NXHashRemove(class_hash, cls);
2063 unload_class(cls->isa);
2064 unload_class(cls);
2065 }
2066
2067
2068 /***********************************************************************
2069 * _internal_class_createInstance. Allocate an instance of the specified
2070 * class with the specified number of bytes for indexed variables, in
2071 * the default zone, using _internal_class_createInstanceFromZone.
2072 **********************************************************************/
2073 static id _internal_class_createInstance(Class cls, size_t extraBytes)
2074 {
2075 return _internal_class_createInstanceFromZone (cls, extraBytes, NULL);
2076 }
2077
2078
2079 static id _internal_object_copyFromZone(id oldObj, size_t extraBytes, void *zone)
2080 {
2081 id obj;
2082 size_t size;
2083
2084 if (!oldObj) return nil;
2085
2086 obj = (*_zoneAlloc)(oldObj->isa, extraBytes, zone);
2087 size = _class_getInstanceSize(oldObj->isa) + extraBytes;
2088 // fixme need C++ copy constructor
2089 bcopy((const char*)oldObj, (char*)obj, size);
2090 return obj;
2091 }
2092
2093 static id _internal_object_copy(id oldObj, size_t extraBytes)
2094 {
2095 void *z = malloc_zone_from_ptr(oldObj);
2096 return _internal_object_copyFromZone(oldObj, extraBytes,
2097 z ? z : malloc_default_zone());
2098 }
2099
2100 static id _internal_object_reallocFromZone(id anObject, size_t nBytes,
2101 void *zone)
2102 {
2103 id newObject;
2104 Class tmp;
2105
2106 if (anObject == nil)
2107 __objc_error(nil, "reallocating nil object");
2108
2109 if (anObject->isa == _objc_getFreedObjectClass ())
2110 __objc_error(anObject, "reallocating freed object");
2111
2112 if (nBytes < _class_getInstanceSize(anObject->isa))
2113 __objc_error(anObject, "(%s, %zu) requested size too small",
2114 object_getClassName(anObject), nBytes);
2115
2116 // fixme need C++ copy constructor
2117 // fixme GC copy
2118 // Make sure not to modify space that has been declared free
2119 tmp = anObject->isa;
2120 anObject->isa = _objc_getFreedObjectClass ();
2121 newObject = (id)malloc_zone_realloc(zone, anObject, nBytes);
2122 if (newObject) {
2123 newObject->isa = tmp;
2124 } else {
2125 // realloc failed, anObject is still alive
2126 anObject->isa = tmp;
2127 }
2128 return newObject;
2129 }
2130
2131
2132 static id _internal_object_realloc(id anObject, size_t nBytes)
2133 {
2134 void *z = malloc_zone_from_ptr(anObject);
2135 return _internal_object_reallocFromZone(anObject,
2136 nBytes,
2137 z ? z : malloc_default_zone());
2138 }
2139
2140 id (*_alloc)(Class, size_t) = _internal_class_createInstance;
2141 id (*_copy)(id, size_t) = _internal_object_copy;
2142 id (*_realloc)(id, size_t) = _internal_object_realloc;
2143 id (*_dealloc)(id) = _internal_object_dispose;
2144 id (*_zoneAlloc)(Class, size_t, void *) = _internal_class_createInstanceFromZone;
2145 id (*_zoneCopy)(id, size_t, void *) = _internal_object_copyFromZone;
2146 id (*_zoneRealloc)(id, size_t, void *) = _internal_object_reallocFromZone;
2147 void (*_error)() = (void(*)())_objc_error;
2148
2149
2150 id class_createInstance(Class cls, size_t extraBytes)
2151 {
2152 if (UseGC) {
2153 return _internal_class_createInstance(cls, extraBytes);
2154 } else {
2155 return (*_alloc)(cls, extraBytes);
2156 }
2157 }
2158
2159 id class_createInstanceFromZone(Class cls, size_t extraBytes, void *z)
2160 {
2161 OBJC_WARN_DEPRECATED;
2162 if (UseGC) {
2163 return _internal_class_createInstanceFromZone(cls, extraBytes, z);
2164 } else {
2165 return (*_zoneAlloc)(cls, extraBytes, z);
2166 }
2167 }
2168
2169 id object_copy(id obj, size_t extraBytes)
2170 {
2171 if (UseGC) return _internal_object_copy(obj, extraBytes);
2172 else return (*_copy)(obj, extraBytes);
2173 }
2174
2175 id object_copyFromZone(id obj, size_t extraBytes, void *z)
2176 {
2177 OBJC_WARN_DEPRECATED;
2178 if (UseGC) return _internal_object_copyFromZone(obj, extraBytes, z);
2179 else return (*_zoneCopy)(obj, extraBytes, z);
2180 }
2181
2182 id object_dispose(id obj)
2183 {
2184 if (UseGC) return _internal_object_dispose(obj);
2185 else return (*_dealloc)(obj);
2186 }
2187
2188 id object_realloc(id obj, size_t nBytes)
2189 {
2190 OBJC_WARN_DEPRECATED;
2191 if (UseGC) return _internal_object_realloc(obj, nBytes);
2192 else return (*_realloc)(obj, nBytes);
2193 }
2194
2195 id object_reallocFromZone(id obj, size_t nBytes, void *z)
2196 {
2197 OBJC_WARN_DEPRECATED;
2198 if (UseGC) return _internal_object_reallocFromZone(obj, nBytes, z);
2199 else return (*_zoneRealloc)(obj, nBytes, z);
2200 }
2201
2202
2203 // ProKit SPI
2204 Class class_setSuperclass(Class cls, Class newSuper)
2205 {
2206 Class oldSuper = cls->super_class;
2207 set_superclass(oldcls(cls), oldcls(newSuper));
2208 flush_caches(cls, YES);
2209 return oldSuper;
2210 }
2211 #endif