]> git.saurik.com Git - apple/objc4.git/blame - runtime/objc-class-old.mm
objc4-818.2.tar.gz
[apple/objc4.git] / runtime / objc-class-old.mm
CommitLineData
b3962a83 1/*
8972963c 2 * Copyright (c) 1999-2009 Apple Inc. All Rights Reserved.
b3962a83
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/***********************************************************************
25* objc-class-old.m
26* Support for old-ABI classes, methods, and categories.
27**********************************************************************/
28
29#if !__OBJC2__
30
7af964d1 31#include "objc-private.h"
8972963c 32#include "objc-runtime-old.h"
7257e56c
A
33#include "objc-file-old.h"
34#include "objc-cache-old.h"
35
36static Method _class_getMethod(Class cls, SEL sel);
37static Method _class_getMethodNoSuper(Class cls, SEL sel);
38static Method _class_getMethodNoSuper_nolock(Class cls, SEL sel);
13ba007e 39static Class _class_getNonMetaClass(Class cls, id obj);
7257e56c
A
40static void flush_caches(Class cls, bool flush_meta);
41
b3962a83
A
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.
7257e56c 45static const void* freedObjectClass[12] =
b3962a83
A
46{
47 Nil, // isa
7257e56c 48 Nil, // superclass
b3962a83
A
49 "FREED(id)", // name
50 0, // version
51 0, // info
52 0, // instance_size
7257e56c
A
53 nil, // ivars
54 nil, // methodLists
b3962a83 55 (Cache) &_objc_empty_cache, // cache
7257e56c
A
56 nil, // protocols
57 nil, // ivar_layout;
58 nil // ext
b3962a83
A
59};
60
b3962a83
A
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**********************************************************************/
7af964d1 68static Class _class_getFreedObjectClass(void)
b3962a83 69{
7257e56c 70 return (Class)freedObjectClass;
b3962a83
A
71}
72
73
b3962a83
A
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**********************************************************************/
80Class _objc_getFreedObjectClass(void)
81{
82 return _class_getFreedObjectClass();
83}
84
85
7257e56c 86static void allocateExt(Class cls)
b3962a83
A
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) {
7257e56c 93 uint32_t size = (uint32_t)sizeof(old_class_ext);
31875a97 94 cls->ext = (old_class_ext *)calloc(size, 1);
b3962a83
A
95 cls->ext->size = size;
96 }
97}
98
99
7257e56c 100static inline old_method *_findNamedMethodInList(old_method_list * mlist, const char *meth_name) {
b3962a83 101 int i;
7257e56c 102 if (!mlist) return nil;
b3962a83 103 for (i = 0; i < mlist->method_count; i++) {
7257e56c 104 old_method *m = &mlist->method_list[i];
8972963c 105 if (0 == strcmp((const char *)(m->method_name), meth_name)) {
b3962a83
A
106 return m;
107 }
108 }
7257e56c 109 return nil;
b3962a83
A
110}
111
112
7af964d1
A
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)
126static void *fixed_up_method_list = OBJC_FIXED_UP;
127
128// sel_init() decided that selectors in the dyld shared cache are untrustworthy
cd5f04f5 129void disableSharedCacheOptimizations(void)
7af964d1
A
130{
131 fixed_up_method_list = OBJC_FIXED_UP_outside_dyld;
132}
133
b3962a83
A
134/***********************************************************************
135* fixupSelectorsInMethodList
136* Uniques selectors in the given method list.
7257e56c 137* The given method list must be non-nil and not already fixed-up.
b3962a83
A
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**********************************************************************/
7257e56c 146static old_method_list *fixupSelectorsInMethodList(Class cls, old_method_list *mlist)
b3962a83
A
147{
148 int i;
149 size_t size;
7257e56c
A
150 old_method *method;
151 old_method_list *old_mlist;
b3962a83 152
7257e56c 153 if ( ! mlist ) return nil;
7af964d1
A
154 if ( mlist->obsolete == fixed_up_method_list ) {
155 // method list OK
156 } else {
31875a97 157 bool isBundle = cls->info & CLS_FROM_BUNDLE;
b3962a83
A
158 if (!isBundle) {
159 old_mlist = mlist;
7257e56c 160 size = sizeof(old_method_list) - sizeof(old_method) + old_mlist->method_count * sizeof(old_method);
31875a97 161 mlist = (old_method_list *)malloc(size);
b3962a83
A
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 }
66799735 167 mutex_locker_t lock(selLock);
b3962a83
A
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.
b3962a83 172 }
7af964d1 173 mlist->obsolete = fixed_up_method_list;
b3962a83
A
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*
7257e56c
A
192* void *iterator = nil;
193* old_method_list *mlist;
31875a97 194* mutex_locker_t lock(methodListLock);
b3962a83
A
195* while ((mlist = nextMethodList(cls, &iterator))) {
196* // do something with mlist
197* }
b3962a83 198**********************************************************************/
7257e56c 199static old_method_list *nextMethodList(Class cls,
b3962a83
A
200 void **it)
201{
202 uintptr_t index = *(uintptr_t *)it;
7257e56c 203 old_method_list **resultp;
b3962a83
A
204
205 if (index == 0) {
206 // First call to nextMethodList.
207 if (!cls->methodLists) {
7257e56c 208 resultp = nil;
b3962a83 209 } else if (cls->info & CLS_NO_METHOD_ARRAY) {
7257e56c 210 resultp = (old_method_list **)&cls->methodLists;
b3962a83
A
211 } else {
212 resultp = &cls->methodLists[0];
213 if (!*resultp || *resultp == END_OF_METHODS_LIST) {
7257e56c 214 resultp = nil;
b3962a83
A
215 }
216 }
217 } else {
218 // Subsequent call to nextMethodList.
219 if (!cls->methodLists) {
7257e56c 220 resultp = nil;
b3962a83 221 } else if (cls->info & CLS_NO_METHOD_ARRAY) {
7257e56c 222 resultp = nil;
b3962a83
A
223 } else {
224 resultp = &cls->methodLists[index];
225 if (!*resultp || *resultp == END_OF_METHODS_LIST) {
7257e56c 226 resultp = nil;
b3962a83
A
227 }
228 }
229 }
230
7257e56c 231 // resultp now is nil, meaning there are no more method lists,
b3962a83
A
232 // OR the address of the method list pointer to fix up and return.
233
234 if (resultp) {
7af964d1 235 if (*resultp) {
b3962a83
A
236 *resultp = fixupSelectorsInMethodList(cls, *resultp);
237 }
238 *it = (void *)(index + 1);
239 return *resultp;
240 } else {
241 *it = 0;
7257e56c 242 return nil;
b3962a83
A
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 */
7257e56c 250static inline old_method *_findMethodInList(old_method_list * mlist, SEL sel) {
b3962a83 251 int i;
7257e56c 252 if (!mlist) return nil;
b3962a83 253 for (i = 0; i < mlist->method_count; i++) {
7257e56c 254 old_method *m = &mlist->method_list[i];
b3962a83
A
255 if (m->method_name == sel) {
256 return m;
257 }
258 }
7257e56c 259 return nil;
b3962a83
A
260}
261
7257e56c
A
262static inline old_method * _findMethodInClass(Class cls, SEL sel) __attribute__((always_inline));
263static inline old_method * _findMethodInClass(Class cls, SEL sel) {
b3962a83
A
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))) {
7257e56c 268 // old_method *m = _findMethodInList(mlist, sel);
b3962a83
A
269 // if (m) return m;
270 // }
271
272 if (!cls->methodLists) {
273 // No method lists.
7257e56c 274 return nil;
b3962a83
A
275 }
276 else if (cls->info & CLS_NO_METHOD_ARRAY) {
277 // One method list.
7257e56c
A
278 old_method_list **mlistp;
279 mlistp = (old_method_list **)&cls->methodLists;
7af964d1 280 *mlistp = fixupSelectorsInMethodList(cls, *mlistp);
b3962a83
A
281 return _findMethodInList(*mlistp, sel);
282 }
283 else {
284 // Multiple method lists.
7257e56c 285 old_method_list **mlistp;
b3962a83 286 for (mlistp = cls->methodLists;
7257e56c 287 *mlistp != nil && *mlistp != END_OF_METHODS_LIST;
b3962a83
A
288 mlistp++)
289 {
7257e56c 290 old_method *m;
7af964d1 291 *mlistp = fixupSelectorsInMethodList(cls, *mlistp);
b3962a83
A
292 m = _findMethodInList(*mlistp, sel);
293 if (m) return m;
294 }
7257e56c 295 return nil;
b3962a83
A
296 }
297}
298
7257e56c
A
299static inline old_method * _getMethod(Class cls, SEL sel) {
300 for (; cls; cls = cls->superclass) {
301 old_method *m;
b3962a83
A
302 m = _findMethodInClass(cls, sel);
303 if (m) return m;
304 }
7257e56c 305 return nil;
b3962a83
A
306}
307
308
c1e772c4 309// called by a debugging check in _objc_insertMethods
7257e56c 310IMP findIMPInClass(Class cls, SEL sel)
b3962a83 311{
7257e56c 312 old_method *m = _findMethodInClass(cls, sel);
b3962a83 313 if (m) return m->method_imp;
7257e56c 314 else return nil;
b3962a83
A
315}
316
317
7af964d1
A
318/***********************************************************************
319* _freedHandler.
320**********************************************************************/
321static void _freedHandler(id obj, SEL sel)
322{
323 __objc_error (obj, "message %s sent to freed object=%p",
7257e56c 324 sel_getName(sel), (void*)obj);
7af964d1
A
325}
326
7af964d1 327
13ba007e
A
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**********************************************************************/
1807f628 334static void _class_resolveClassMethod(id inst, SEL sel, Class cls)
13ba007e 335{
1807f628
A
336 ASSERT(cls->isMetaClass());
337 SEL resolve_sel = @selector(resolveClassMethod:);
13ba007e 338
34d5b5e8 339 if (!lookUpImpOrNilTryCache(inst, resolve_sel, cls)) {
13ba007e
A
340 // Resolver not implemented.
341 return;
342 }
343
344 BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
1807f628 345 bool resolved = msg(_class_getNonMetaClass(cls, inst), resolve_sel, sel);
13ba007e
A
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
34d5b5e8 349 IMP imp = lookUpImpOrNilTryCache(inst, sel, cls);
13ba007e
A
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**********************************************************************/
1807f628 375static void _class_resolveInstanceMethod(id inst, SEL sel, Class cls)
13ba007e 376{
1807f628
A
377 SEL resolve_sel = @selector(resolveInstanceMethod:);
378
34d5b5e8 379 if (! lookUpImpOrNilTryCache(cls, resolve_sel, cls->ISA())) {
13ba007e
A
380 // Resolver not implemented.
381 return;
382 }
383
384 BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
1807f628 385 bool resolved = msg(cls, resolve_sel, sel);
13ba007e
A
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
34d5b5e8 389 IMP imp = lookUpImpOrNilTryCache(inst, sel, cls);
13ba007e
A
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**********************************************************************/
1807f628
A
416static void
417_class_resolveMethod(id inst, SEL sel, Class cls)
13ba007e
A
418{
419 if (! cls->isMetaClass()) {
420 // try [cls resolveInstanceMethod:sel]
1807f628 421 _class_resolveInstanceMethod(inst, sel, cls);
13ba007e
A
422 }
423 else {
424 // try [nonMetaClass resolveClassMethod:sel]
425 // and [cls resolveInstanceMethod:sel]
1807f628 426 _class_resolveClassMethod(inst, sel, cls);
34d5b5e8 427 if (!lookUpImpOrNilTryCache(inst, sel, cls)) {
1807f628 428 _class_resolveInstanceMethod(inst, sel, cls);
13ba007e
A
429 }
430 }
431}
432
433
7af964d1 434/***********************************************************************
7257e56c
A
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.
7af964d1 439**********************************************************************/
7257e56c
A
440static void
441log_and_fill_cache(Class cls, Class implementer, Method meth, SEL sel)
7af964d1 442{
7257e56c
A
443#if SUPPORT_MESSAGE_LOGGING
444 if (objcMsgLogEnabled) {
445 bool cacheIt = logMessageSend(implementer->isMetaClass(),
8070259c
A
446 cls->nameForLogging(),
447 implementer->nameForLogging(),
7257e56c
A
448 sel);
449 if (!cacheIt) return;
450 }
451#endif
452 _cache_fill (cls, meth, sel);
7af964d1 453}
7257e56c
A
454
455
7257e56c
A
456/***********************************************************************
457* lookUpImpOrForward.
458* The standard IMP lookup.
1807f628
A
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.
7257e56c
A
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.
1807f628 466* If you don't want forwarding at all, use LOOKUP_NIL.
7257e56c 467**********************************************************************/
1807f628 468IMP lookUpImpOrForward(id inst, SEL sel, Class cls, int behavior)
7af964d1 469{
7257e56c
A
470 Class curClass;
471 IMP methodPC = nil;
472 Method meth;
473 bool triedResolver = NO;
474
31875a97 475 methodListLock.assertUnlocked();
7af964d1 476
7257e56c 477 // Optimistic cache lookup
1807f628 478 if (behavior & LOOKUP_CACHE) {
7257e56c 479 methodPC = _cache_getImp(cls, sel);
1807f628 480 if (methodPC) goto out_nolock;
7257e56c
A
481 }
482
7af964d1
A
483 // Check for freed class
484 if (cls == _class_getFreedObjectClass())
485 return (IMP) _freedHandler;
486
7257e56c 487 // Check for +initialize
1807f628 488 if ((behavior & LOOKUP_INITIALIZE) && !cls->isInitialized()) {
13ba007e
A
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
7af964d1
A
492 // procedure finishes. Of course, if this is not being called
493 // from the messenger then it won't happen. 2778172
494 }
7257e56c
A
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:
31875a97 501 methodListLock.lock();
7257e56c 502
7257e56c
A
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
1807f628 549 if ((behavior & LOOKUP_RESOLVER) && !triedResolver) {
31875a97 550 methodListLock.unlock();
7257e56c
A
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:
31875a97 563 methodListLock.unlock();
7257e56c 564
1807f628
A
565 out_nolock:
566 if ((behavior & LOOKUP_NIL) && methodPC == (IMP)_objc_msgForward_impcache) {
567 return nil;
568 }
7257e56c 569 return methodPC;
7af964d1
A
570}
571
b3962a83 572
7257e56c
A
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**********************************************************************/
578IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel)
b3962a83 579{
7257e56c
A
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.
b3962a83 587
7257e56c
A
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
c1e772c4
A
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**********************************************************************/
613Class _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
7257e56c
A
629/***********************************************************************
630* class_getVariable. Return the named instance variable.
631**********************************************************************/
632
c1e772c4 633Ivar _class_getVariable(Class cls, const char *name)
7257e56c
A
634{
635 for (; cls != Nil; cls = cls->superclass) {
b3962a83
A
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
7257e56c 643 // compiler generates ivar entries with nil ivar_name
b3962a83 644 // (e.g. for anonymous bit fields).
7257e56c 645 old_ivar *ivar = &cls->ivars->ivar_list[i];
b3962a83
A
646 if (ivar->ivar_name && 0 == strcmp(name, ivar->ivar_name)) {
647 return (Ivar)ivar;
648 }
649 }
650 }
651
652 // Not found
7257e56c 653 return nil;
b3962a83
A
654}
655
656
7257e56c
A
657old_property *
658property_list_nth(const old_property_list *plist, uint32_t i)
8972963c 659{
7257e56c 660 return (old_property *)(i*plist->entsize + (char *)&plist->first);
8972963c
A
661}
662
7257e56c
A
663old_property **
664copyPropertyList(old_property_list *plist, unsigned int *outCount)
8972963c 665{
7257e56c 666 old_property **result = nil;
8972963c
A
667 unsigned int count = 0;
668
669 if (plist) {
670 count = plist->count;
671 }
672
673 if (count > 0) {
674 unsigned int i;
7257e56c 675 result = (old_property **)malloc((count+1) * sizeof(old_property *));
8972963c
A
676
677 for (i = 0; i < count; i++) {
678 result[i] = property_list_nth(plist, i);
679 }
7257e56c 680 result[i] = nil;
8972963c
A
681 }
682
683 if (outCount) *outCount = count;
684 return result;
685}
686
687
7257e56c
A
688static old_property_list *
689nextPropertyList(Class cls, uintptr_t *indexp)
b3962a83 690{
7257e56c 691 old_property_list *result = nil;
b3962a83 692
31875a97 693 classLock.assertLocked();
b3962a83
A
694 if (! ((cls->info & CLS_EXT) && cls->ext)) {
695 // No class ext
7257e56c 696 result = nil;
b3962a83
A
697 } else if (!cls->ext->propertyLists) {
698 // No property lists
7257e56c 699 result = nil;
b3962a83
A
700 } else if (cls->info & CLS_NO_PROPERTY_ARRAY) {
701 // Only one property list
702 if (*indexp == 0) {
7257e56c 703 result = (old_property_list *)cls->ext->propertyLists;
b3962a83 704 } else {
7257e56c 705 result = nil;
b3962a83
A
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;
7257e56c 717 return nil;
b3962a83
A
718 }
719}
720
721
722/***********************************************************************
723* class_getIvarLayout
7257e56c 724* nil means all-scanned. "" means non-scanned.
b3962a83 725**********************************************************************/
8972963c 726const uint8_t *
7257e56c 727class_getIvarLayout(Class cls)
b3962a83 728{
b3962a83
A
729 if (cls && (cls->info & CLS_EXT)) {
730 return cls->ivar_layout;
731 } else {
7257e56c 732 return nil; // conservative scan
b3962a83
A
733 }
734}
735
736
737/***********************************************************************
738* class_getWeakIvarLayout
7257e56c 739* nil means no weak ivars.
b3962a83 740**********************************************************************/
8972963c 741const uint8_t *
7257e56c 742class_getWeakIvarLayout(Class cls)
b3962a83 743{
b3962a83
A
744 if (cls && (cls->info & CLS_EXT) && cls->ext) {
745 return cls->ext->weak_ivar_layout;
746 } else {
7257e56c 747 return nil; // no weak ivars
b3962a83
A
748 }
749}
750
751
752/***********************************************************************
753* class_setIvarLayout
7257e56c 754* nil means all-scanned. "" means non-scanned.
b3962a83 755**********************************************************************/
7257e56c 756void class_setIvarLayout(Class cls, const uint8_t *layout)
b3962a83 757{
b3962a83
A
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
31875a97 766 cls->ivar_layout = ustrdupMaybeNil(layout);
b3962a83
A
767}
768
769
770/***********************************************************************
771* class_setWeakIvarLayout
7257e56c 772* nil means no weak ivars.
b3962a83 773**********************************************************************/
7257e56c 774void class_setWeakIvarLayout(Class cls, const uint8_t *layout)
b3962a83 775{
b3962a83
A
776 if (!cls) return;
777
31875a97 778 mutex_locker_t lock(classLock);
b3962a83
A
779
780 allocateExt(cls);
781
782 // fixme leak
31875a97 783 cls->ext->weak_ivar_layout = ustrdupMaybeNil(layout);
b3962a83
A
784}
785
786
b3962a83
A
787/***********************************************************************
788* class_setVersion. Record the specified version with the class.
789**********************************************************************/
790void 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**********************************************************************/
799int class_getVersion(Class cls)
800{
801 if (!cls) return 0;
802 return (int)cls->version;
803}
804
805
8070259c
A
806/***********************************************************************
807* class_getName.
808**********************************************************************/
809const char *class_getName(Class cls)
810{
811 if (!cls) return "nil";
812 else return cls->demangledName();
813}
814
815
b3962a83
A
816/***********************************************************************
817* _class_getNonMetaClass.
818* Return the ordinary class for this class or metaclass.
819* Used by +initialize.
820**********************************************************************/
13ba007e 821static Class _class_getNonMetaClass(Class cls, id obj)
b3962a83
A
822{
823 // fixme ick
7257e56c 824 if (cls->isMetaClass()) {
31875a97
A
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) {
b3962a83
A
831 // Posee's meta's name is smashed and isn't in the class_hash,
832 // so objc_getClass doesn't work.
7257e56c
A
833 const char *baseName = strchr(cls->name, '%'); // get posee's real name
834 cls = objc_getClass(baseName);
31875a97
A
835 }
836 else {
7257e56c 837 cls = objc_getClass(cls->name);
b3962a83 838 }
1807f628 839 ASSERT(cls);
b3962a83
A
840 }
841
842 return cls;
13ba007e
A
843}
844
845
846Class class_initialize(Class cls, id inst) {
847 if (!cls->isInitialized()) {
848 initializeNonMetaClass (_class_getNonMetaClass(cls, inst));
849 }
850 return cls;
b3962a83
A
851}
852
853
cd5f04f5 854Cache _class_getCache(Class cls)
b3962a83
A
855{
856 return cls->cache;
857}
858
cd5f04f5 859void _class_setCache(Class cls, Cache cache)
b3962a83
A
860{
861 cls->cache = cache;
862}
863
cd5f04f5 864const char *_category_getName(Category cat)
b3962a83 865{
8972963c 866 return oldcategory(cat)->category_name;
b3962a83
A
867}
868
cd5f04f5 869const char *_category_getClassName(Category cat)
b3962a83 870{
8972963c 871 return oldcategory(cat)->class_name;
b3962a83
A
872}
873
cd5f04f5 874Class _category_getClass(Category cat)
b3962a83 875{
7257e56c 876 return objc_getClass(oldcategory(cat)->class_name);
b3962a83
A
877}
878
cd5f04f5 879IMP _category_getLoadMethod(Category cat)
b3962a83 880{
7257e56c 881 old_method_list *mlist = oldcategory(cat)->class_methods;
b3962a83
A
882 if (mlist) {
883 return lookupNamedMethodInMethodList(mlist, "load");
884 } else {
7257e56c 885 return nil;
b3962a83
A
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**********************************************************************/
66799735 904struct objc_method_list *class_nextMethodList(Class cls, void **it)
b3962a83 905{
b3962a83
A
906 OBJC_WARN_DEPRECATED;
907
31875a97
A
908 mutex_locker_t lock(methodListLock);
909 return (struct objc_method_list *) nextMethodList(cls, it);
b3962a83
A
910}
911
912
913/***********************************************************************
914* class_addMethods.
915*
916* Formerly class_addInstanceMethods ()
917**********************************************************************/
66799735 918void class_addMethods(Class cls, struct objc_method_list *meths)
b3962a83
A
919{
920 OBJC_WARN_DEPRECATED;
921
922 // Add the methods.
31875a97
A
923 {
924 mutex_locker_t lock(methodListLock);
925 _objc_insertMethods(cls, (old_method_list *)meths, nil);
926 }
b3962a83
A
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**********************************************************************/
66799735 938void class_removeMethods(Class cls, struct objc_method_list *meths)
b3962a83
A
939{
940 OBJC_WARN_DEPRECATED;
941
942 // Remove the methods
31875a97
A
943 {
944 mutex_locker_t lock(methodListLock);
945 _objc_removeMethods(cls, (old_method_list *)meths);
946 }
b3962a83
A
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**********************************************************************/
7257e56c 960IMP lookupNamedMethodInMethodList(old_method_list *mlist, const char *meth_name)
b3962a83 961{
7257e56c
A
962 old_method *m;
963 m = meth_name ? _findNamedMethodInList(mlist, meth_name) : nil;
964 return (m ? m->method_imp : nil);
b3962a83
A
965}
966
7257e56c 967static Method _class_getMethod(Class cls, SEL sel)
b3962a83 968{
31875a97
A
969 mutex_locker_t lock(methodListLock);
970 return (Method)_getMethod(cls, sel);
b3962a83
A
971}
972
7257e56c 973static Method _class_getMethodNoSuper(Class cls, SEL sel)
b3962a83 974{
31875a97
A
975 mutex_locker_t lock(methodListLock);
976 return (Method)_findMethodInClass(cls, sel);
b3962a83
A
977}
978
7257e56c 979static Method _class_getMethodNoSuper_nolock(Class cls, SEL sel)
7af964d1 980{
31875a97 981 methodListLock.assertLocked();
7257e56c 982 return (Method)_findMethodInClass(cls, sel);
7af964d1
A
983}
984
b3962a83 985
7257e56c
A
986/***********************************************************************
987* class_getInstanceMethod. Return the instance method for the
988* specified class and selector.
989**********************************************************************/
990Method class_getInstanceMethod(Class cls, SEL sel)
b3962a83 991{
7257e56c
A
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.
1807f628 1009 lookUpImpOrForward(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER);
7257e56c
A
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
1023BOOL class_conformsToProtocol(Class cls, Protocol *proto_gen)
1024{
1025 old_protocol *proto = oldprotocol(proto_gen);
7af964d1 1026
7257e56c 1027 if (!cls) return NO;
7af964d1 1028 if (!proto) return NO;
b3962a83 1029
7257e56c
A
1030 if (cls->ISA()->version >= 3) {
1031 old_protocol_list *list;
1032 for (list = cls->protocols; list != nil; list = list->next) {
b3962a83
A
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 }
7257e56c 1038 if (cls->ISA()->version <= 4) break;
b3962a83
A
1039 }
1040 }
1041 return NO;
1042}
1043
1044
7257e56c 1045static NXMapTable * posed_class_hash = nil;
b3962a83
A
1046
1047/***********************************************************************
1048* objc_getOrigClass.
1049**********************************************************************/
7257e56c 1050extern "C"
cd5f04f5 1051Class _objc_getOrigClass(const char *name)
b3962a83 1052{
b3962a83 1053 // Look for class among the posers
31875a97
A
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 }
b3962a83
A
1061
1062 // Not a poser. Do a normal lookup.
31875a97
A
1063 Class cls = objc_getClass (name);
1064 if (cls) return cls;
b3962a83 1065
31875a97
A
1066 _objc_inform ("class `%s' not linked into application", name);
1067 return nil;
b3962a83
A
1068}
1069
1070Class 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**********************************************************************/
7257e56c 1082static void _objc_addOrigClass (Class origClass)
b3962a83 1083{
31875a97 1084 mutex_locker_t lock(classLock);
b3962a83
A
1085
1086 // Create the poser's hash table on first use
1087 if (!posed_class_hash)
1088 {
31875a97 1089 posed_class_hash = NXCreateMapTable(NXStrValueMapPrototype, 8);
b3962a83
A
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);
b3962a83
A
1095}
1096
1097
1098/***********************************************************************
1099* change_class_references
1100* Change classrefs and superclass pointers from original to imposter
7257e56c 1101* But if copy!=nil, don't change copy->superclass.
b3962a83
A
1102* If changeSuperRefs==YES, also change [super message] classrefs.
1103* Used by class_poseAs and objc_setFutureClass
1104* classLock must be locked.
1105**********************************************************************/
7257e56c
A
1106void change_class_references(Class imposter,
1107 Class original,
1108 Class copy,
31875a97 1109 bool changeSuperRefs)
b3962a83
A
1110{
1111 header_info *hInfo;
7257e56c 1112 Class clsObject;
b3962a83
A
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 {
7257e56c 1122 if (clsObject->superclass == original)
b3962a83 1123 {
7257e56c
A
1124 clsObject->superclass = imposter;
1125 clsObject->ISA()->superclass = imposter->ISA();
b3962a83
A
1126 // We must flush caches here!
1127 break;
1128 }
1129
7257e56c 1130 clsObject = clsObject->superclass;
b3962a83
A
1131 }
1132 }
1133
1134 // Replace the original with the imposter in all class refs
1135 // Major loop - process all headers
c1e772c4 1136 for (hInfo = FirstHeader; hInfo != nil; hInfo = hInfo->getNext())
b3962a83 1137 {
7257e56c 1138 Class *cls_refs;
b3962a83
A
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**********************************************************************/
7257e56c 1160Class class_poseAs(Class imposter, Class original)
b3962a83 1161{
b3962a83 1162 char * imposterNamePtr;
7257e56c 1163 Class copy;
b3962a83
A
1164
1165 OBJC_WARN_DEPRECATED;
1166
1167 // Trivial case is easy
7257e56c
A
1168 if (imposter == original)
1169 return imposter;
b3962a83
A
1170
1171 // Imposter must be an immediate subclass of the original
7257e56c
A
1172 if (imposter->superclass != original) {
1173 __objc_error(imposter,
b3962a83
A
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) {
7257e56c 1180 __objc_error(imposter,
b3962a83
A
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.
7af964d1
A
1186#if TARGET_OS_WIN32
1187# define imposterNamePrefix "_%"
31875a97 1188 imposterNamePtr = malloc(strlen(original->name) + strlen(imposterNamePrefix) + 1);
b3962a83
A
1189 strcpy(imposterNamePtr, imposterNamePrefix);
1190 strcat(imposterNamePtr, original->name);
7af964d1
A
1191# undef imposterNamePrefix
1192#else
1193 asprintf(&imposterNamePtr, "_%%%s", original->name);
1194#endif
b3962a83
A
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.
31875a97 1211 copy = (Class)malloc(sizeof(objc_class));
7257e56c 1212 memmove(copy, imposter, sizeof(objc_class));
b3962a83 1213
31875a97 1214 mutex_locker_t lock(classLock);
b3962a83
A
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
7257e56c
A
1223 imposter->setInfo(CLS_POSING);
1224 imposter->ISA()->setInfo(CLS_POSING);
b3962a83
A
1225
1226 // Change the name of the imposter to that of the original class.
1227 imposter->name = original->name;
7257e56c 1228 imposter->ISA()->name = original->ISA()->name;
b3962a83
A
1229
1230 // Also copy the version field to avoid archiving problems.
1231 imposter->version = original->version;
1232
1233 // Change classrefs and superclass pointers
7257e56c 1234 // Don't change copy->superclass
b3962a83
A
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;
7257e56c 1240 original->ISA()->name = imposterNamePtr;
b3962a83
A
1241
1242 // Restore the imposter and the original class with their new names.
1243 NXHashInsert (class_hash, imposter);
1244 NXHashInsert (class_hash, original);
1245
7257e56c 1246 return imposter;
b3962a83
A
1247}
1248
1249
1250/***********************************************************************
7257e56c 1251* _objc_flush_caches. Flush the instance and class method caches
b3962a83
A
1252* of cls and all its subclasses.
1253*
1254* Specifying Nil for the class "all classes."
1255**********************************************************************/
7257e56c 1256static void flush_caches(Class target, bool flush_meta)
b3962a83 1257{
7257e56c 1258 bool collectALot = (target == nil);
b3962a83 1259 NXHashState state;
7257e56c 1260 Class clsObject;
b3962a83
A
1261#ifdef OBJC_INSTRUMENTED
1262 unsigned int classesVisited;
1263 unsigned int subclassCount;
1264#endif
1265
31875a97
A
1266 mutex_locker_t lock(classLock);
1267 mutex_locker_t lock2(cacheUpdateLock);
b3962a83
A
1268
1269 // Leaf classes are fastest because there are no subclass caches to flush.
1270 // fixme instrument
1271 if (target && (target->info & CLS_LEAF)) {
7257e56c 1272 _cache_flush (target);
b3962a83 1273
7257e56c
A
1274 if (target->ISA() && (target->ISA()->info & CLS_LEAF)) {
1275 _cache_flush (target->ISA());
b3962a83
A
1276 return; // done
1277 } else {
1278 // Reset target and handle it by one of the methods below.
7257e56c 1279 target = target->ISA();
b3962a83
A
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.
7257e56c 1290 if (!target || !target->superclass)
b3962a83
A
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 {
7257e56c 1300 Class metaClsObject;
b3962a83
A
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?
7257e56c
A
1309 metaClsObject = clsObject->ISA();
1310 if (target && metaClsObject && target->ISA() != metaClsObject->ISA()) {
b3962a83
A
1311 continue;
1312 }
1313
1314#ifdef OBJC_INSTRUMENTED
1315 subclassCount += 1;
1316#endif
1317
7257e56c
A
1318 _cache_flush (clsObject);
1319 if (flush_meta && metaClsObject != nil) {
1320 _cache_flush (metaClsObject);
b3962a83
A
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
7257e56c 1332 goto done;
b3962a83
A
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 {
7257e56c 1344 Class clsIter;
b3962a83
A
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
7257e56c 1366 _cache_flush (clsObject);
b3962a83 1367 if (flush_meta)
7257e56c 1368 _cache_flush (clsObject->ISA());
b3962a83
A
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
7257e56c 1377 else if (clsIter->ISA() == target)
b3962a83
A
1378 {
1379#ifdef OBJC_INSTRUMENTED
1380 subclassCount += 1;
1381#endif
7257e56c 1382 _cache_flush (clsObject->ISA());
b3962a83
A
1383 break;
1384 }
1385
1386 // Move up superclass chain
7257e56c
A
1387 // else if (clsIter->isInitialized())
1388 clsIter = clsIter->superclass;
b3962a83
A
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
7257e56c
A
1409
1410 done:
1411 if (collectALot) {
1412 _cache_collect(true);
1413 }
b3962a83
A
1414}
1415
1416
7257e56c
A
1417void _objc_flush_caches(Class target)
1418{
1419 flush_caches(target, YES);
1420}
1421
1422
1423
b3962a83
A
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**********************************************************************/
cd5f04f5 1429void flush_marked_caches(void)
b3962a83 1430{
7257e56c
A
1431 Class cls;
1432 Class supercls;
b3962a83
A
1433 NXHashState state;
1434
31875a97
A
1435 mutex_locker_t lock(classLock);
1436 mutex_locker_t lock2(cacheUpdateLock);
b3962a83
A
1437
1438 state = NXInitHashState(class_hash);
1439 while (NXNextHashState(class_hash, &state, (void**)&cls)) {
7257e56c 1440 for (supercls = cls; supercls; supercls = supercls->superclass) {
b3962a83 1441 if (supercls->info & CLS_FLUSH_CACHE) {
7257e56c 1442 _cache_flush(cls);
b3962a83
A
1443 break;
1444 }
1445 }
1446
7257e56c 1447 for (supercls = cls->ISA(); supercls; supercls = supercls->superclass) {
b3962a83 1448 if (supercls->info & CLS_FLUSH_CACHE) {
7257e56c 1449 _cache_flush(cls->ISA());
b3962a83
A
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) {
7257e56c 1458 cls->clearInfo(CLS_FLUSH_CACHE);
b3962a83 1459 }
7257e56c
A
1460 if (cls->ISA()->info & CLS_FLUSH_CACHE) {
1461 cls->ISA()->clearInfo(CLS_FLUSH_CACHE);
b3962a83
A
1462 }
1463 }
b3962a83
A
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**********************************************************************/
7257e56c 1475static old_method_list *get_base_method_list(Class cls)
b3962a83 1476{
7257e56c 1477 old_method_list **ptr;
b3962a83 1478
7257e56c
A
1479 if (!cls->methodLists) return nil;
1480 if (cls->info & CLS_NO_METHOD_ARRAY) return (old_method_list *)cls->methodLists;
b3962a83 1481 ptr = cls->methodLists;
7257e56c 1482 if (!*ptr || *ptr == END_OF_METHODS_LIST) return nil;
b3962a83
A
1483 while ( *ptr != 0 && *ptr != END_OF_METHODS_LIST ) { ptr++; }
1484 --ptr;
1485 return *ptr;
1486}
1487
1488
7257e56c 1489static IMP _class_getLoadMethod_nocheck(Class cls)
b3962a83 1490{
7257e56c
A
1491 old_method_list *mlist;
1492 mlist = get_base_method_list(cls->ISA());
b3962a83
A
1493 if (mlist) {
1494 return lookupNamedMethodInMethodList (mlist, "load");
1495 }
7257e56c 1496 return nil;
b3962a83
A
1497}
1498
1499
31875a97 1500bool _class_hasLoadMethod(Class cls)
b3962a83 1501{
7257e56c 1502 if (cls->ISA()->info & CLS_HAS_LOAD_METHOD) return YES;
31875a97 1503 return _class_getLoadMethod_nocheck(cls);
b3962a83
A
1504}
1505
1506
1507/***********************************************************************
7257e56c
A
1508* objc_class::getLoadMethod
1509* Returns cls's +load implementation, or nil if it doesn't have one.
b3962a83 1510**********************************************************************/
7257e56c 1511IMP objc_class::getLoadMethod()
b3962a83 1512{
7257e56c
A
1513 if (ISA()->info & CLS_HAS_LOAD_METHOD) {
1514 return _class_getLoadMethod_nocheck((Class)this);
b3962a83 1515 }
7257e56c 1516 return nil;
7af964d1 1517}
b3962a83 1518
b3962a83
A
1519ptrdiff_t ivar_getOffset(Ivar ivar)
1520{
8972963c 1521 return oldivar(ivar)->ivar_offset;
b3962a83
A
1522}
1523
1524const char *ivar_getName(Ivar ivar)
1525{
8972963c 1526 return oldivar(ivar)->ivar_name;
b3962a83
A
1527}
1528
1529const char *ivar_getTypeEncoding(Ivar ivar)
1530{
8972963c 1531 return oldivar(ivar)->ivar_type;
b3962a83
A
1532}
1533
1534
1535IMP method_getImplementation(Method m)
1536{
7257e56c 1537 if (!m) return nil;
8972963c 1538 return oldmethod(m)->method_imp;
b3962a83
A
1539}
1540
1541SEL method_getName(Method m)
1542{
7257e56c 1543 if (!m) return nil;
8972963c 1544 return oldmethod(m)->method_name;
b3962a83
A
1545}
1546
1547const char *method_getTypeEncoding(Method m)
1548{
7257e56c 1549 if (!m) return nil;
8972963c 1550 return oldmethod(m)->method_types;
b3962a83
A
1551}
1552
8972963c
A
1553unsigned int method_getSizeOfArguments(Method m)
1554{
1555 OBJC_WARN_DEPRECATED;
1556 if (!m) return 0;
1557 return encoding_getSizeOfArguments(method_getTypeEncoding(m));
1558}
1559
66799735
A
1560// This function was accidentally un-exported beginning in macOS 10.9.
1561// As of macOS 10.13 nobody had complained.
1562/*
8972963c
A
1563unsigned 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}
66799735 1571*/
8972963c
A
1572
1573
bd8dfcfc 1574spinlock_t impLock;
7af964d1
A
1575
1576IMP method_setImplementation(Method m_gen, IMP imp)
b3962a83 1577{
7af964d1 1578 IMP old;
7257e56c
A
1579 old_method *m = oldmethod(m_gen);
1580 if (!m) return nil;
1581 if (!imp) return nil;
7af964d1 1582
31875a97 1583 impLock.lock();
7af964d1
A
1584 old = m->method_imp;
1585 m->method_imp = imp;
31875a97 1586 impLock.unlock();
b3962a83
A
1587 return old;
1588}
1589
1590
7af964d1
A
1591void method_exchangeImplementations(Method m1_gen, Method m2_gen)
1592{
1593 IMP m1_imp;
7257e56c
A
1594 old_method *m1 = oldmethod(m1_gen);
1595 old_method *m2 = oldmethod(m2_gen);
7af964d1
A
1596 if (!m1 || !m2) return;
1597
31875a97 1598 impLock.lock();
7af964d1
A
1599 m1_imp = m1->method_imp;
1600 m1->method_imp = m2->method_imp;
1601 m2->method_imp = m1_imp;
31875a97 1602 impLock.unlock();
7af964d1
A
1603}
1604
1605
b3962a83
A
1606struct objc_method_description * method_getDescription(Method m)
1607{
7257e56c 1608 if (!m) return nil;
b3962a83
A
1609 return (struct objc_method_description *)oldmethod(m);
1610}
1611
1612
8972963c
A
1613const char *property_getName(objc_property_t prop)
1614{
1615 return oldproperty(prop)->name;
1616}
1617
1618const char *property_getAttributes(objc_property_t prop)
1619{
1620 return oldproperty(prop)->attributes;
1621}
1622
1623objc_property_attribute_t *property_copyAttributeList(objc_property_t prop,
1624 unsigned int *outCount)
1625{
1626 if (!prop) {
1627 if (outCount) *outCount = 0;
7257e56c 1628 return nil;
8972963c
A
1629 }
1630
31875a97
A
1631 mutex_locker_t lock(classLock);
1632 return copyPropertyAttributeList(oldproperty(prop)->attributes,outCount);
8972963c
A
1633}
1634
1635char * property_copyAttributeValue(objc_property_t prop, const char *name)
1636{
7257e56c 1637 if (!prop || !name || *name == '\0') return nil;
8972963c 1638
31875a97
A
1639 mutex_locker_t lock(classLock);
1640 return copyPropertyAttributeValue(oldproperty(prop)->attributes, name);
8972963c
A
1641}
1642
1643
b3962a83
A
1644/***********************************************************************
1645* class_addMethod
1646**********************************************************************/
7257e56c 1647static IMP _class_addMethod(Class cls, SEL name, IMP imp,
31875a97 1648 const char *types, bool replace)
b3962a83 1649{
7257e56c
A
1650 old_method *m;
1651 IMP result = nil;
b3962a83
A
1652
1653 if (!types) types = "";
1654
31875a97 1655 mutex_locker_t lock(methodListLock);
b3962a83 1656
b3962a83
A
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
7257e56c 1666 old_method_list *mlist =
31875a97 1667 (old_method_list *)calloc(sizeof(old_method_list), 1);
7af964d1 1668 mlist->obsolete = fixed_up_method_list;
b3962a83
A
1669 mlist->method_count = 1;
1670 mlist->method_list[0].method_name = name;
31875a97 1671 mlist->method_list[0].method_types = strdup(types);
c1e772c4 1672 mlist->method_list[0].method_imp = imp;
b3962a83 1673
7257e56c 1674 _objc_insertMethods(cls, mlist, nil);
b3962a83 1675 if (!(cls->info & CLS_CONSTRUCTING)) {
7257e56c 1676 flush_caches(cls, NO);
b3962a83
A
1677 } else {
1678 // in-construction class has no subclasses
7257e56c 1679 flush_cache(cls);
b3962a83 1680 }
7257e56c 1681 result = nil;
b3962a83
A
1682 }
1683
b3962a83
A
1684 return result;
1685}
1686
1687
1688/***********************************************************************
1689* class_addMethod
1690**********************************************************************/
1691BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
1692{
7af964d1 1693 IMP old;
b3962a83
A
1694 if (!cls) return NO;
1695
7af964d1 1696 old = _class_addMethod(cls, name, imp, types, NO);
31875a97 1697 return !old;
b3962a83
A
1698}
1699
1700
1701/***********************************************************************
1702* class_replaceMethod
1703**********************************************************************/
1704IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
1705{
7257e56c 1706 if (!cls) return nil;
b3962a83
A
1707
1708 return _class_addMethod(cls, name, imp, types, YES);
1709}
1710
1711
1712/***********************************************************************
1713* class_addIvar
1714**********************************************************************/
7257e56c 1715BOOL class_addIvar(Class cls, const char *name, size_t size,
b3962a83
A
1716 uint8_t alignment, const char *type)
1717{
31875a97 1718 bool result = YES;
b3962a83
A
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 = "";
7257e56c 1725 if (name && 0 == strcmp(name, "")) name = nil;
b3962a83 1726
31875a97 1727 mutex_locker_t lock(classLock);
b3962a83
A
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) {
7257e56c 1742 old_ivar_list *old = cls->ivars;
b3962a83
A
1743 size_t oldSize;
1744 int newCount;
7257e56c 1745 old_ivar *ivar;
b3962a83
A
1746 size_t alignBytes;
1747 size_t misalign;
1748
1749 if (old) {
7257e56c
A
1750 oldSize = sizeof(old_ivar_list) +
1751 (old->ivar_count - 1) * sizeof(old_ivar);
b3962a83
A
1752 newCount = 1 + old->ivar_count;
1753 } else {
7257e56c 1754 oldSize = sizeof(old_ivar_list) - sizeof(old_ivar);
b3962a83
A
1755 newCount = 1;
1756 }
1757
1758 // allocate new ivar list
7257e56c 1759 cls->ivars = (old_ivar_list *)
31875a97 1760 calloc(oldSize+sizeof(old_ivar), 1);
b3962a83
A
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
31875a97
A
1767 ivar->ivar_name = strdup(name);
1768 ivar->ivar_type = strdup(type);
b3962a83
A
1769
1770 // align if necessary
1771 alignBytes = 1 << alignment;
1772 misalign = cls->instance_size % alignBytes;
7af964d1 1773 if (misalign) cls->instance_size += (long)(alignBytes - misalign);
b3962a83
A
1774
1775 // set ivar offset and increase instance size
1776 ivar->ivar_offset = (int)cls->instance_size;
7af964d1 1777 cls->instance_size += (long)size;
b3962a83
A
1778 }
1779
b3962a83
A
1780 return result;
1781}
1782
1783
1784/***********************************************************************
1785* class_addProtocol
1786**********************************************************************/
7257e56c 1787BOOL class_addProtocol(Class cls, Protocol *protocol_gen)
b3962a83 1788{
7257e56c
A
1789 old_protocol *protocol = oldprotocol(protocol_gen);
1790 old_protocol_list *plist;
b3962a83
A
1791
1792 if (!cls) return NO;
7257e56c 1793 if (class_conformsToProtocol(cls, protocol_gen)) return NO;
b3962a83 1794
31875a97 1795 mutex_locker_t lock(classLock);
b3962a83
A
1796
1797 // fixme optimize - protocol list doesn't escape?
31875a97 1798 plist = (old_protocol_list*)calloc(sizeof(old_protocol_list), 1);
b3962a83
A
1799 plist->count = 1;
1800 plist->list[0] = protocol;
1801 plist->next = cls->protocols;
1802 cls->protocols = plist;
1803
1804 // fixme metaclass?
1805
b3962a83
A
1806 return YES;
1807}
1808
1809
1810/***********************************************************************
8972963c
A
1811* _class_addProperties
1812* Internal helper to add properties to a class.
1813* Used by category attachment and class_addProperty()
1814* Locking: acquires classLock
b3962a83 1815**********************************************************************/
31875a97 1816bool
7257e56c
A
1817_class_addProperties(Class cls,
1818 old_property_list *additions)
b3962a83 1819{
7257e56c 1820 old_property_list *newlist;
7af964d1 1821
8972963c 1822 if (!(cls->info & CLS_EXT)) return NO;
b3962a83 1823
7257e56c 1824 newlist = (old_property_list *)
31875a97 1825 memdup(additions, sizeof(*newlist) - sizeof(newlist->first)
b3962a83
A
1826 + (additions->entsize * additions->count));
1827
31875a97 1828 mutex_locker_t lock(classLock);
b3962a83
A
1829
1830 allocateExt(cls);
1831 if (!cls->ext->propertyLists) {
1832 // cls has no properties - simply use this list
7257e56c
A
1833 cls->ext->propertyLists = (old_property_list **)newlist;
1834 cls->setInfo(CLS_NO_PROPERTY_ARRAY);
b3962a83
A
1835 }
1836 else if (cls->info & CLS_NO_PROPERTY_ARRAY) {
1837 // cls has one property list - make a new array
7257e56c 1838 old_property_list **newarray = (old_property_list **)
31875a97 1839 malloc(3 * sizeof(*newarray));
b3962a83 1840 newarray[0] = newlist;
7257e56c
A
1841 newarray[1] = (old_property_list *)cls->ext->propertyLists;
1842 newarray[2] = nil;
b3962a83 1843 cls->ext->propertyLists = newarray;
7257e56c 1844 cls->clearInfo(CLS_NO_PROPERTY_ARRAY);
b3962a83
A
1845 }
1846 else {
1847 // cls has a property array - make a bigger one
7257e56c 1848 old_property_list **newarray;
b3962a83
A
1849 int count = 0;
1850 while (cls->ext->propertyLists[count]) count++;
7257e56c 1851 newarray = (old_property_list **)
31875a97 1852 malloc((count+2) * sizeof(*newarray));
b3962a83
A
1853 newarray[0] = newlist;
1854 memcpy(&newarray[1], &cls->ext->propertyLists[0],
1855 count * sizeof(*newarray));
7257e56c 1856 newarray[count+1] = nil;
b3962a83
A
1857 free(cls->ext->propertyLists);
1858 cls->ext->propertyLists = newarray;
1859 }
1860
8972963c
A
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**********************************************************************/
31875a97 1870static bool
7257e56c 1871_class_addProperty(Class cls, const char *name,
8972963c 1872 const objc_property_attribute_t *attrs, unsigned int count,
31875a97 1873 bool replace)
8972963c 1874{
8972963c
A
1875 if (!cls) return NO;
1876 if (!name) return NO;
1877
7257e56c 1878 old_property *prop = oldproperty(class_getProperty(cls, name));
8972963c
A
1879 if (prop && !replace) {
1880 // already exists, refuse to replace
1881 return NO;
1882 }
1883 else if (prop) {
1884 // replace existing
31875a97 1885 mutex_locker_t lock(classLock);
8972963c
A
1886 try_free(prop->attributes);
1887 prop->attributes = copyPropertyAttributeString(attrs, count);
8972963c
A
1888 return YES;
1889 }
1890 else {
1891 // add new
7257e56c
A
1892 old_property_list proplist;
1893 proplist.entsize = sizeof(old_property);
8972963c 1894 proplist.count = 1;
31875a97 1895 proplist.first.name = strdup(name);
8972963c
A
1896 proplist.first.attributes = copyPropertyAttributeString(attrs, count);
1897
1898 return _class_addProperties(cls, &proplist);
1899 }
1900}
1901
1902BOOL
7257e56c 1903class_addProperty(Class cls, const char *name,
8972963c
A
1904 const objc_property_attribute_t *attrs, unsigned int n)
1905{
7257e56c 1906 return _class_addProperty(cls, name, attrs, n, NO);
8972963c
A
1907}
1908
1909void
7257e56c 1910class_replaceProperty(Class cls, const char *name,
8972963c
A
1911 const objc_property_attribute_t *attrs, unsigned int n)
1912{
7257e56c 1913 _class_addProperty(cls, name, attrs, n, YES);
b3962a83
A
1914}
1915
1916
1917/***********************************************************************
1918* class_copyProtocolList. Returns a heap block containing the
7257e56c 1919* protocols implemented by the class, or nil if the class
b3962a83
A
1920* implements no protocols. Caller must free the block.
1921* Does not copy any superclass's protocols.
1922**********************************************************************/
8972963c 1923Protocol * __unsafe_unretained *
7257e56c 1924class_copyProtocolList(Class cls, unsigned int *outCount)
b3962a83 1925{
7257e56c
A
1926 old_protocol_list *plist;
1927 Protocol **result = nil;
b3962a83 1928 unsigned int count = 0;
7af964d1 1929 unsigned int p;
b3962a83
A
1930
1931 if (!cls) {
1932 if (outCount) *outCount = 0;
7257e56c 1933 return nil;
b3962a83
A
1934 }
1935
31875a97 1936 mutex_locker_t lock(classLock);
b3962a83 1937
7257e56c 1938 for (plist = cls->protocols; plist != nil; plist = plist->next) {
b3962a83
A
1939 count += (int)plist->count;
1940 }
1941
1942 if (count > 0) {
7257e56c 1943 result = (Protocol **)malloc((count+1) * sizeof(Protocol *));
b3962a83
A
1944
1945 for (p = 0, plist = cls->protocols;
7257e56c 1946 plist != nil;
b3962a83
A
1947 plist = plist->next)
1948 {
7af964d1 1949 int i;
b3962a83
A
1950 for (i = 0; i < plist->count; i++) {
1951 result[p++] = (Protocol *)plist->list[i];
1952 }
1953 }
7257e56c 1954 result[p] = nil;
b3962a83
A
1955 }
1956
b3962a83
A
1957 if (outCount) *outCount = count;
1958 return result;
1959}
1960
1961
1962/***********************************************************************
1963* class_getProperty. Return the named property.
1964**********************************************************************/
7257e56c 1965objc_property_t class_getProperty(Class cls, const char *name)
b3962a83 1966{
7257e56c 1967 if (!cls || !name) return nil;
b3962a83 1968
31875a97 1969 mutex_locker_t lock(classLock);
b3962a83 1970
31875a97 1971 for (; cls; cls = cls->superclass) {
b3962a83 1972 uintptr_t iterator = 0;
7257e56c 1973 old_property_list *plist;
b3962a83
A
1974 while ((plist = nextPropertyList(cls, &iterator))) {
1975 uint32_t i;
1976 for (i = 0; i < plist->count; i++) {
7257e56c 1977 old_property *p = property_list_nth(plist, i);
b3962a83 1978 if (0 == strcmp(name, p->name)) {
31875a97 1979 return (objc_property_t)p;
b3962a83
A
1980 }
1981 }
1982 }
1983 }
1984
31875a97 1985 return nil;
b3962a83
A
1986}
1987
1988
1989/***********************************************************************
1990* class_copyPropertyList. Returns a heap block containing the
7257e56c 1991* properties declared in the class, or nil if the class
b3962a83
A
1992* declares no properties. Caller must free the block.
1993* Does not copy any superclass's properties.
1994**********************************************************************/
7257e56c 1995objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
b3962a83 1996{
7257e56c 1997 old_property_list *plist;
b3962a83 1998 uintptr_t iterator = 0;
7257e56c 1999 old_property **result = nil;
b3962a83
A
2000 unsigned int count = 0;
2001 unsigned int p, i;
2002
2003 if (!cls) {
2004 if (outCount) *outCount = 0;
7257e56c 2005 return nil;
b3962a83
A
2006 }
2007
31875a97 2008 mutex_locker_t lock(classLock);
b3962a83
A
2009
2010 iterator = 0;
2011 while ((plist = nextPropertyList(cls, &iterator))) {
2012 count += plist->count;
2013 }
2014
2015 if (count > 0) {
7257e56c 2016 result = (old_property **)malloc((count+1) * sizeof(old_property *));
b3962a83
A
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 }
7257e56c 2025 result[p] = nil;
b3962a83
A
2026 }
2027
b3962a83 2028 if (outCount) *outCount = count;
8972963c 2029 return (objc_property_t *)result;
b3962a83
A
2030}
2031
2032
2033/***********************************************************************
2034* class_copyMethodList. Returns a heap block containing the
7257e56c 2035* methods implemented by the class, or nil if the class
b3962a83
A
2036* implements no methods. Caller must free the block.
2037* Does not copy any superclass's methods.
2038**********************************************************************/
7257e56c 2039Method *class_copyMethodList(Class cls, unsigned int *outCount)
b3962a83 2040{
7257e56c
A
2041 old_method_list *mlist;
2042 void *iterator = nil;
2043 Method *result = nil;
b3962a83 2044 unsigned int count = 0;
7af964d1 2045 unsigned int m;
b3962a83
A
2046
2047 if (!cls) {
2048 if (outCount) *outCount = 0;
7257e56c 2049 return nil;
b3962a83
A
2050 }
2051
31875a97 2052 mutex_locker_t lock(methodListLock);
b3962a83 2053
7257e56c 2054 iterator = nil;
b3962a83
A
2055 while ((mlist = nextMethodList(cls, &iterator))) {
2056 count += mlist->method_count;
2057 }
2058
2059 if (count > 0) {
7257e56c 2060 result = (Method *)malloc((count+1) * sizeof(Method));
b3962a83
A
2061
2062 m = 0;
7257e56c 2063 iterator = nil;
b3962a83 2064 while ((mlist = nextMethodList(cls, &iterator))) {
7af964d1 2065 int i;
b3962a83 2066 for (i = 0; i < mlist->method_count; i++) {
c1e772c4 2067 result[m++] = (Method)&mlist->method_list[i];
b3962a83
A
2068 }
2069 }
7257e56c 2070 result[m] = nil;
b3962a83
A
2071 }
2072
b3962a83
A
2073 if (outCount) *outCount = count;
2074 return result;
2075}
2076
2077
2078/***********************************************************************
2079* class_copyIvarList. Returns a heap block containing the
7257e56c 2080* ivars declared in the class, or nil if the class
b3962a83
A
2081* declares no ivars. Caller must free the block.
2082* Does not copy any superclass's ivars.
2083**********************************************************************/
7257e56c 2084Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
b3962a83 2085{
7257e56c 2086 Ivar *result = nil;
b3962a83 2087 unsigned int count = 0;
7af964d1 2088 int i;
b3962a83
A
2089
2090 if (!cls) {
2091 if (outCount) *outCount = 0;
7257e56c 2092 return nil;
b3962a83
A
2093 }
2094
2095 if (cls->ivars) {
2096 count = cls->ivars->ivar_count;
2097 }
2098
2099 if (count > 0) {
7257e56c 2100 result = (Ivar *)malloc((count+1) * sizeof(Ivar));
b3962a83
A
2101
2102 for (i = 0; i < cls->ivars->ivar_count; i++) {
2103 result[i] = (Ivar)&cls->ivars->ivar_list[i];
2104 }
7257e56c 2105 result[i] = nil;
b3962a83
A
2106 }
2107
2108 if (outCount) *outCount = count;
2109 return result;
2110}
2111
2112
2113/***********************************************************************
2114* objc_allocateClass.
2115**********************************************************************/
cd5f04f5 2116
31875a97 2117void set_superclass(Class cls, Class supercls, bool cls_is_new)
b3962a83 2118{
7257e56c 2119 Class meta = cls->ISA();
b3962a83
A
2120
2121 if (supercls) {
7257e56c
A
2122 cls->superclass = supercls;
2123 meta->superclass = supercls->ISA();
2124 meta->initIsa(supercls->ISA()->ISA());
b3962a83 2125
8972963c
A
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;
7257e56c 2129 else cls->setInfo(CLS_HAS_CXX_STRUCTORS);
8972963c
A
2130 }
2131
b3962a83
A
2132 // Superclass is no longer a leaf for cache flushing
2133 if (supercls->info & CLS_LEAF) {
7257e56c
A
2134 supercls->clearInfo(CLS_LEAF);
2135 supercls->ISA()->clearInfo(CLS_LEAF);
b3962a83
A
2136 }
2137 } else {
7257e56c
A
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
b3962a83
A
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.)
7257e56c
A
2145 cls->clearInfo(CLS_LEAF);
2146 meta->clearInfo(CLS_LEAF);
b3962a83
A
2147 }
2148}
2149
8972963c
A
2150// &UnsetLayout is the default ivar layout during class construction
2151static const uint8_t UnsetLayout = 0;
2152
7257e56c 2153Class objc_initializeClassPair(Class supercls, const char *name, Class cls, Class meta)
b3962a83 2154{
b3962a83 2155 // Connect to superclasses and metaclasses
7257e56c 2156 cls->initIsa(meta);
8972963c 2157 set_superclass(cls, supercls, YES);
b3962a83
A
2158
2159 // Set basic info
31875a97
A
2160 cls->name = strdup(name);
2161 meta->name = strdup(name);
b3962a83
A
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.
7af964d1
A
2168 if (supercls) {
2169 cls->instance_size = supercls->instance_size;
7257e56c 2170 meta->instance_size = supercls->ISA()->instance_size;
b3962a83 2171 } else {
7257e56c
A
2172 cls->instance_size = sizeof(Class); // just an isa
2173 meta->instance_size = sizeof(objc_class);
b3962a83
A
2174 }
2175
8972963c 2176 // No ivars. No methods. Empty cache. No protocols. No layout. Empty ext.
7257e56c
A
2177 cls->ivars = nil;
2178 cls->methodLists = nil;
b3962a83 2179 cls->cache = (Cache)&_objc_empty_cache;
7257e56c 2180 cls->protocols = nil;
8972963c 2181 cls->ivar_layout = &UnsetLayout;
7257e56c 2182 cls->ext = nil;
8972963c
A
2183 allocateExt(cls);
2184 cls->ext->weak_ivar_layout = &UnsetLayout;
b3962a83 2185
7257e56c
A
2186 meta->ivars = nil;
2187 meta->methodLists = nil;
b3962a83 2188 meta->cache = (Cache)&_objc_empty_cache;
7257e56c
A
2189 meta->protocols = nil;
2190 meta->ext = nil;
8972963c 2191
7257e56c 2192 return cls;
7af964d1
A
2193}
2194
7257e56c 2195Class objc_allocateClassPair(Class supercls, const char *name,
7af964d1
A
2196 size_t extraBytes)
2197{
7af964d1
A
2198 Class cls, meta;
2199
7257e56c 2200 if (objc_getClass(name)) return nil;
7af964d1
A
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
7257e56c 2205 return nil;
7af964d1
A
2206 }
2207
2208 // Allocate new classes.
2209 if (supercls) {
7257e56c
A
2210 cls = _calloc_class(supercls->ISA()->alignedInstanceSize() + extraBytes);
2211 meta = _calloc_class(supercls->ISA()->ISA()->alignedInstanceSize() + extraBytes);
7af964d1 2212 } else {
7257e56c
A
2213 cls = _calloc_class(sizeof(objc_class) + extraBytes);
2214 meta = _calloc_class(sizeof(objc_class) + extraBytes);
7af964d1
A
2215 }
2216
b3962a83 2217
7257e56c 2218 objc_initializeClassPair(supercls, name, cls, meta);
7af964d1 2219
7257e56c 2220 return cls;
b3962a83
A
2221}
2222
2223
7257e56c 2224void objc_registerClassPair(Class cls)
b3962a83 2225{
b3962a83 2226 if ((cls->info & CLS_CONSTRUCTED) ||
7257e56c 2227 (cls->ISA()->info & CLS_CONSTRUCTED))
b3962a83
A
2228 {
2229 _objc_inform("objc_registerClassPair: class '%s' was already "
2230 "registered!", cls->name);
2231 return;
2232 }
2233
2234 if (!(cls->info & CLS_CONSTRUCTING) ||
7257e56c 2235 !(cls->ISA()->info & CLS_CONSTRUCTING))
b3962a83
A
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
31875a97 2248 mutex_locker_t lock(classLock);
b3962a83 2249
b3962a83
A
2250 // Clear "under construction" bit, set "done constructing" bit
2251 cls->info &= ~CLS_CONSTRUCTING;
7257e56c 2252 cls->ISA()->info &= ~CLS_CONSTRUCTING;
b3962a83 2253 cls->info |= CLS_CONSTRUCTED;
7257e56c 2254 cls->ISA()->info |= CLS_CONSTRUCTED;
b3962a83
A
2255
2256 NXHashInsertIfAbsent(class_hash, cls);
b3962a83
A
2257}
2258
2259
7257e56c 2260Class objc_duplicateClass(Class original, const char *name, size_t extraBytes)
b3962a83
A
2261{
2262 unsigned int count, i;
7257e56c
A
2263 old_method **originalMethods;
2264 old_method_list *duplicateMethods;
2265 // Don't use sizeof(objc_class) here because
b3962a83
A
2266 // instance_size has historically contained two extra words,
2267 // and instance_size is what objc_getIndexedIvars() actually uses.
7257e56c
A
2268 Class duplicate =
2269 _calloc_class(original->ISA()->alignedInstanceSize() + extraBytes);
b3962a83 2270
7257e56c
A
2271 duplicate->initIsa(original->ISA());
2272 duplicate->superclass = original->superclass;
b3962a83
A
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) {
31875a97 2285 duplicate->ext = (old_class_ext *)malloc(original->ext->size);
b3962a83
A
2286 memcpy(duplicate->ext, original->ext, original->ext->size);
2287 } else {
7257e56c 2288 duplicate->ext = nil;
b3962a83
A
2289 }
2290 }
2291
2292 // Method lists are deep-copied so they can be stomped.
7257e56c 2293 originalMethods = (old_method **)class_copyMethodList(original, &count);
b3962a83 2294 if (originalMethods) {
7257e56c
A
2295 duplicateMethods = (old_method_list *)
2296 calloc(sizeof(old_method_list) +
2297 (count-1)*sizeof(old_method), 1);
7af964d1 2298 duplicateMethods->obsolete = fixed_up_method_list;
b3962a83
A
2299 duplicateMethods->method_count = count;
2300 for (i = 0; i < count; i++) {
2301 duplicateMethods->method_list[i] = *(originalMethods[i]);
2302 }
7257e56c 2303 duplicate->methodLists = (old_method_list **)duplicateMethods;
b3962a83
A
2304 duplicate->info |= CLS_NO_METHOD_ARRAY;
2305 free(originalMethods);
2306 }
2307
31875a97 2308 mutex_locker_t lock(classLock);
b3962a83 2309 NXHashInsert(class_hash, duplicate);
b3962a83 2310
7257e56c 2311 return duplicate;
b3962a83
A
2312}
2313
2314
7257e56c 2315void objc_disposeClassPair(Class cls)
b3962a83 2316{
b3962a83 2317 if (!(cls->info & (CLS_CONSTRUCTED|CLS_CONSTRUCTING)) ||
7257e56c 2318 !(cls->ISA()->info & (CLS_CONSTRUCTED|CLS_CONSTRUCTING)))
b3962a83
A
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
31875a97 2333 mutex_locker_t lock(classLock);
b3962a83 2334 NXHashRemove(class_hash, cls);
7257e56c 2335 unload_class(cls->ISA());
b3962a83
A
2336 unload_class(cls);
2337}
2338
2339
8070259c
A
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**********************************************************************/
2349id
2350objc_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()) {
1807f628 2359 return object_cxxConstructFromClass(obj, cls, OBJECT_CONSTRUCT_NONE);
8070259c
A
2360 } else {
2361 return obj;
2362 }
2363}
2364
8972963c 2365
b3962a83 2366/***********************************************************************
8972963c
A
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**********************************************************************/
cd5f04f5 2372id
8972963c
A
2373_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone)
2374{
8070259c 2375 void *bytes;
8972963c
A
2376 size_t size;
2377
2378 // Can't create something for nothing
2379 if (!cls) return nil;
2380
2381 // Allocate and initialize
7257e56c 2382 size = cls->alignedInstanceSize() + extraBytes;
8972963c
A
2383
2384 // CF requires all objects be at least 16 bytes.
2385 if (size < 16) size = 16;
2386
8972963c 2387 if (zone) {
8070259c 2388 bytes = malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
8972963c 2389 } else {
8070259c 2390 bytes = calloc(1, size);
8972963c
A
2391 }
2392
8070259c 2393 return objc_constructInstance(cls, bytes);
8972963c
A
2394}
2395
2396
2397/***********************************************************************
2398* _class_createInstance. Allocate an instance of the specified
b3962a83 2399* class with the specified number of bytes for indexed variables, in
8972963c 2400* the default zone, using _class_createInstanceFromZone.
b3962a83 2401**********************************************************************/
8972963c 2402static id _class_createInstance(Class cls, size_t extraBytes)
b3962a83 2403{
7257e56c 2404 return _class_createInstanceFromZone (cls, extraBytes, nil);
b3962a83
A
2405}
2406
2407
8972963c 2408static id _object_copyFromZone(id oldObj, size_t extraBytes, void *zone)
b3962a83
A
2409{
2410 id obj;
2411 size_t size;
2412
2413 if (!oldObj) return nil;
2414
7257e56c
A
2415 obj = (*_zoneAlloc)(oldObj->ISA(), extraBytes, zone);
2416 size = oldObj->ISA()->alignedInstanceSize() + extraBytes;
7af964d1 2417
b3962a83 2418 // fixme need C++ copy constructor
c1e772c4 2419 memmove(obj, oldObj, size);
7af964d1 2420
c1e772c4 2421 fixupCopiedIvars(obj, oldObj);
7af964d1 2422
b3962a83
A
2423 return obj;
2424}
2425
8972963c
A
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.
8972963c
A
2433* CoreFoundation and other clients do call this under GC.
2434**********************************************************************/
2435void *objc_destructInstance(id obj)
2436{
2437 if (obj) {
7257e56c 2438 Class isa = obj->getIsa();
8972963c 2439
7257e56c 2440 if (isa->hasCxxDtor()) {
8972963c
A
2441 object_cxxDestruct(obj);
2442 }
2443
7257e56c 2444 if (isa->instancesHaveAssociatedObjects()) {
8972963c
A
2445 _object_remove_assocations(obj);
2446 }
2447
c1e772c4 2448 objc_clear_deallocating(obj);
8972963c
A
2449 }
2450
2451 return obj;
2452}
2453
2454static id
2455_object_dispose(id anObject)
2456{
2457 if (anObject==nil) return nil;
2458
2459 objc_destructInstance(anObject);
2460
c1e772c4
A
2461 anObject->initIsa(_objc_getFreedObjectClass ());
2462
8972963c
A
2463 free(anObject);
2464 return nil;
2465}
2466
2467static id _object_copy(id oldObj, size_t extraBytes)
b3962a83
A
2468{
2469 void *z = malloc_zone_from_ptr(oldObj);
8972963c 2470 return _object_copyFromZone(oldObj, extraBytes,
b3962a83
A
2471 z ? z : malloc_default_zone());
2472}
2473
7257e56c 2474static id _object_reallocFromZone(id anObject, size_t nBytes, void *zone)
b3962a83
A
2475{
2476 id newObject;
2477 Class tmp;
2478
2479 if (anObject == nil)
2480 __objc_error(nil, "reallocating nil object");
2481
7257e56c 2482 if (anObject->ISA() == _objc_getFreedObjectClass ())
b3962a83
A
2483 __objc_error(anObject, "reallocating freed object");
2484
7257e56c 2485 if (nBytes < anObject->ISA()->alignedInstanceSize())
b3962a83
A
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
7257e56c
A
2492 tmp = anObject->ISA();
2493 anObject->initIsa(_objc_getFreedObjectClass ());
2494 newObject = (id)malloc_zone_realloc((malloc_zone_t *)zone, anObject, nBytes);
b3962a83 2495 if (newObject) {
7257e56c 2496 newObject->initIsa(tmp);
b3962a83
A
2497 } else {
2498 // realloc failed, anObject is still alive
7257e56c 2499 anObject->initIsa(tmp);
b3962a83
A
2500 }
2501 return newObject;
2502}
2503
2504
8972963c 2505static id _object_realloc(id anObject, size_t nBytes)
b3962a83
A
2506{
2507 void *z = malloc_zone_from_ptr(anObject);
8972963c 2508 return _object_reallocFromZone(anObject,
b3962a83
A
2509 nBytes,
2510 z ? z : malloc_default_zone());
2511}
2512
8972963c
A
2513id (*_alloc)(Class, size_t) = _class_createInstance;
2514id (*_copy)(id, size_t) = _object_copy;
2515id (*_realloc)(id, size_t) = _object_realloc;
2516id (*_dealloc)(id) = _object_dispose;
2517id (*_zoneAlloc)(Class, size_t, void *) = _class_createInstanceFromZone;
2518id (*_zoneCopy)(id, size_t, void *) = _object_copyFromZone;
2519id (*_zoneRealloc)(id, size_t, void *) = _object_reallocFromZone;
7af964d1 2520void (*_error)(id, const char *, va_list) = _objc_error;
b3962a83
A
2521
2522
2523id class_createInstance(Class cls, size_t extraBytes)
2524{
c1e772c4 2525 return (*_alloc)(cls, extraBytes);
b3962a83
A
2526}
2527
2528id class_createInstanceFromZone(Class cls, size_t extraBytes, void *z)
2529{
2530 OBJC_WARN_DEPRECATED;
c1e772c4 2531 return (*_zoneAlloc)(cls, extraBytes, z);
b3962a83
A
2532}
2533
1807f628
A
2534id
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
8972963c
A
2549unsigned class_createInstances(Class cls, size_t extraBytes,
2550 id *results, unsigned num_requested)
2551{
c1e772c4 2552 if (_alloc == &_class_createInstance) {
7257e56c 2553 return _class_createInstancesFromZone(cls, extraBytes, nil,
8972963c
A
2554 results, num_requested);
2555 } else {
2556 // _alloc in use, which isn't understood by the batch allocator
2557 return 0;
2558 }
2559}
2560
b3962a83
A
2561id object_copy(id obj, size_t extraBytes)
2562{
c1e772c4 2563 return (*_copy)(obj, extraBytes);
b3962a83
A
2564}
2565
2566id object_copyFromZone(id obj, size_t extraBytes, void *z)
2567{
2568 OBJC_WARN_DEPRECATED;
c1e772c4 2569 return (*_zoneCopy)(obj, extraBytes, z);
b3962a83
A
2570}
2571
2572id object_dispose(id obj)
2573{
c1e772c4 2574 return (*_dealloc)(obj);
b3962a83
A
2575}
2576
2577id object_realloc(id obj, size_t nBytes)
2578{
2579 OBJC_WARN_DEPRECATED;
c1e772c4 2580 return (*_realloc)(obj, nBytes);
b3962a83
A
2581}
2582
2583id object_reallocFromZone(id obj, size_t nBytes, void *z)
2584{
2585 OBJC_WARN_DEPRECATED;
c1e772c4 2586 return (*_zoneRealloc)(obj, nBytes, z);
b3962a83
A
2587}
2588
2589
8070259c
A
2590/***********************************************************************
2591* object_getIndexedIvars.
2592**********************************************************************/
2593void *object_getIndexedIvars(id obj)
2594{
2595 // ivars are tacked onto the end of the object
34d5b5e8 2596 if (obj->isTaggedPointerOrNil()) return nil;
8070259c
A
2597 return ((char *) obj) + obj->ISA()->alignedInstanceSize();
2598}
2599
2600
b3962a83
A
2601// ProKit SPI
2602Class class_setSuperclass(Class cls, Class newSuper)
2603{
7257e56c
A
2604 Class oldSuper = cls->superclass;
2605 set_superclass(cls, newSuper, NO);
b3962a83
A
2606 flush_caches(cls, YES);
2607 return oldSuper;
2608}
2609#endif