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-private.h
25 *	Copyright 1988-1996, NeXT Software, Inc.
26 */
27
28#ifndef _OBJC_PRIVATE_H_
29#define _OBJC_PRIVATE_H_
30
31#include "objc-config.h"
32
33/* Isolate ourselves from the definitions of id and Class in the compiler
34 * and public headers.
35 */
36
37#ifdef _OBJC_OBJC_H_
38#error include objc-private.h before other headers
39#endif
40
41#define OBJC_TYPES_DEFINED 1
42#define OBJC_OLD_DISPATCH_PROTOTYPES 0
43
44#include <cstddef>  // for nullptr_t
45#include <stdint.h>
46#include <assert.h>
47
48struct objc_class;
49struct objc_object;
50
51typedef struct objc_class *Class;
52typedef struct objc_object *id;
53
54namespace {
55    class SideTable;
56};
57
58
59union isa_t
60{
61    isa_t() { }
62    isa_t(uintptr_t value) : bits(value) { }
63
64    Class cls;
65    uintptr_t bits;
66
67#if SUPPORT_NONPOINTER_ISA
68
69    // extra_rc must be the MSB-most field (so it matches carry/overflow flags)
70    // indexed must be the LSB (fixme or get rid of it)
71    // shiftcls must occupy the same bits that a real class pointer would
72    // bits + RC_ONE is equivalent to extra_rc + 1
73    // RC_HALF is the high bit of extra_rc (i.e. half of its range)
74
75    // future expansion:
76    // uintptr_t fast_rr : 1;     // no r/r overrides
77    // uintptr_t lock : 2;        // lock for atomic property, @synch
78    // uintptr_t extraBytes : 1;  // allocated with extra bytes
79
80# if __arm64__
81#   define ISA_MASK        0x00000001fffffff8ULL
82#   define ISA_MAGIC_MASK  0x000003fe00000001ULL
83#   define ISA_MAGIC_VALUE 0x000001a400000001ULL
84    struct {
85        uintptr_t indexed           : 1;
86        uintptr_t has_assoc         : 1;
87        uintptr_t has_cxx_dtor      : 1;
88        uintptr_t shiftcls          : 30; // MACH_VM_MAX_ADDRESS 0x1a0000000
89        uintptr_t magic             : 9;
90        uintptr_t weakly_referenced : 1;
91        uintptr_t deallocating      : 1;
92        uintptr_t has_sidetable_rc  : 1;
93        uintptr_t extra_rc          : 19;
94#       define RC_ONE   (1ULL<<45)
95#       define RC_HALF  (1ULL<<18)
96    };
97
98# elif __x86_64__
99#   define ISA_MASK        0x00007ffffffffff8ULL
100#   define ISA_MAGIC_MASK  0x0000000000000001ULL
101#   define ISA_MAGIC_VALUE 0x0000000000000001ULL
102    struct {
103        uintptr_t indexed           : 1;
104        uintptr_t has_assoc         : 1;
105        uintptr_t has_cxx_dtor      : 1;
106        uintptr_t shiftcls          : 44; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
107        uintptr_t weakly_referenced : 1;
108        uintptr_t deallocating      : 1;
109        uintptr_t has_sidetable_rc  : 1;
110        uintptr_t extra_rc          : 14;
111#       define RC_ONE   (1ULL<<50)
112#       define RC_HALF  (1ULL<<13)
113    };
114
115# else
116    // Available bits in isa field are architecture-specific.
117#   error unknown architecture
118# endif
119
120// SUPPORT_NONPOINTER_ISA
121#endif
122
123};
124
125
126struct objc_object {
127private:
128    isa_t isa;
129
130public:
131
132    // ISA() assumes this is NOT a tagged pointer object
133    Class ISA();
134
135    // getIsa() allows this to be a tagged pointer object
136    Class getIsa();
137
138    // initIsa() should be used to init the isa of new objects only.
139    // If this object already has an isa, use changeIsa() for correctness.
140    // initInstanceIsa(): objects with no custom RR/AWZ
141    // initClassIsa(): class objects
142    // initProtocolIsa(): protocol objects
143    // initIsa(): other objects
144    void initIsa(Class cls /*indexed=false*/);
145    void initClassIsa(Class cls /*indexed=maybe*/);
146    void initProtocolIsa(Class cls /*indexed=maybe*/);
147    void initInstanceIsa(Class cls, bool hasCxxDtor);
148
149    // changeIsa() should be used to change the isa of existing objects.
150    // If this is a new object, use initIsa() for performance.
151    Class changeIsa(Class newCls);
152
153    bool hasIndexedIsa();
154    bool isTaggedPointer();
155    bool isClass();
156
157    // object may have associated objects?
158    bool hasAssociatedObjects();
159    void setHasAssociatedObjects();
160
161    // object may be weakly referenced?
162    bool isWeaklyReferenced();
163    void setWeaklyReferenced_nolock();
164
165    // object may have -.cxx_destruct implementation?
166    bool hasCxxDtor();
167
168    // Optimized calls to retain/release methods
169    id retain();
170    void release();
171    id autorelease();
172
173    // Implementations of retain/release methods
174    id rootRetain();
175    bool rootRelease();
176    id rootAutorelease();
177    bool rootTryRetain();
178    bool rootReleaseShouldDealloc();
179    uintptr_t rootRetainCount();
180
181    // Implementation of dealloc methods
182    bool rootIsDeallocating();
183    void clearDeallocating();
184    void rootDealloc();
185
186private:
187    void initIsa(Class newCls, bool indexed, bool hasCxxDtor);
188
189    // Slow paths for inline control
190    id rootAutorelease2();
191    bool overrelease_error();
192
193#if SUPPORT_NONPOINTER_ISA
194    // Unified retain count manipulation for nonpointer isa
195    id rootRetain(bool tryRetain, bool handleOverflow);
196    bool rootRelease(bool performDealloc, bool handleUnderflow);
197    id rootRetain_overflow(bool tryRetain);
198    bool rootRelease_underflow(bool performDealloc);
199
200    void clearDeallocating_weak();
201
202    // Side table retain count overflow for nonpointer isa
203    void sidetable_lock();
204    void sidetable_unlock();
205
206    void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced);
207    bool sidetable_addExtraRC_nolock(size_t delta_rc);
208    bool sidetable_subExtraRC_nolock(size_t delta_rc);
209    size_t sidetable_getExtraRC_nolock();
210#endif
211
212    // Side-table-only retain count
213    bool sidetable_isDeallocating();
214    void sidetable_clearDeallocating();
215
216    bool sidetable_isWeaklyReferenced();
217    void sidetable_setWeaklyReferenced_nolock();
218
219    id sidetable_retain();
220    id sidetable_retain_slow(SideTable *table);
221
222    bool sidetable_release(bool performDealloc = true);
223    bool sidetable_release_slow(SideTable *table, bool performDealloc = true);
224
225    bool sidetable_tryRetain();
226
227    uintptr_t sidetable_retainCount();
228#if !NDEBUG
229    bool sidetable_present();
230#endif
231};
232
233
234#if __OBJC2__
235typedef struct method_t *Method;
236typedef struct ivar_t *Ivar;
237typedef struct category_t *Category;
238typedef struct property_t *objc_property_t;
239#else
240typedef struct old_method *Method;
241typedef struct old_ivar *Ivar;
242typedef struct old_category *Category;
243typedef struct old_property *objc_property_t;
244#endif
245
246// Public headers
247
248#include "objc.h"
249#include "runtime.h"
250#include "objc-os.h"
251#include "objc-abi.h"
252#include "objc-api.h"
253#include "objc-auto.h"
254#include "objc-config.h"
255#include "objc-internal.h"
256#include "maptable.h"
257#include "hashtable2.h"
258
259/* Do not include message.h here. */
260/* #include "message.h" */
261
262#define __APPLE_API_PRIVATE
263#include "objc-gdb.h"
264#undef __APPLE_API_PRIVATE
265
266
267// Private headers
268
269#if __OBJC2__
270#include "objc-runtime-new.h"
271#else
272#include "objc-runtime-old.h"
273#endif
274
275#include "objc-references.h"
276#include "objc-initialize.h"
277#include "objc-loadmethod.h"
278
279
280__BEGIN_DECLS
281
282
283#if (defined(OBJC_NO_GC) && SUPPORT_GC)  ||  \
284    (!defined(OBJC_NO_GC) && !SUPPORT_GC)
285#   error OBJC_NO_GC and SUPPORT_GC inconsistent
286#endif
287
288#if SUPPORT_GC
289#   include <auto_zone.h>
290    // PRIVATE_EXTERN is needed to help the compiler know "how" extern these are
291    PRIVATE_EXTERN extern int8_t UseGC;          // equivalent to calling objc_collecting_enabled()
292    PRIVATE_EXTERN extern auto_zone_t *gc_zone;  // the GC zone, or NULL if no GC
293    extern void objc_addRegisteredClass(Class c);
294    extern void objc_removeRegisteredClass(Class c);
295#else
296#   define UseGC NO
297#   define gc_zone NULL
298#   define objc_addRegisteredClass(c) do {} while(0)
299#   define objc_removeRegisteredClass(c) do {} while(0)
300    /* Uses of the following must be protected with UseGC. */
301    extern id gc_unsupported_dont_call();
302#   define auto_zone_allocate_object gc_unsupported_dont_call
303#   define auto_zone_retain gc_unsupported_dont_call
304#   define auto_zone_release gc_unsupported_dont_call
305#   define auto_zone_is_valid_pointer gc_unsupported_dont_call
306#   define auto_zone_write_barrier_memmove gc_unsupported_dont_call
307#   define AUTO_OBJECT_SCANNED 0
308#endif
309
310
311#define _objcHeaderIsReplacement(h)  ((h)->info  &&  ((h)->info->flags & OBJC_IMAGE_IS_REPLACEMENT))
312
313/* OBJC_IMAGE_IS_REPLACEMENT:
314   Don't load any classes
315   Don't load any categories
316   Do fix up selector refs (@selector points to them)
317   Do fix up class refs (@class and objc_msgSend points to them)
318   Do fix up protocols (@protocol points to them)
319   Do fix up superclass pointers in classes ([super ...] points to them)
320   Future: do load new classes?
321   Future: do load new categories?
322   Future: do insert new methods on existing classes?
323   Future: do insert new methods on existing categories?
324*/
325
326#define _objcInfoSupportsGC(info) (((info)->flags & OBJC_IMAGE_SUPPORTS_GC) ? 1 : 0)
327#define _objcInfoRequiresGC(info) (((info)->flags & OBJC_IMAGE_REQUIRES_GC) ? 1 : 0)
328#define _objcHeaderSupportsGC(h) ((h)->info && _objcInfoSupportsGC((h)->info))
329#define _objcHeaderRequiresGC(h) ((h)->info && _objcInfoRequiresGC((h)->info))
330
331/* OBJC_IMAGE_SUPPORTS_GC:
332    was compiled with -fobjc-gc flag, regardless of whether write-barriers were issued
333    if executable image compiled this way, then all subsequent libraries etc. must also be this way
334*/
335
336#define _objcHeaderOptimizedByDyld(h)  ((h)->info  &&  ((h)->info->flags & OBJC_IMAGE_OPTIMIZED_BY_DYLD))
337
338/* OBJC_IMAGE_OPTIMIZED_BY_DYLD:
339   Assorted metadata precooked in the dyld shared cache.
340   Never set for images outside the shared cache file itself.
341*/
342
343
344typedef struct _header_info {
345    struct _header_info *next;
346    const headerType *mhdr;
347    const objc_image_info *info;
348    const char *fname;  // same as Dl_info.dli_fname
349    bool loaded;
350    bool inSharedCache;
351    bool allClassesRealized;
352
353    // Do not add fields without editing ObjCModernAbstraction.hpp
354
355#if !__OBJC2__
356    struct old_protocol **proto_refs;
357    struct objc_module *mod_ptr;
358    size_t              mod_count;
359# if TARGET_OS_WIN32
360    struct objc_module **modules;
361    size_t moduleCount;
362    struct old_protocol **protocols;
363    size_t protocolCount;
364    void *imageinfo;
365    size_t imageinfoBytes;
366    SEL *selrefs;
367    size_t selrefCount;
368    struct objc_class **clsrefs;
369    size_t clsrefCount;
370    TCHAR *moduleName;
371# endif
372#endif
373} header_info;
374
375extern header_info *FirstHeader;
376extern header_info *LastHeader;
377extern int HeaderCount;
378
379extern uint32_t AppSDKVersion;  // X.Y.Z is 0xXXXXYYZZ
380
381extern void appendHeader(header_info *hi);
382extern void removeHeader(header_info *hi);
383
384extern objc_image_info *_getObjcImageInfo(const headerType *head, size_t *size);
385extern BOOL _hasObjcContents(const header_info *hi);
386
387
388/* selectors */
389extern void sel_init(BOOL gc, size_t selrefCount);
390extern SEL sel_registerNameNoLock(const char *str, BOOL copy);
391extern void sel_lock(void);
392extern void sel_unlock(void);
393extern BOOL sel_preoptimizationValid(const header_info *hi);
394
395extern SEL SEL_load;
396extern SEL SEL_initialize;
397extern SEL SEL_resolveClassMethod;
398extern SEL SEL_resolveInstanceMethod;
399extern SEL SEL_cxx_construct;
400extern SEL SEL_cxx_destruct;
401extern SEL SEL_retain;
402extern SEL SEL_release;
403extern SEL SEL_autorelease;
404extern SEL SEL_retainCount;
405extern SEL SEL_alloc;
406extern SEL SEL_allocWithZone;
407extern SEL SEL_dealloc;
408extern SEL SEL_copy;
409extern SEL SEL_new;
410extern SEL SEL_finalize;
411extern SEL SEL_forwardInvocation;
412extern SEL SEL_tryRetain;
413extern SEL SEL_isDeallocating;
414extern SEL SEL_retainWeakReference;
415extern SEL SEL_allowsWeakReference;
416
417/* preoptimization */
418extern void preopt_init(void);
419extern void disableSharedCacheOptimizations(void);
420extern bool isPreoptimized(void);
421extern header_info *preoptimizedHinfoForHeader(const headerType *mhdr);
422
423#if SUPPORT_PREOPT  &&  __cplusplus
424#include <objc-shared-cache.h>
425using objc_selopt_t = const objc_opt::objc_selopt_t;
426#else
427struct objc_selopt_t;
428#endif
429
430extern objc_selopt_t *preoptimizedSelectors(void);
431extern Class getPreoptimizedClass(const char *name);
432extern Class* copyPreoptimizedClasses(const char *name, int *outCount);
433
434
435/* optional malloc zone for runtime data */
436extern malloc_zone_t *_objc_internal_zone(void);
437extern void *_malloc_internal(size_t size);
438extern void *_calloc_internal(size_t count, size_t size);
439extern void *_realloc_internal(void *ptr, size_t size);
440extern char *_strdup_internal(const char *str);
441extern char *_strdupcat_internal(const char *s1, const char *s2);
442extern uint8_t *_ustrdup_internal(const uint8_t *str);
443extern void *_memdup_internal(const void *mem, size_t size);
444extern void _free_internal(void *ptr);
445extern size_t _malloc_size_internal(void *ptr);
446
447extern Class _calloc_class(size_t size);
448
449/* method lookup */
450extern IMP lookUpImpOrNil(Class, SEL, id obj, bool initialize, bool cache, bool resolver);
451extern IMP lookUpImpOrForward(Class, SEL, id obj, bool initialize, bool cache, bool resolver);
452
453extern IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel);
454extern BOOL class_respondsToSelector_inst(Class cls, SEL sel, id inst);
455
456extern bool objcMsgLogEnabled;
457extern bool logMessageSend(bool isClassMethod,
458                    const char *objectsClass,
459                    const char *implementingClass,
460                    SEL selector);
461
462/* message dispatcher */
463extern IMP _class_lookupMethodAndLoadCache3(id, SEL, Class);
464
465#if !OBJC_OLD_DISPATCH_PROTOTYPES
466extern void _objc_msgForward_impcache(void);
467extern void _objc_ignored_method(void);
468extern void _objc_msgSend_uncached_impcache(void);
469#else
470extern id _objc_msgForward_impcache(id, SEL, ...);
471extern id _objc_ignored_method(id, SEL, ...);
472extern id _objc_msgSend_uncached_impcache(id, SEL, ...);
473#endif
474
475/* errors */
476extern void __objc_error(id, const char *, ...) __attribute__((format (printf, 2, 3), noreturn));
477extern void _objc_inform(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
478extern void _objc_inform_on_crash(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
479extern void _objc_inform_now_and_on_crash(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
480extern void _objc_inform_deprecated(const char *oldname, const char *newname) __attribute__((noinline));
481extern void inform_duplicate(const char *name, Class oldCls, Class cls);
482extern bool crashlog_header_name(header_info *hi);
483extern bool crashlog_header_name_string(const char *name);
484
485/* magic */
486extern Class _objc_getFreedObjectClass (void);
487
488/* map table additions */
489extern void *NXMapKeyCopyingInsert(NXMapTable *table, const void *key, const void *value);
490extern void *NXMapKeyFreeingRemove(NXMapTable *table, const void *key);
491
492/* hash table additions */
493extern unsigned _NXHashCapacity(NXHashTable *table);
494extern void _NXHashRehashToCapacity(NXHashTable *table, unsigned newCapacity);
495
496/* property attribute parsing */
497extern const char *copyPropertyAttributeString(const objc_property_attribute_t *attrs, unsigned int count);
498extern objc_property_attribute_t *copyPropertyAttributeList(const char *attrs, unsigned int *outCount);
499extern char *copyPropertyAttributeValue(const char *attrs, const char *name);
500
501/* locking */
502extern void lock_init(void);
503extern rwlock_t selLock;
504extern mutex_t cacheUpdateLock;
505extern recursive_mutex_t loadMethodLock;
506#if __OBJC2__
507extern rwlock_t runtimeLock;
508#else
509extern mutex_t classLock;
510extern mutex_t methodListLock;
511#endif
512
513/* Lock debugging */
514#if defined(NDEBUG)  ||  TARGET_OS_WIN32
515
516#define mutex_lock(m)             _mutex_lock_nodebug(m)
517#define mutex_try_lock(m)         _mutex_try_lock_nodebug(m)
518#define mutex_unlock(m)           _mutex_unlock_nodebug(m)
519#define mutex_assert_locked(m)    do { } while (0)
520#define mutex_assert_unlocked(m)  do { } while (0)
521
522#define recursive_mutex_lock(m)             _recursive_mutex_lock_nodebug(m)
523#define recursive_mutex_try_lock(m)         _recursive_mutex_try_lock_nodebug(m)
524#define recursive_mutex_unlock(m)           _recursive_mutex_unlock_nodebug(m)
525#define recursive_mutex_assert_locked(m)    do { } while (0)
526#define recursive_mutex_assert_unlocked(m)  do { } while (0)
527
528#define monitor_enter(m)            _monitor_enter_nodebug(m)
529#define monitor_exit(m)             _monitor_exit_nodebug(m)
530#define monitor_wait(m)             _monitor_wait_nodebug(m)
531#define monitor_assert_locked(m)    do { } while (0)
532#define monitor_assert_unlocked(m)  do { } while (0)
533
534#define rwlock_read(m)              _rwlock_read_nodebug(m)
535#define rwlock_write(m)             _rwlock_write_nodebug(m)
536#define rwlock_try_read(m)          _rwlock_try_read_nodebug(m)
537#define rwlock_try_write(m)         _rwlock_try_write_nodebug(m)
538#define rwlock_unlock_read(m)       _rwlock_unlock_read_nodebug(m)
539#define rwlock_unlock_write(m)      _rwlock_unlock_write_nodebug(m)
540#define rwlock_assert_reading(m)    do { } while (0)
541#define rwlock_assert_writing(m)    do { } while (0)
542#define rwlock_assert_locked(m)     do { } while (0)
543#define rwlock_assert_unlocked(m)   do { } while (0)
544
545#else
546
547extern int _mutex_lock_debug(mutex_t *lock, const char *name);
548extern int _mutex_try_lock_debug(mutex_t *lock, const char *name);
549extern int _mutex_unlock_debug(mutex_t *lock, const char *name);
550extern void _mutex_assert_locked_debug(mutex_t *lock, const char *name);
551extern void _mutex_assert_unlocked_debug(mutex_t *lock, const char *name);
552
553extern int _recursive_mutex_lock_debug(recursive_mutex_t *lock, const char *name);
554extern int _recursive_mutex_try_lock_debug(recursive_mutex_t *lock, const char *name);
555extern int _recursive_mutex_unlock_debug(recursive_mutex_t *lock, const char *name);
556extern void _recursive_mutex_assert_locked_debug(recursive_mutex_t *lock, const char *name);
557extern void _recursive_mutex_assert_unlocked_debug(recursive_mutex_t *lock, const char *name);
558
559extern int _monitor_enter_debug(monitor_t *lock, const char *name);
560extern int _monitor_exit_debug(monitor_t *lock, const char *name);
561extern int _monitor_wait_debug(monitor_t *lock, const char *name);
562extern void _monitor_assert_locked_debug(monitor_t *lock, const char *name);
563extern void _monitor_assert_unlocked_debug(monitor_t *lock, const char *name);
564
565extern void _rwlock_read_debug(rwlock_t *l, const char *name);
566extern void _rwlock_write_debug(rwlock_t *l, const char *name);
567extern int  _rwlock_try_read_debug(rwlock_t *l, const char *name);
568extern int  _rwlock_try_write_debug(rwlock_t *l, const char *name);
569extern void _rwlock_unlock_read_debug(rwlock_t *l, const char *name);
570extern void _rwlock_unlock_write_debug(rwlock_t *l, const char *name);
571extern void _rwlock_assert_reading_debug(rwlock_t *l, const char *name);
572extern void _rwlock_assert_writing_debug(rwlock_t *l, const char *name);
573extern void _rwlock_assert_locked_debug(rwlock_t *l, const char *name);
574extern void _rwlock_assert_unlocked_debug(rwlock_t *l, const char *name);
575
576#define mutex_lock(m)             _mutex_lock_debug (m, #m)
577#define mutex_try_lock(m)         _mutex_try_lock_debug (m, #m)
578#define mutex_unlock(m)           _mutex_unlock_debug (m, #m)
579#define mutex_assert_locked(m)    _mutex_assert_locked_debug (m, #m)
580#define mutex_assert_unlocked(m)  _mutex_assert_unlocked_debug (m, #m)
581
582#define recursive_mutex_lock(m)             _recursive_mutex_lock_debug (m, #m)
583#define recursive_mutex_try_lock(m)         _recursive_mutex_try_lock_debug (m, #m)
584#define recursive_mutex_unlock(m)           _recursive_mutex_unlock_debug (m, #m)
585#define recursive_mutex_assert_locked(m)    _recursive_mutex_assert_locked_debug (m, #m)
586#define recursive_mutex_assert_unlocked(m)  _recursive_mutex_assert_unlocked_debug (m, #m)
587
588#define monitor_enter(m)            _monitor_enter_debug(m, #m)
589#define monitor_exit(m)             _monitor_exit_debug(m, #m)
590#define monitor_wait(m)             _monitor_wait_debug(m, #m)
591#define monitor_assert_locked(m)    _monitor_assert_locked_debug(m, #m)
592#define monitor_assert_unlocked(m)  _monitor_assert_unlocked_debug(m, #m)
593
594#define rwlock_read(m)              _rwlock_read_debug(m, #m)
595#define rwlock_write(m)             _rwlock_write_debug(m, #m)
596#define rwlock_try_read(m)          _rwlock_try_read_debug(m, #m)
597#define rwlock_try_write(m)         _rwlock_try_write_debug(m, #m)
598#define rwlock_unlock_read(m)       _rwlock_unlock_read_debug(m, #m)
599#define rwlock_unlock_write(m)      _rwlock_unlock_write_debug(m, #m)
600#define rwlock_assert_reading(m)    _rwlock_assert_reading_debug(m, #m)
601#define rwlock_assert_writing(m)    _rwlock_assert_writing_debug(m, #m)
602#define rwlock_assert_locked(m)     _rwlock_assert_locked_debug(m, #m)
603#define rwlock_assert_unlocked(m)   _rwlock_assert_unlocked_debug(m, #m)
604
605#endif
606
607#define rwlock_unlock(m, s)                           \
608    do {                                              \
609        if ((s) == RDONLY) rwlock_unlock_read(m);     \
610        else if ((s) == RDWR) rwlock_unlock_write(m); \
611    } while (0)
612
613
614/* ignored selector support */
615
616/* Non-GC: no ignored selectors
617   GC (i386 Mac): some selectors ignored, remapped to kIgnore
618   GC (others): some selectors ignored, but not remapped
619*/
620
621static inline int ignoreSelector(SEL sel)
622{
623#if !SUPPORT_GC
624    return NO;
625#elif SUPPORT_IGNORED_SELECTOR_CONSTANT
626    return UseGC  &&  sel == (SEL)kIgnore;
627#else
628    return UseGC  &&
629        (sel == @selector(retain)       ||
630         sel == @selector(release)      ||
631         sel == @selector(autorelease)  ||
632         sel == @selector(retainCount)  ||
633         sel == @selector(dealloc));
634#endif
635}
636
637static inline int ignoreSelectorNamed(const char *sel)
638{
639#if !SUPPORT_GC
640    return NO;
641#else
642    // release retain retainCount dealloc autorelease
643    return (UseGC &&
644            (  (sel[0] == 'r' && sel[1] == 'e' &&
645                (strcmp(&sel[2], "lease") == 0 ||
646                 strcmp(&sel[2], "tain") == 0 ||
647                 strcmp(&sel[2], "tainCount") == 0 ))
648               ||
649               (strcmp(sel, "dealloc") == 0)
650               ||
651               (sel[0] == 'a' && sel[1] == 'u' &&
652                strcmp(&sel[2], "torelease") == 0)));
653#endif
654}
655
656/* GC startup */
657extern void gc_init(BOOL wantsGC);
658extern void gc_init2(void);
659
660/* Exceptions */
661struct alt_handler_list;
662extern void exception_init(void);
663extern void _destroyAltHandlerList(struct alt_handler_list *list);
664
665/* Class change notifications (gdb only for now) */
666#define OBJC_CLASS_ADDED (1<<0)
667#define OBJC_CLASS_REMOVED (1<<1)
668#define OBJC_CLASS_IVARS_CHANGED (1<<2)
669#define OBJC_CLASS_METHODS_CHANGED (1<<3)
670extern void gdb_objc_class_changed(Class cls, unsigned long changes, const char *classname)
671    __attribute__((noinline));
672
673#if SUPPORT_GC
674
675/* Write barrier implementations */
676extern id objc_getAssociatedObject_non_gc(id object, const void *key);
677extern void objc_setAssociatedObject_non_gc(id object, const void *key, id value, objc_AssociationPolicy policy);
678
679extern id objc_getAssociatedObject_gc(id object, const void *key);
680extern void objc_setAssociatedObject_gc(id object, const void *key, id value, objc_AssociationPolicy policy);
681
682/* xrefs */
683extern objc_xref_t _object_addExternalReference_non_gc(id obj, objc_xref_t type);
684extern id _object_readExternalReference_non_gc(objc_xref_t ref);
685extern void _object_removeExternalReference_non_gc(objc_xref_t ref);
686
687extern objc_xref_t _object_addExternalReference_gc(id obj, objc_xref_t type);
688extern id _object_readExternalReference_gc(objc_xref_t ref);
689extern void _object_removeExternalReference_gc(objc_xref_t ref);
690
691/* GC weak reference fixup. */
692extern void gc_fixup_weakreferences(id newObject, id oldObject);
693
694/* GC datasegment registration. */
695extern void gc_register_datasegment(uintptr_t base, size_t size);
696extern void gc_unregister_datasegment(uintptr_t base, size_t size);
697
698/* objc_dumpHeap implementation */
699extern BOOL _objc_dumpHeap(auto_zone_t *zone, const char *filename);
700
701#endif
702
703
704// Settings from environment variables
705#define OPTION(var, env, help) extern bool var;
706#include "objc-env.h"
707#undef OPTION
708
709extern void environ_init(void);
710
711extern void logReplacedMethod(const char *className, SEL s, BOOL isMeta, const char *catName, IMP oldImp, IMP newImp);
712
713static __inline uint32_t _objc_strhash(const char *s) {
714    uint32_t hash = 0;
715    for (;;) {
716	int a = *s++;
717	if (0 == a) break;
718	hash += (hash << 8) + a;
719    }
720    return hash;
721}
722
723
724// objc per-thread storage
725typedef struct {
726    struct _objc_initializing_classes *initializingClasses; // for +initialize
727    struct SyncCache *syncCache;  // for @synchronize
728    struct alt_handler_list *handlerList;  // for exception alt handlers
729    char *printableNames[4];  // temporary demangled names for logging
730
731    // If you add new fields here, don't forget to update
732    // _objc_pthread_destroyspecific()
733
734} _objc_pthread_data;
735
736extern _objc_pthread_data *_objc_fetch_pthread_data(BOOL create);
737extern void tls_init(void);
738
739// encoding.h
740extern unsigned int encoding_getNumberOfArguments(const char *typedesc);
741extern unsigned int encoding_getSizeOfArguments(const char *typedesc);
742extern unsigned int encoding_getArgumentInfo(const char *typedesc, unsigned int arg, const char **type, int *offset);
743extern void encoding_getReturnType(const char *t, char *dst, size_t dst_len);
744extern char * encoding_copyReturnType(const char *t);
745extern void encoding_getArgumentType(const char *t, unsigned int index, char *dst, size_t dst_len);
746extern char *encoding_copyArgumentType(const char *t, unsigned int index);
747
748// sync.h
749extern void _destroySyncCache(struct SyncCache *cache);
750
751// arr
752extern void arr_init(void);
753extern id objc_autoreleaseReturnValue(id obj);
754
755// block trampolines
756extern IMP _imp_implementationWithBlockNoCopy(id block);
757
758// layout.h
759typedef struct {
760    uint8_t *bits;
761    size_t bitCount;
762    size_t bitsAllocated;
763    BOOL weak;
764} layout_bitmap;
765extern layout_bitmap layout_bitmap_create(const unsigned char *layout_string, size_t layoutStringInstanceSize, size_t instanceSize, BOOL weak);
766extern layout_bitmap layout_bitmap_create_empty(size_t instanceSize, BOOL weak);
767extern void layout_bitmap_free(layout_bitmap bits);
768extern const unsigned char *layout_string_create(layout_bitmap bits);
769extern void layout_bitmap_set_ivar(layout_bitmap bits, const char *type, size_t offset);
770extern void layout_bitmap_grow(layout_bitmap *bits, size_t newCount);
771extern void layout_bitmap_slide(layout_bitmap *bits, size_t oldPos, size_t newPos);
772extern void layout_bitmap_slide_anywhere(layout_bitmap *bits, size_t oldPos, size_t newPos);
773extern BOOL layout_bitmap_splat(layout_bitmap dst, layout_bitmap src,
774                                size_t oldSrcInstanceSize);
775extern BOOL layout_bitmap_or(layout_bitmap dst, layout_bitmap src, const char *msg);
776extern BOOL layout_bitmap_clear(layout_bitmap dst, layout_bitmap src, const char *msg);
777extern void layout_bitmap_print(layout_bitmap bits);
778
779
780// fixme runtime
781extern Class look_up_class(const char *aClassName, BOOL includeUnconnected, BOOL includeClassHandler);
782extern const char *map_images(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info infoList[]);
783extern const char *map_images_nolock(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info infoList[]);
784extern const char * load_images(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info infoList[]);
785extern BOOL load_images_nolock(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info infoList[]);
786extern void unmap_image(const struct mach_header *mh, intptr_t vmaddr_slide);
787extern void unmap_image_nolock(const struct mach_header *mh);
788extern void _read_images(header_info **hList, uint32_t hCount);
789extern void prepare_load_methods(header_info *hi);
790extern void _unload_image(header_info *hi);
791extern const char ** _objc_copyClassNamesForImage(header_info *hi, unsigned int *outCount);
792
793
794extern const header_info *_headerForClass(Class cls);
795
796extern Class _class_remap(Class cls);
797extern Class _class_getNonMetaClass(Class cls, id obj);
798extern Ivar _class_getVariable(Class cls, const char *name, Class *memberOf);
799extern BOOL _class_usesAutomaticRetainRelease(Class cls);
800extern uint32_t _class_getInstanceStart(Class cls);
801
802extern unsigned _class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone, id *results, unsigned num_requested);
803extern id _objc_constructOrFree(id bytes, Class cls);
804
805extern const char *_category_getName(Category cat);
806extern const char *_category_getClassName(Category cat);
807extern Class _category_getClass(Category cat);
808extern IMP _category_getLoadMethod(Category cat);
809
810extern id object_cxxConstructFromClass(id obj, Class cls);
811extern void object_cxxDestruct(id obj);
812
813extern void _class_resolveMethod(Class cls, SEL sel, id inst);
814
815#define OBJC_WARN_DEPRECATED \
816    do { \
817        static int warned = 0; \
818        if (!warned) { \
819            warned = 1; \
820            _objc_inform_deprecated(__FUNCTION__, NULL); \
821        } \
822    } while (0) \
823
824__END_DECLS
825
826
827#ifndef STATIC_ASSERT
828#   define STATIC_ASSERT(x) _STATIC_ASSERT2(x, __LINE__)
829#   define _STATIC_ASSERT2(x, line) _STATIC_ASSERT3(x, line)
830#   define _STATIC_ASSERT3(x, line)                                     \
831        typedef struct {                                                \
832            int _static_assert[(x) ? 0 : -1];                           \
833        } _static_assert_ ## line __attribute__((unavailable))
834#endif
835
836#define countof(arr) (sizeof(arr) / sizeof((arr)[0]))
837
838
839// Global operator new and delete. We must not use any app overrides.
840// This ALSO REQUIRES each of these be in libobjc's unexported symbol list.
841#if __cplusplus
842#pragma clang diagnostic push
843#pragma clang diagnostic ignored "-Winline-new-delete"
844#include <new>
845inline void* operator new(std::size_t size) throw (std::bad_alloc) { return _malloc_internal(size); }
846inline void* operator new[](std::size_t size) throw (std::bad_alloc) { return _malloc_internal(size); }
847inline void* operator new(std::size_t size, const std::nothrow_t&) throw() { return _malloc_internal(size); }
848inline void* operator new[](std::size_t size, const std::nothrow_t&) throw() { return _malloc_internal(size); }
849inline void operator delete(void* p) throw() { _free_internal(p); }
850inline void operator delete[](void* p) throw() { _free_internal(p); }
851inline void operator delete(void* p, const std::nothrow_t&) throw() { _free_internal(p); }
852inline void operator delete[](void* p, const std::nothrow_t&) throw() { _free_internal(p); }
853#pragma clang diagnostic pop
854#endif
855
856
857// DisguisedPtr<T> acts like pointer type T*, except the
858// stored value is disguised to hide it from tools like `leaks`.
859// nil is disguised as itself so zero-filled memory works as expected,
860// which means 0x80..00 is also diguised as itself but we don't care
861template <typename T>
862class DisguisedPtr {
863    uintptr_t value;
864
865    static uintptr_t disguise(T* ptr) {
866        return -(uintptr_t)ptr;
867    }
868
869    static T* undisguise(uintptr_t val) {
870        return (T*)-val;
871    }
872
873 public:
874    DisguisedPtr() { }
875    DisguisedPtr(T* ptr)
876        : value(disguise(ptr)) { }
877    DisguisedPtr(const DisguisedPtr<T>& ptr)
878        : value(ptr.value) { }
879
880    DisguisedPtr<T>& operator = (T* rhs) {
881        value = disguise(rhs);
882        return *this;
883    }
884    DisguisedPtr<T>& operator = (const DisguisedPtr<T>& rhs) {
885        value = rhs.value;
886        return *this;
887    }
888
889    operator T* () const {
890        return undisguise(value);
891    }
892    T* operator -> () const {
893        return undisguise(value);
894    }
895    T& operator * () const {
896        return *undisguise(value);
897    }
898    T& operator [] (size_t i) const {
899        return undisguise(value)[i];
900    }
901
902    // pointer arithmetic operators omitted
903    // because we don't currently use them anywhere
904};
905
906
907// Pointer hash function.
908// This is not a terrific hash, but it is fast
909// and not outrageously flawed for our purposes.
910
911// Based on principles from http://locklessinc.com/articles/fast_hash/
912// and evaluation ideas from http://floodyberry.com/noncryptohashzoo/
913#if __LP64__
914static inline uint32_t ptr_hash(uint64_t key)
915{
916    key ^= key >> 4;
917    key *= 0x8a970be7488fda55;
918    key ^= __builtin_bswap64(key);
919    return (uint32_t)key;
920}
921#else
922static inline uint32_t ptr_hash(uint32_t key)
923{
924    key ^= key >> 4;
925    key *= 0x5052acdb;
926    key ^= __builtin_bswap32(key);
927    return key;
928}
929#endif
930
931/*
932  Higher-quality hash function. This is measurably slower in some workloads.
933#if __LP64__
934 uint32_t ptr_hash(uint64_t key)
935{
936    key -= __builtin_bswap64(key);
937    key *= 0x8a970be7488fda55;
938    key ^= __builtin_bswap64(key);
939    key *= 0x8a970be7488fda55;
940    key ^= __builtin_bswap64(key);
941    return (uint32_t)key;
942}
943#else
944static uint32_t ptr_hash(uint32_t key)
945{
946    key -= __builtin_bswap32(key);
947    key *= 0x5052acdb;
948    key ^= __builtin_bswap32(key);
949    key *= 0x5052acdb;
950    key ^= __builtin_bswap32(key);
951    return key;
952}
953#endif
954*/
955
956
957// Inlined parts of objc_object's implementation
958#include "objc-object.h"
959
960#endif /* _OBJC_PRIVATE_H_ */
961
962