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*	objc-class.m
25*	Copyright 1988-1997, Apple Computer, Inc.
26*	Author:	s. naroff
27**********************************************************************/
28
29
30/***********************************************************************
31 * Lazy method list arrays and method list locking  (2004-10-19)
32 *
33 * cls->methodLists may be in one of three forms:
34 * 1. nil: The class has no methods.
35 * 2. non-nil, with CLS_NO_METHOD_ARRAY set: cls->methodLists points
36 *    to a single method list, which is the class's only method list.
37 * 3. non-nil, with CLS_NO_METHOD_ARRAY clear: cls->methodLists points to
38 *    an array of method list pointers. The end of the array's block
39 *    is set to -1. If the actual number of method lists is smaller
40 *    than that, the rest of the array is nil.
41 *
42 * Attaching categories and adding and removing classes may change
43 * the form of the class list. In addition, individual method lists
44 * may be reallocated when fixed up.
45 *
46 * Classes are initially read as #1 or #2. If a category is attached
47 * or other methods added, the class is changed to #3. Once in form #3,
48 * the class is never downgraded to #1 or #2, even if methods are removed.
49 * Classes added with objc_addClass are initially either #1 or #3.
50 *
51 * Accessing and manipulating a class's method lists are synchronized,
52 * to prevent races when one thread restructures the list. However,
53 * if the class is not yet in use (i.e. not in class_hash), then the
54 * thread loading the class may access its method lists without locking.
55 *
56 * The following functions acquire methodListLock:
57 * class_getInstanceMethod
58 * class_getClassMethod
59 * class_nextMethodList
60 * class_addMethods
61 * class_removeMethods
62 * class_respondsToMethod
63 * _class_lookupMethodAndLoadCache
64 * lookupMethodInClassAndLoadCache
65 * _objc_add_category_flush_caches
66 *
67 * The following functions don't acquire methodListLock because they
68 * only access method lists during class load and unload:
69 * _objc_register_category
70 * _resolve_categories_for_class (calls _objc_add_category)
71 * add_class_to_loadable_list
72 * _objc_addClass
73 * _objc_remove_classes_in_image
74 *
75 * The following functions use method lists without holding methodListLock.
76 * The caller must either hold methodListLock, or be loading the class.
77 * _getMethod (called by class_getInstanceMethod, class_getClassMethod,
78 *   and class_respondsToMethod)
79 * _findMethodInClass (called by _class_lookupMethodAndLoadCache,
80 *   lookupMethodInClassAndLoadCache, _getMethod)
81 * _findMethodInList (called by _findMethodInClass)
82 * nextMethodList (called by _findMethodInClass and class_nextMethodList
83 * fixupSelectorsInMethodList (called by nextMethodList)
84 * _objc_add_category (called by _objc_add_category_flush_caches,
85 *   resolve_categories_for_class and _objc_register_category)
86 * _objc_insertMethods (called by class_addMethods and _objc_add_category)
87 * _objc_removeMethods (called by class_removeMethods)
88 * _objcTweakMethodListPointerForClass (called by _objc_insertMethods)
89 * get_base_method_list (called by add_class_to_loadable_list)
90 * lookupNamedMethodInMethodList (called by add_class_to_loadable_list)
91 ***********************************************************************/
92
93/***********************************************************************
94 * Thread-safety of class info bits  (2004-10-19)
95 *
96 * Some class info bits are used to store mutable runtime state.
97 * Modifications of the info bits at particular times need to be
98 * synchronized to prevent races.
99 *
100 * Three thread-safe modification functions are provided:
101 * cls->setInfo()     // atomically sets some bits
102 * cls->clearInfo()   // atomically clears some bits
103 * cls->changeInfo()  // atomically sets some bits and clears others
104 * These replace CLS_SETINFO() for the multithreaded cases.
105 *
106 * Three modification windows are defined:
107 * - compile time
108 * - class construction or image load (before +load) in one thread
109 * - multi-threaded messaging and method caches
110 *
111 * Info bit modification at compile time and class construction do not
112 *   need to be locked, because only one thread is manipulating the class.
113 * Info bit modification during messaging needs to be locked, because
114 *   there may be other threads simultaneously messaging or otherwise
115 *   manipulating the class.
116 *
117 * Modification windows for each flag:
118 *
119 * CLS_CLASS: compile-time and class load
120 * CLS_META: compile-time and class load
121 * CLS_INITIALIZED: +initialize
122 * CLS_POSING: messaging
123 * CLS_MAPPED: compile-time
124 * CLS_FLUSH_CACHE: class load and messaging
125 * CLS_GROW_CACHE: messaging
126 * CLS_NEED_BIND: unused
127 * CLS_METHOD_ARRAY: unused
128 * CLS_JAVA_HYBRID: JavaBridge only
129 * CLS_JAVA_CLASS: JavaBridge only
130 * CLS_INITIALIZING: messaging
131 * CLS_FROM_BUNDLE: class load
132 * CLS_HAS_CXX_STRUCTORS: compile-time and class load
133 * CLS_NO_METHOD_ARRAY: class load and messaging
134 * CLS_HAS_LOAD_METHOD: class load
135 *
136 * CLS_INITIALIZED and CLS_INITIALIZING have additional thread-safety
137 * constraints to support thread-safe +initialize. See "Thread safety
138 * during class initialization" for details.
139 *
140 * CLS_JAVA_HYBRID and CLS_JAVA_CLASS are set immediately after JavaBridge
141 * calls objc_addClass(). The JavaBridge does not use an atomic update,
142 * but the modification counts as "class construction" unless some other
143 * thread quickly finds the class via the class list. This race is
144 * small and unlikely in well-behaved code.
145 *
146 * Most info bits that may be modified during messaging are also never
147 * read without a lock. There is no general read lock for the info bits.
148 * CLS_INITIALIZED: classInitLock
149 * CLS_FLUSH_CACHE: cacheUpdateLock
150 * CLS_GROW_CACHE: cacheUpdateLock
151 * CLS_NO_METHOD_ARRAY: methodListLock
152 * CLS_INITIALIZING: classInitLock
153 ***********************************************************************/
154
155/***********************************************************************
156* Imports.
157**********************************************************************/
158
159#include "objc-private.h"
160#include "objc-abi.h"
161#include "objc-auto.h"
162#include <objc/message.h>
163
164
165/* overriding the default object allocation and error handling routines */
166
167OBJC_EXPORT id	(*_alloc)(Class, size_t);
168OBJC_EXPORT id	(*_copy)(id, size_t);
169OBJC_EXPORT id	(*_realloc)(id, size_t);
170OBJC_EXPORT id	(*_dealloc)(id);
171OBJC_EXPORT id	(*_zoneAlloc)(Class, size_t, void *);
172OBJC_EXPORT id	(*_zoneRealloc)(id, size_t, void *);
173OBJC_EXPORT id	(*_zoneCopy)(id, size_t, void *);
174
175
176/***********************************************************************
177* Information about multi-thread support:
178*
179* Since we do not lock many operations which walk the superclass, method
180* and ivar chains, these chains must remain intact once a class is published
181* by inserting it into the class hashtable.  All modifications must be
182* atomic so that someone walking these chains will always geta valid
183* result.
184***********************************************************************/
185
186
187
188/***********************************************************************
189* object_getClass.
190* Locking: None. If you add locking, tell gdb (rdar://7516456).
191**********************************************************************/
192Class object_getClass(id obj)
193{
194    if (obj) return obj->getIsa();
195    else return Nil;
196}
197
198
199/***********************************************************************
200* object_setClass.
201**********************************************************************/
202Class object_setClass(id obj, Class cls)
203{
204    if (obj) return obj->changeIsa(cls);
205    else return Nil;
206}
207
208
209/***********************************************************************
210* object_getClassName.
211**********************************************************************/
212const char *object_getClassName(id obj)
213{
214    return class_getName(obj ? obj->getIsa() : nil);
215}
216
217
218/***********************************************************************
219 * object_getMethodImplementation.
220 **********************************************************************/
221IMP object_getMethodImplementation(id obj, SEL name)
222{
223    Class cls = (obj ? obj->getIsa() : nil);
224    return class_getMethodImplementation(cls, name);
225}
226
227
228/***********************************************************************
229 * object_getMethodImplementation_stret.
230 **********************************************************************/
231IMP object_getMethodImplementation_stret(id obj, SEL name)
232{
233    Class cls = (obj ? obj->getIsa() : nil);
234    return class_getMethodImplementation_stret(cls, name);
235}
236
237
238/***********************************************************************
239* object_getIndexedIvars.
240**********************************************************************/
241void *object_getIndexedIvars(id obj)
242{
243    // ivars are tacked onto the end of the object
244    if (!obj) return nil;
245    if (obj->isTaggedPointer()) return nil;
246    return ((char *) obj) + obj->ISA()->alignedInstanceSize();
247}
248
249
250Ivar object_setInstanceVariable(id obj, const char *name, void *value)
251{
252    Ivar ivar = nil;
253
254    if (obj  &&  name  &&  !obj->isTaggedPointer()) {
255        if ((ivar = class_getInstanceVariable(obj->ISA(), name))) {
256            object_setIvar(obj, ivar, (id)value);
257        }
258    }
259    return ivar;
260}
261
262Ivar object_getInstanceVariable(id obj, const char *name, void **value)
263{
264    if (obj  &&  name  &&  !obj->isTaggedPointer()) {
265        Ivar ivar;
266        if ((ivar = class_getInstanceVariable(obj->ISA(), name))) {
267            if (value) *value = (void *)object_getIvar(obj, ivar);
268            return ivar;
269        }
270    }
271    if (value) *value = nil;
272    return nil;
273}
274
275static BOOL is_scanned_offset(ptrdiff_t ivar_offset, const uint8_t *layout) {
276    ptrdiff_t index = 0, ivar_index = ivar_offset / sizeof(void*);
277    uint8_t byte;
278    while ((byte = *layout++)) {
279        unsigned skips = (byte >> 4);
280        unsigned scans = (byte & 0x0F);
281        index += skips;
282        while (scans--) {
283            if (index == ivar_index) return YES;
284            if (index > ivar_index) return NO;
285            ++index;
286        }
287    }
288    return NO;
289}
290
291// FIXME:  this could be optimized.
292
293static Class _ivar_getClass(Class cls, Ivar ivar) {
294    Class ivar_class = nil;
295    const char *ivar_name = ivar_getName(ivar);
296    Ivar named_ivar = _class_getVariable(cls, ivar_name, &ivar_class);
297    if (named_ivar) {
298        // the same ivar name can appear multiple times along the superclass chain.
299        while (named_ivar != ivar && ivar_class != nil) {
300            ivar_class = ivar_class->superclass;
301            named_ivar = _class_getVariable(cls, ivar_getName(ivar), &ivar_class);
302        }
303    }
304    return ivar_class;
305}
306
307void object_setIvar(id obj, Ivar ivar, id value)
308{
309    if (obj  &&  ivar  &&  !obj->isTaggedPointer()) {
310        Class cls = _ivar_getClass(obj->ISA(), ivar);
311        ptrdiff_t ivar_offset = ivar_getOffset(ivar);
312        id *location = (id *)((char *)obj + ivar_offset);
313        // if this ivar is a member of an ARR compiled class, then issue the correct barrier according to the layout.
314        if (_class_usesAutomaticRetainRelease(cls)) {
315            // for ARR, layout strings are relative to the instance start.
316            uint32_t instanceStart = _class_getInstanceStart(cls);
317            const uint8_t *weak_layout = class_getWeakIvarLayout(cls);
318            if (weak_layout && is_scanned_offset(ivar_offset - instanceStart, weak_layout)) {
319                // use the weak system to write to this variable.
320                objc_storeWeak(location, value);
321                return;
322            }
323            const uint8_t *strong_layout = class_getIvarLayout(cls);
324            if (strong_layout && is_scanned_offset(ivar_offset - instanceStart, strong_layout)) {
325                objc_storeStrong(location, value);
326                return;
327            }
328        }
329#if SUPPORT_GC
330        if (UseGC) {
331            // for GC, check for weak references.
332            const uint8_t *weak_layout = class_getWeakIvarLayout(cls);
333            if (weak_layout && is_scanned_offset(ivar_offset, weak_layout)) {
334                objc_assign_weak(value, location);
335            }
336        }
337        objc_assign_ivar(value, obj, ivar_offset);
338#else
339        *location = value;
340#endif
341    }
342}
343
344
345id object_getIvar(id obj, Ivar ivar)
346{
347    if (obj  &&  ivar  &&  !obj->isTaggedPointer()) {
348        Class cls = obj->ISA();
349        ptrdiff_t ivar_offset = ivar_getOffset(ivar);
350        if (_class_usesAutomaticRetainRelease(cls)) {
351            // for ARR, layout strings are relative to the instance start.
352            uint32_t instanceStart = _class_getInstanceStart(cls);
353            const uint8_t *weak_layout = class_getWeakIvarLayout(cls);
354            if (weak_layout && is_scanned_offset(ivar_offset - instanceStart, weak_layout)) {
355                // use the weak system to read this variable.
356                id *location = (id *)((char *)obj + ivar_offset);
357                return objc_loadWeak(location);
358            }
359        }
360        id *idx = (id *)((char *)obj + ivar_offset);
361#if SUPPORT_GC
362        if (UseGC) {
363            const uint8_t *weak_layout = class_getWeakIvarLayout(cls);
364            if (weak_layout && is_scanned_offset(ivar_offset, weak_layout)) {
365                return objc_read_weak(idx);
366            }
367        }
368#endif
369        return *idx;
370    }
371    return nil;
372}
373
374
375/***********************************************************************
376* object_cxxDestructFromClass.
377* Call C++ destructors on obj, starting with cls's
378*   dtor method (if any) followed by superclasses' dtors (if any),
379*   stopping at cls's dtor (if any).
380* Uses methodListLock and cacheUpdateLock. The caller must hold neither.
381**********************************************************************/
382static void object_cxxDestructFromClass(id obj, Class cls)
383{
384    void (*dtor)(id);
385
386    // Call cls's dtor first, then superclasses's dtors.
387
388    for ( ; cls; cls = cls->superclass) {
389        if (!cls->hasCxxDtor()) return;
390        dtor = (void(*)(id))
391            lookupMethodInClassAndLoadCache(cls, SEL_cxx_destruct);
392        if (dtor != (void(*)(id))_objc_msgForward_impcache) {
393            if (PrintCxxCtors) {
394                _objc_inform("CXX: calling C++ destructors for class %s",
395                             cls->getName());
396            }
397            (*dtor)(obj);
398        }
399    }
400}
401
402
403/***********************************************************************
404* object_cxxDestruct.
405* Call C++ destructors on obj, if any.
406* Uses methodListLock and cacheUpdateLock. The caller must hold neither.
407**********************************************************************/
408void object_cxxDestruct(id obj)
409{
410    if (!obj) return;
411    if (obj->isTaggedPointer()) return;
412    object_cxxDestructFromClass(obj, obj->ISA());
413}
414
415
416/***********************************************************************
417* object_cxxConstructFromClass.
418* Recursively call C++ constructors on obj, starting with base class's
419*   ctor method (if any) followed by subclasses' ctors (if any), stopping
420*   at cls's ctor (if any).
421* Returns YES if construction succeeded.
422* Returns NO if some constructor threw an exception. The exception is
423*   caught and discarded. Any partial construction is destructed.
424* Uses methodListLock and cacheUpdateLock. The caller must hold neither.
425*
426* .cxx_construct returns id. This really means:
427* return self: construction succeeded
428* return nil:  construction failed because a C++ constructor threw an exception
429**********************************************************************/
430static BOOL object_cxxConstructFromClass(id obj, Class cls)
431{
432    id (*ctor)(id);
433    Class supercls;
434
435    // Stop if neither this class nor any superclass has ctors.
436    if (!cls->hasCxxCtor()) return YES;  // no ctor - ok
437
438    supercls = cls->superclass;
439
440    // Call superclasses' ctors first, if any.
441    if (supercls) {
442        BOOL ok = object_cxxConstructFromClass(obj, supercls);
443        if (!ok) return NO;  // some superclass's ctor failed - give up
444    }
445
446    // Find this class's ctor, if any.
447    ctor = (id(*)(id))lookupMethodInClassAndLoadCache(cls, SEL_cxx_construct);
448    if (ctor == (id(*)(id))_objc_msgForward_impcache) return YES;  // no ctor - ok
449
450    // Call this class's ctor.
451    if (PrintCxxCtors) {
452        _objc_inform("CXX: calling C++ constructors for class %s", cls->getName());
453    }
454    if ((*ctor)(obj)) return YES;  // ctor called and succeeded - ok
455
456    // This class's ctor was called and failed.
457    // Call superclasses's dtors to clean up.
458    if (supercls) object_cxxDestructFromClass(obj, supercls);
459    return NO;
460}
461
462
463/***********************************************************************
464* object_cxxConstructFromClass.
465* Call C++ constructors on obj, if any.
466* Returns YES if construction succeeded.
467* Returns NO if some constructor threw an exception. The exception is
468*   caught and discarded. Any partial construction is destructed.
469* Uses methodListLock and cacheUpdateLock. The caller must hold neither.
470**********************************************************************/
471BOOL object_cxxConstruct(id obj)
472{
473    if (!obj) return YES;
474    if (obj->isTaggedPointer()) return YES;
475    return object_cxxConstructFromClass(obj, obj->ISA());
476}
477
478
479/***********************************************************************
480* _class_resolveClassMethod
481* Call +resolveClassMethod, looking for a method to be added to class cls.
482* cls should be a metaclass.
483* Does not check if the method already exists.
484**********************************************************************/
485static void _class_resolveClassMethod(Class cls, SEL sel, id inst)
486{
487    assert(cls->isMetaClass());
488
489    if (! lookUpImpOrNil(cls, SEL_resolveClassMethod, inst,
490                         NO/*initialize*/, YES/*cache*/, NO/*resolver*/))
491    {
492        // Resolver not implemented.
493        return;
494    }
495
496    BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
497    BOOL resolved = msg(_class_getNonMetaClass(cls, inst),
498                        SEL_resolveClassMethod, sel);
499
500    // Cache the result (good or bad) so the resolver doesn't fire next time.
501    // +resolveClassMethod adds to self->ISA() a.k.a. cls
502    IMP imp = lookUpImpOrNil(cls, sel, inst,
503                             NO/*initialize*/, YES/*cache*/, NO/*resolver*/);
504
505    if (resolved  &&  PrintResolving) {
506        if (imp) {
507            _objc_inform("RESOLVE: method %c[%s %s] "
508                         "dynamically resolved to %p",
509                         cls->isMetaClass() ? '+' : '-',
510                         cls->getName(), sel_getName(sel), imp);
511        }
512        else {
513            // Method resolver didn't add anything?
514            _objc_inform("RESOLVE: +[%s resolveClassMethod:%s] returned YES"
515                         ", but no new implementation of %c[%s %s] was found",
516                         cls->getName(), sel_getName(sel),
517                         cls->isMetaClass() ? '+' : '-',
518                         cls->getName(), sel_getName(sel));
519        }
520    }
521}
522
523
524/***********************************************************************
525* _class_resolveInstanceMethod
526* Call +resolveInstanceMethod, looking for a method to be added to class cls.
527* cls may be a metaclass or a non-meta class.
528* Does not check if the method already exists.
529**********************************************************************/
530static void _class_resolveInstanceMethod(Class cls, SEL sel, id inst)
531{
532    if (! lookUpImpOrNil(cls->ISA(), SEL_resolveInstanceMethod, cls,
533                         NO/*initialize*/, YES/*cache*/, NO/*resolver*/))
534    {
535        // Resolver not implemented.
536        return;
537    }
538
539    BOOL (*msg)(Class, SEL, SEL) = (typeof(msg))objc_msgSend;
540    BOOL resolved = msg(cls, SEL_resolveInstanceMethod, sel);
541
542    // Cache the result (good or bad) so the resolver doesn't fire next time.
543    // +resolveInstanceMethod adds to self a.k.a. cls
544    IMP imp = lookUpImpOrNil(cls, sel, inst,
545                             NO/*initialize*/, YES/*cache*/, NO/*resolver*/);
546
547    if (resolved  &&  PrintResolving) {
548        if (imp) {
549            _objc_inform("RESOLVE: method %c[%s %s] "
550                         "dynamically resolved to %p",
551                         cls->isMetaClass() ? '+' : '-',
552                         cls->getName(), sel_getName(sel), imp);
553        }
554        else {
555            // Method resolver didn't add anything?
556            _objc_inform("RESOLVE: +[%s resolveInstanceMethod:%s] returned YES"
557                         ", but no new implementation of %c[%s %s] was found",
558                         cls->getName(), sel_getName(sel),
559                         cls->isMetaClass() ? '+' : '-',
560                         cls->getName(), sel_getName(sel));
561        }
562    }
563}
564
565
566/***********************************************************************
567* _class_resolveMethod
568* Call +resolveClassMethod or +resolveInstanceMethod.
569* Returns nothing; any result would be potentially out-of-date already.
570* Does not check if the method already exists.
571**********************************************************************/
572void _class_resolveMethod(Class cls, SEL sel, id inst)
573{
574    if (! cls->isMetaClass()) {
575        // try [cls resolveInstanceMethod:sel]
576        _class_resolveInstanceMethod(cls, sel, inst);
577    }
578    else {
579        // try [nonMetaClass resolveClassMethod:sel]
580        // and [cls resolveInstanceMethod:sel]
581        _class_resolveClassMethod(cls, sel, inst);
582        if (!lookUpImpOrNil(cls, sel, inst,
583                            NO/*initialize*/, YES/*cache*/, NO/*resolver*/))
584        {
585            _class_resolveInstanceMethod(cls, sel, inst);
586        }
587    }
588}
589
590
591/***********************************************************************
592* class_getClassMethod.  Return the class method for the specified
593* class and selector.
594**********************************************************************/
595Method class_getClassMethod(Class cls, SEL sel)
596{
597    if (!cls  ||  !sel) return nil;
598
599    return class_getInstanceMethod(cls->getMeta(), sel);
600}
601
602
603/***********************************************************************
604* class_getInstanceVariable.  Return the named instance variable.
605**********************************************************************/
606Ivar class_getInstanceVariable(Class cls, const char *name)
607{
608    if (!cls  ||  !name) return nil;
609
610    return _class_getVariable(cls, name, nil);
611}
612
613
614/***********************************************************************
615* class_getClassVariable.  Return the named class variable.
616**********************************************************************/
617Ivar class_getClassVariable(Class cls, const char *name)
618{
619    if (!cls) return nil;
620
621    return class_getInstanceVariable(cls->ISA(), name);
622}
623
624
625/***********************************************************************
626* gdb_objc_class_changed
627* Tell gdb that a class changed. Currently used for OBJC2 ivar layouts only
628* Does nothing; gdb sets a breakpoint on it.
629**********************************************************************/
630BREAKPOINT_FUNCTION(
631    void gdb_objc_class_changed(Class cls, unsigned long changes, const char *classname)
632);
633
634
635/***********************************************************************
636* class_respondsToSelector.
637**********************************************************************/
638BOOL class_respondsToMethod(Class cls, SEL sel)
639{
640    OBJC_WARN_DEPRECATED;
641
642    return class_respondsToSelector(cls, sel);
643}
644
645
646BOOL class_respondsToSelector(Class cls, SEL sel)
647{
648    IMP imp;
649
650    if (!sel  ||  !cls) return NO;
651
652    // Avoids +initialize because it historically did so.
653    // We're not returning a callable IMP anyway.
654    imp = lookUpImpOrNil(cls, sel, nil,
655                         NO/*initialize*/, YES/*cache*/, YES/*resolver*/);
656    return imp ? YES : NO;
657}
658
659
660/***********************************************************************
661* class_getMethodImplementation.
662* Returns the IMP that would be invoked if [obj sel] were sent,
663* where obj is an instance of class cls.
664**********************************************************************/
665IMP class_lookupMethod(Class cls, SEL sel)
666{
667    OBJC_WARN_DEPRECATED;
668
669    // No one responds to zero!
670    if (!sel) {
671        __objc_error(cls, "invalid selector (null)");
672    }
673
674    return class_getMethodImplementation(cls, sel);
675}
676
677IMP class_getMethodImplementation(Class cls, SEL sel)
678{
679    IMP imp;
680
681    if (!cls  ||  !sel) return nil;
682
683    imp = lookUpImpOrNil(cls, sel, nil,
684                         YES/*initialize*/, YES/*cache*/, YES/*resolver*/);
685
686    // Translate forwarding function to C-callable external version
687    if (!imp) {
688        return _objc_msgForward;
689    }
690
691    return imp;
692}
693
694
695IMP class_getMethodImplementation_stret(Class cls, SEL sel)
696{
697    IMP imp = class_getMethodImplementation(cls, sel);
698
699    // Translate forwarding function to struct-returning version
700    if (imp == (IMP)&_objc_msgForward /* not _internal! */) {
701        return (IMP)&_objc_msgForward_stret;
702    }
703    return imp;
704}
705
706
707/***********************************************************************
708* instrumentObjcMessageSends
709**********************************************************************/
710#if !SUPPORT_MESSAGE_LOGGING
711
712void	instrumentObjcMessageSends(BOOL flag)
713{
714}
715
716#else
717
718bool objcMsgLogEnabled = false;
719static int objcMsgLogFD = -1;
720
721bool logMessageSend(bool isClassMethod,
722                    const char *objectsClass,
723                    const char *implementingClass,
724                    SEL selector)
725{
726    char	buf[ 1024 ];
727
728    // Create/open the log file
729    if (objcMsgLogFD == (-1))
730    {
731        snprintf (buf, sizeof(buf), "/tmp/msgSends-%d", (int) getpid ());
732        objcMsgLogFD = secure_open (buf, O_WRONLY | O_CREAT, geteuid());
733        if (objcMsgLogFD < 0) {
734            // no log file - disable logging
735            objcMsgLogEnabled = false;
736            objcMsgLogFD = -1;
737            return true;
738        }
739    }
740
741    // Make the log entry
742    snprintf(buf, sizeof(buf), "%c %s %s %s\n",
743            isClassMethod ? '+' : '-',
744            objectsClass,
745            implementingClass,
746            sel_getName(selector));
747
748    static spinlock_t lock = SPINLOCK_INITIALIZER;
749    spinlock_lock(&lock);
750    write (objcMsgLogFD, buf, strlen(buf));
751    spinlock_unlock(&lock);
752
753    // Tell caller to not cache the method
754    return false;
755}
756
757void instrumentObjcMessageSends(BOOL flag)
758{
759    bool enable = flag;
760
761    // Shortcut NOP
762    if (objcMsgLogEnabled == enable)
763        return;
764
765    // If enabling, flush all method caches so we get some traces
766    if (enable)
767        _objc_flush_caches(Nil);
768
769    // Sync our log file
770    if (objcMsgLogFD != -1)
771        fsync (objcMsgLogFD);
772
773    objcMsgLogEnabled = enable;
774}
775
776// SUPPORT_MESSAGE_LOGGING
777#endif
778
779
780/***********************************************************************
781* _malloc_internal
782* _calloc_internal
783* _realloc_internal
784* _strdup_internal
785* _strdupcat_internal
786* _memdup_internal
787* _free_internal
788* Convenience functions for the internal malloc zone.
789**********************************************************************/
790void *_malloc_internal(size_t size)
791{
792    return malloc_zone_malloc(_objc_internal_zone(), size);
793}
794
795void *_calloc_internal(size_t count, size_t size)
796{
797    return malloc_zone_calloc(_objc_internal_zone(), count, size);
798}
799
800void *_realloc_internal(void *ptr, size_t size)
801{
802    return malloc_zone_realloc(_objc_internal_zone(), ptr, size);
803}
804
805char *_strdup_internal(const char *str)
806{
807    size_t len;
808    char *dup;
809    if (!str) return nil;
810    len = strlen(str);
811    dup = (char *)malloc_zone_malloc(_objc_internal_zone(), len + 1);
812    memcpy(dup, str, len + 1);
813    return dup;
814}
815
816uint8_t *_ustrdup_internal(const uint8_t *str)
817{
818    return (uint8_t *)_strdup_internal((char *)str);
819}
820
821// allocate a new string that concatenates s1+s2.
822char *_strdupcat_internal(const char *s1, const char *s2)
823{
824    size_t len1 = strlen(s1);
825    size_t len2 = strlen(s2);
826    char *dup = (char *)
827        malloc_zone_malloc(_objc_internal_zone(), len1 + len2 + 1);
828    memcpy(dup, s1, len1);
829    memcpy(dup + len1, s2, len2 + 1);
830    return dup;
831}
832
833void *_memdup_internal(const void *mem, size_t len)
834{
835    void *dup = malloc_zone_malloc(_objc_internal_zone(), len);
836    memcpy(dup, mem, len);
837    return dup;
838}
839
840void _free_internal(void *ptr)
841{
842    malloc_zone_free(_objc_internal_zone(), ptr);
843}
844
845size_t _malloc_size_internal(void *ptr)
846{
847    malloc_zone_t *zone = _objc_internal_zone();
848    return zone->size(zone, ptr);
849}
850
851Class _calloc_class(size_t size)
852{
853#if SUPPORT_GC
854    if (UseGC) return (Class) malloc_zone_calloc(gc_zone, 1, size);
855#endif
856    return (Class) _calloc_internal(1, size);
857}
858
859
860const char *class_getName(Class cls)
861{
862    if (!cls) return "nil";
863    else return cls->getName();
864}
865
866Class class_getSuperclass(Class cls)
867{
868    if (!cls) return nil;
869    return cls->superclass;
870}
871
872BOOL class_isMetaClass(Class cls)
873{
874    if (!cls) return NO;
875    return cls->isMetaClass();
876}
877
878
879size_t class_getInstanceSize(Class cls)
880{
881    if (!cls) return 0;
882    return cls->alignedInstanceSize();
883}
884
885
886/***********************************************************************
887* method_getNumberOfArguments.
888**********************************************************************/
889unsigned int method_getNumberOfArguments(Method m)
890{
891    if (!m) return 0;
892    return encoding_getNumberOfArguments(method_getTypeEncoding(m));
893}
894
895
896void method_getReturnType(Method m, char *dst, size_t dst_len)
897{
898    encoding_getReturnType(method_getTypeEncoding(m), dst, dst_len);
899}
900
901
902char * method_copyReturnType(Method m)
903{
904    return encoding_copyReturnType(method_getTypeEncoding(m));
905}
906
907
908void method_getArgumentType(Method m, unsigned int index,
909                            char *dst, size_t dst_len)
910{
911    encoding_getArgumentType(method_getTypeEncoding(m),
912                             index, dst, dst_len);
913}
914
915
916char * method_copyArgumentType(Method m, unsigned int index)
917{
918    return encoding_copyArgumentType(method_getTypeEncoding(m), index);
919}
920
921
922/***********************************************************************
923* objc_constructInstance
924* Creates an instance of `cls` at the location pointed to by `bytes`.
925* `bytes` must point to at least class_getInstanceSize(cls) bytes of
926*   well-aligned zero-filled memory.
927* The new object's isa is set. Any C++ constructors are called.
928* Returns `bytes` if successful. Returns nil if `cls` or `bytes` is
929*   nil, or if C++ constructors fail.
930* Note: class_createInstance() and class_createInstances() preflight this.
931**********************************************************************/
932static id
933_objc_constructInstance(Class cls, void *bytes)
934{
935    id obj = (id)bytes;
936
937    // Set the isa pointer
938    obj->initIsa(cls);
939
940    // Call C++ constructors, if any.
941    if (!object_cxxConstruct(obj)) {
942        // Some C++ constructor threw an exception.
943        return nil;
944    }
945
946    return obj;
947}
948
949
950id
951objc_constructInstance(Class cls, void *bytes)
952{
953    if (!cls  ||  !bytes) return nil;
954    return _objc_constructInstance(cls, bytes);
955}
956
957
958id
959_objc_constructOrFree(Class cls, void *bytes)
960{
961    id obj = _objc_constructInstance(cls, bytes);
962    if (!obj) {
963#if SUPPORT_GC
964        if (UseGC) {
965            auto_zone_retain(gc_zone, bytes);  // gc free expects rc==1
966        }
967#endif
968        free(bytes);
969    }
970
971    return obj;
972}
973
974
975/***********************************************************************
976* _class_createInstancesFromZone
977* Batch-allocating version of _class_createInstanceFromZone.
978* Attempts to allocate num_requested objects, each with extraBytes.
979* Returns the number of allocated objects (possibly zero), with
980* the allocated pointers in *results.
981**********************************************************************/
982unsigned
983_class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone,
984                               id *results, unsigned num_requested)
985{
986    unsigned num_allocated;
987    if (!cls) return 0;
988
989    size_t size = cls->alignedInstanceSize() + extraBytes;
990    // CF requires all objects be at least 16 bytes.
991    if (size < 16) size = 16;
992
993#if SUPPORT_GC
994    if (UseGC) {
995        num_allocated =
996            auto_zone_batch_allocate(gc_zone, size, AUTO_OBJECT_SCANNED, 0, 1,
997                                     (void**)results, num_requested);
998    } else
999#endif
1000    {
1001        unsigned i;
1002        num_allocated =
1003            malloc_zone_batch_malloc((malloc_zone_t *)(zone ? zone : malloc_default_zone()),
1004                                     size, (void**)results, num_requested);
1005        for (i = 0; i < num_allocated; i++) {
1006            bzero(results[i], size);
1007        }
1008    }
1009
1010    // Construct each object, and delete any that fail construction.
1011
1012    unsigned shift = 0;
1013    unsigned i;
1014    bool ctor = cls->hasCxxCtor();
1015    for (i = 0; i < num_allocated; i++) {
1016        id obj = results[i];
1017        if (ctor) obj = _objc_constructOrFree(cls, obj);
1018        else if (obj) obj->initIsa(cls);
1019
1020        if (obj) {
1021            results[i-shift] = obj;
1022        } else {
1023            shift++;
1024        }
1025    }
1026
1027    return num_allocated - shift;
1028}
1029
1030
1031/***********************************************************************
1032* inform_duplicate. Complain about duplicate class implementations.
1033**********************************************************************/
1034void
1035inform_duplicate(const char *name, Class oldCls, Class cls)
1036{
1037#if TARGET_OS_WIN32
1038    _objc_inform ("Class %s is implemented in two different images.", name);
1039#else
1040    const header_info *oldHeader = _headerForClass(oldCls);
1041    const header_info *newHeader = _headerForClass(cls);
1042    const char *oldName = oldHeader ? oldHeader->fname : "??";
1043    const char *newName = newHeader ? newHeader->fname : "??";
1044
1045    _objc_inform ("Class %s is implemented in both %s and %s. "
1046                  "One of the two will be used. "
1047                  "Which one is undefined.",
1048                  name, oldName, newName);
1049#endif
1050}
1051
1052
1053const char *
1054copyPropertyAttributeString(const objc_property_attribute_t *attrs,
1055                            unsigned int count)
1056{
1057    char *result;
1058    unsigned int i;
1059    if (count == 0) return strdup("");
1060
1061#ifndef NDEBUG
1062    // debug build: sanitize input
1063    for (i = 0; i < count; i++) {
1064        assert(attrs[i].name);
1065        assert(strlen(attrs[i].name) > 0);
1066        assert(! strchr(attrs[i].name, ','));
1067        assert(! strchr(attrs[i].name, '"'));
1068        if (attrs[i].value) assert(! strchr(attrs[i].value, ','));
1069    }
1070#endif
1071
1072    size_t len = 0;
1073    for (i = 0; i < count; i++) {
1074        if (attrs[i].value) {
1075            size_t namelen = strlen(attrs[i].name);
1076            if (namelen > 1) namelen += 2;  // long names get quoted
1077            len += namelen + strlen(attrs[i].value) + 1;
1078        }
1079    }
1080
1081    result = (char *)malloc(len + 1);
1082    char *s = result;
1083    for (i = 0; i < count; i++) {
1084        if (attrs[i].value) {
1085            size_t namelen = strlen(attrs[i].name);
1086            if (namelen > 1) {
1087                s += sprintf(s, "\"%s\"%s,", attrs[i].name, attrs[i].value);
1088            } else {
1089                s += sprintf(s, "%s%s,", attrs[i].name, attrs[i].value);
1090            }
1091        }
1092    }
1093
1094    // remove trailing ',' if any
1095    if (s > result) s[-1] = '\0';
1096
1097    return result;
1098}
1099
1100/*
1101  Property attribute string format:
1102
1103  - Comma-separated name-value pairs.
1104  - Name and value may not contain ,
1105  - Name may not contain "
1106  - Value may be empty
1107  - Name is single char, value follows
1108  - OR Name is double-quoted string of 2+ chars, value follows
1109
1110  Grammar:
1111    attribute-string: \0
1112    attribute-string: name-value-pair (',' name-value-pair)*
1113    name-value-pair:  unquoted-name optional-value
1114    name-value-pair:  quoted-name optional-value
1115    unquoted-name:    [^",]
1116    quoted-name:      '"' [^",]{2,} '"'
1117    optional-value:   [^,]*
1118
1119*/
1120static unsigned int
1121iteratePropertyAttributes(const char *attrs,
1122                          BOOL (*fn)(unsigned int index,
1123                                     void *ctx1, void *ctx2,
1124                                     const char *name, size_t nlen,
1125                                     const char *value, size_t vlen),
1126                          void *ctx1, void *ctx2)
1127{
1128    if (!attrs) return 0;
1129
1130#ifndef NDEBUG
1131    const char *attrsend = attrs + strlen(attrs);
1132#endif
1133    unsigned int attrcount = 0;
1134
1135    while (*attrs) {
1136        // Find the next comma-separated attribute
1137        const char *start = attrs;
1138        const char *end = start + strcspn(attrs, ",");
1139
1140        // Move attrs past this attribute and the comma (if any)
1141        attrs = *end ? end+1 : end;
1142
1143        assert(attrs <= attrsend);
1144        assert(start <= attrsend);
1145        assert(end <= attrsend);
1146
1147        // Skip empty attribute
1148        if (start == end) continue;
1149
1150        // Process one non-empty comma-free attribute [start,end)
1151        const char *nameStart;
1152        const char *nameEnd;
1153
1154        assert(start < end);
1155        assert(*start);
1156        if (*start != '\"') {
1157            // single-char short name
1158            nameStart = start;
1159            nameEnd = start+1;
1160            start++;
1161        }
1162        else {
1163            // double-quoted long name
1164            nameStart = start+1;
1165            nameEnd = nameStart + strcspn(nameStart, "\",");
1166            start++;                       // leading quote
1167            start += nameEnd - nameStart;  // name
1168            if (*start == '\"') start++;   // trailing quote, if any
1169        }
1170
1171        // Process one possibly-empty comma-free attribute value [start,end)
1172        const char *valueStart;
1173        const char *valueEnd;
1174
1175        assert(start <= end);
1176
1177        valueStart = start;
1178        valueEnd = end;
1179
1180        BOOL more = (*fn)(attrcount, ctx1, ctx2,
1181                          nameStart, nameEnd-nameStart,
1182                          valueStart, valueEnd-valueStart);
1183        attrcount++;
1184        if (!more) break;
1185    }
1186
1187    return attrcount;
1188}
1189
1190
1191static BOOL
1192copyOneAttribute(unsigned int index, void *ctxa, void *ctxs,
1193                 const char *name, size_t nlen, const char *value, size_t vlen)
1194{
1195    objc_property_attribute_t **ap = (objc_property_attribute_t**)ctxa;
1196    char **sp = (char **)ctxs;
1197
1198    objc_property_attribute_t *a = *ap;
1199    char *s = *sp;
1200
1201    a->name = s;
1202    memcpy(s, name, nlen);
1203    s += nlen;
1204    *s++ = '\0';
1205
1206    a->value = s;
1207    memcpy(s, value, vlen);
1208    s += vlen;
1209    *s++ = '\0';
1210
1211    a++;
1212
1213    *ap = a;
1214    *sp = s;
1215
1216    return YES;
1217}
1218
1219
1220objc_property_attribute_t *
1221copyPropertyAttributeList(const char *attrs, unsigned int *outCount)
1222{
1223    if (!attrs) {
1224        if (outCount) *outCount = 0;
1225        return nil;
1226    }
1227
1228    // Result size:
1229    //   number of commas plus 1 for the attributes (upper bound)
1230    //   plus another attribute for the attribute array terminator
1231    //   plus strlen(attrs) for name/value string data (upper bound)
1232    //   plus count*2 for the name/value string terminators (upper bound)
1233    unsigned int attrcount = 1;
1234    const char *s;
1235    for (s = attrs; s && *s; s++) {
1236        if (*s == ',') attrcount++;
1237    }
1238
1239    size_t size =
1240        attrcount * sizeof(objc_property_attribute_t) +
1241        sizeof(objc_property_attribute_t) +
1242        strlen(attrs) +
1243        attrcount * 2;
1244    objc_property_attribute_t *result = (objc_property_attribute_t *)
1245        calloc(size, 1);
1246
1247    objc_property_attribute_t *ra = result;
1248    char *rs = (char *)(ra+attrcount+1);
1249
1250    attrcount = iteratePropertyAttributes(attrs, copyOneAttribute, &ra, &rs);
1251
1252    assert((uint8_t *)(ra+1) <= (uint8_t *)result+size);
1253    assert((uint8_t *)rs <= (uint8_t *)result+size);
1254
1255    if (attrcount == 0) {
1256        free(result);
1257        result = nil;
1258    }
1259
1260    if (outCount) *outCount = attrcount;
1261    return result;
1262}
1263
1264
1265static BOOL
1266findOneAttribute(unsigned int index, void *ctxa, void *ctxs,
1267                 const char *name, size_t nlen, const char *value, size_t vlen)
1268{
1269    const char *query = (char *)ctxa;
1270    char **resultp = (char **)ctxs;
1271
1272    if (strlen(query) == nlen  &&  0 == strncmp(name, query, nlen)) {
1273        char *result = (char *)calloc(vlen+1, 1);
1274        memcpy(result, value, vlen);
1275        result[vlen] = '\0';
1276        *resultp = result;
1277        return NO;
1278    }
1279
1280    return YES;
1281}
1282
1283char *copyPropertyAttributeValue(const char *attrs, const char *name)
1284{
1285    char *result = nil;
1286
1287    iteratePropertyAttributes(attrs, findOneAttribute, (void*)name, &result);
1288
1289    return result;
1290}
1291