1/*
2 * Copyright (c) 2009 Apple Inc.  All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25#ifndef _OBJC_INTERNAL_H
26#define _OBJC_INTERNAL_H
27
28/*
29 * WARNING  DANGER  HAZARD  BEWARE  EEK
30 *
31 * Everything in this file is for Apple Internal use only.
32 * These will change in arbitrary OS updates and in unpredictable ways.
33 * When your program breaks, you get to keep both pieces.
34 */
35
36/*
37 * objc-internal.h: Private SPI for use by other system frameworks.
38 */
39
40#include <objc/objc.h>
41#include <objc/runtime.h>
42#include <Availability.h>
43#include <malloc/malloc.h>
44#include <dispatch/dispatch.h>
45
46__BEGIN_DECLS
47
48// This is the allocation size required for each of the class and the metaclass
49// with objc_initializeClassPair() and objc_readClassPair().
50// The runtime's class structure will never grow beyond this.
51#define OBJC_MAX_CLASS_SIZE (32*sizeof(void*))
52
53// In-place construction of an Objective-C class.
54// cls and metacls must each be OBJC_MAX_CLASS_SIZE bytes.
55// Returns nil if a class with the same name already exists.
56// Returns nil if the superclass is under construction.
57// Call objc_registerClassPair() when you are done.
58OBJC_EXPORT Class objc_initializeClassPair(Class superclass, const char *name, Class cls, Class metacls)
59    __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0);
60
61// Class and metaclass construction from a compiler-generated memory image.
62// cls and cls->isa must each be OBJC_MAX_CLASS_SIZE bytes.
63// Extra bytes not used the the metadata must be zero.
64// info is the same objc_image_info that would be emitted by a static compiler.
65// Returns nil if a class with the same name already exists.
66// Returns nil if the superclass is nil and the class is not marked as a root.
67// Returns nil if the superclass is under construction.
68// Do not call objc_registerClassPair().
69#if __OBJC2__
70struct objc_image_info;
71OBJC_EXPORT Class objc_readClassPair(Class cls,
72                                     const struct objc_image_info *info)
73    __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0);
74#endif
75
76// Batch object allocation using malloc_zone_batch_malloc().
77OBJC_EXPORT unsigned class_createInstances(Class cls, size_t extraBytes,
78                                           id *results, unsigned num_requested)
79    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3)
80    OBJC_ARC_UNAVAILABLE;
81
82// Get the isa pointer written into objects just before being freed.
83OBJC_EXPORT Class _objc_getFreedObjectClass(void)
84    __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
85
86// Return YES if GC is on and `object` is a GC allocation.
87OBJC_EXPORT BOOL objc_isAuto(id object)
88    __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_NA);
89
90// env NSObjCMessageLoggingEnabled
91OBJC_EXPORT void instrumentObjcMessageSends(BOOL flag)
92    __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
93
94// Initializer called by libSystem
95#if __OBJC2__
96OBJC_EXPORT void _objc_init(void)
97    __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0);
98#endif
99
100// GC startup callback from Foundation
101OBJC_EXPORT malloc_zone_t *objc_collect_init(int (*callback)(void))
102    __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_NA);
103
104// Plainly-implemented GC barriers. Rosetta used to use these.
105OBJC_EXPORT id objc_assign_strongCast_generic(id value, id *dest)
106    UNAVAILABLE_ATTRIBUTE;
107OBJC_EXPORT id objc_assign_global_generic(id value, id *dest)
108    UNAVAILABLE_ATTRIBUTE;
109OBJC_EXPORT id objc_assign_threadlocal_generic(id value, id *dest)
110    UNAVAILABLE_ATTRIBUTE;
111OBJC_EXPORT id objc_assign_ivar_generic(id value, id dest, ptrdiff_t offset)
112    UNAVAILABLE_ATTRIBUTE;
113
114// Install missing-class callback. Used by the late unlamented ZeroLink.
115OBJC_EXPORT void _objc_setClassLoader(BOOL (*newClassLoader)(const char *))  OBJC2_UNAVAILABLE;
116
117// Install handler for allocation failures.
118// Handler may abort, or throw, or provide an object to return.
119OBJC_EXPORT void _objc_setBadAllocHandler(id (*newHandler)(Class isa))
120     __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0);
121
122// This can go away when AppKit stops calling it (rdar://7811851)
123#if __OBJC2__
124OBJC_EXPORT void objc_setMultithreaded (BOOL flag)
125    __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0,__MAC_10_5, __IPHONE_NA,__IPHONE_NA);
126#endif
127
128// Used by ExceptionHandling.framework
129#if !__OBJC2__
130OBJC_EXPORT void _objc_error(id rcv, const char *fmt, va_list args)
131    __attribute__((noreturn))
132    __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0,__MAC_10_5, __IPHONE_NA,__IPHONE_NA);
133
134#endif
135
136
137// Tagged pointer objects.
138
139#if __LP64__
140#define OBJC_HAVE_TAGGED_POINTERS 1
141#endif
142
143#if OBJC_HAVE_TAGGED_POINTERS
144
145// Tagged pointer layout and usage is subject to change
146// on different OS versions. The current layout is:
147// (MSB)
148// 60 bits  payload
149//  3 bits  tag index
150//  1 bit   1 for tagged pointer objects, 0 for ordinary objects
151// (LSB)
152
153#if __has_feature(objc_fixed_enum)  ||  __cplusplus >= 201103L
154enum objc_tag_index_t : uint8_t
155#else
156typedef uint8_t objc_tag_index_t;
157enum
158#endif
159{
160    OBJC_TAG_NSAtom            = 0,
161    OBJC_TAG_1                 = 1,
162    OBJC_TAG_NSString          = 2,
163    OBJC_TAG_NSNumber          = 3,
164    OBJC_TAG_NSIndexPath       = 4,
165    OBJC_TAG_NSManagedObjectID = 5,
166    OBJC_TAG_NSDate            = 6,
167    OBJC_TAG_7                 = 7
168};
169#if __has_feature(objc_fixed_enum)  &&  !defined(__cplusplus)
170typedef enum objc_tag_index_t objc_tag_index_t;
171#endif
172
173OBJC_EXPORT void _objc_registerTaggedPointerClass(objc_tag_index_t tag, Class cls)
174    __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0);
175
176OBJC_EXPORT Class _objc_getClassForTag(objc_tag_index_t tag)
177    __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0);
178
179static inline bool
180_objc_taggedPointersEnabled(void)
181{
182    extern uintptr_t objc_debug_taggedpointer_mask;
183    return (objc_debug_taggedpointer_mask != 0);
184}
185
186#if TARGET_OS_IPHONE
187// tagged pointer marker is MSB
188
189static inline void *
190_objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t value)
191{
192    // assert(_objc_taggedPointersEnabled());
193    // assert((unsigned int)tag < 8);
194    // assert(((value << 4) >> 4) == value);
195    return (void*)((1UL << 63) | ((uintptr_t)tag << 60) | (value & ~(0xFUL << 60)));
196}
197
198static inline bool
199_objc_isTaggedPointer(const void *ptr)
200{
201    return (intptr_t)ptr < 0;  // a.k.a. ptr & 0x8000000000000000
202}
203
204static inline objc_tag_index_t
205_objc_getTaggedPointerTag(const void *ptr)
206{
207    // assert(_objc_isTaggedPointer(ptr));
208    return (objc_tag_index_t)(((uintptr_t)ptr >> 60) & 0x7);
209}
210
211static inline uintptr_t
212_objc_getTaggedPointerValue(const void *ptr)
213{
214    // assert(_objc_isTaggedPointer(ptr));
215    return (uintptr_t)ptr & 0x0fffffffffffffff;
216}
217
218static inline intptr_t
219_objc_getTaggedPointerSignedValue(const void *ptr)
220{
221    // assert(_objc_isTaggedPointer(ptr));
222    return ((intptr_t)ptr << 4) >> 4;
223}
224
225// TARGET_OS_IPHONE
226#else
227// not TARGET_OS_IPHONE
228// tagged pointer marker is LSB
229
230static inline void *
231_objc_makeTaggedPointer(objc_tag_index_t tag, uintptr_t value)
232{
233    // assert(_objc_taggedPointersEnabled());
234    // assert((unsigned int)tag < 8);
235    // assert(((value << 4) >> 4) == value);
236    return (void *)((value << 4) | ((uintptr_t)tag << 1) | 1);
237}
238
239static inline bool
240_objc_isTaggedPointer(const void *ptr)
241{
242    return (uintptr_t)ptr & 1;
243}
244
245static inline objc_tag_index_t
246_objc_getTaggedPointerTag(const void *ptr)
247{
248    // assert(_objc_isTaggedPointer(ptr));
249    return (objc_tag_index_t)(((uintptr_t)ptr & 0xe) >> 1);
250}
251
252static inline uintptr_t
253_objc_getTaggedPointerValue(const void *ptr)
254{
255    // assert(_objc_isTaggedPointer(ptr));
256    return (uintptr_t)ptr >> 4;
257}
258
259static inline intptr_t
260_objc_getTaggedPointerSignedValue(const void *ptr)
261{
262    // assert(_objc_isTaggedPointer(ptr));
263    return (intptr_t)ptr >> 4;
264}
265
266// not TARGET_OS_IPHONE
267#endif
268
269
270OBJC_EXPORT void _objc_insert_tagged_isa(unsigned char slotNumber, Class isa)
271    __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7,__MAC_10_9, __IPHONE_4_3,__IPHONE_7_0);
272
273#endif
274
275
276// External Reference support. Used to support compaction.
277
278enum {
279    OBJC_XREF_STRONG = 1,
280    OBJC_XREF_WEAK = 2
281};
282typedef uintptr_t objc_xref_type_t;
283typedef uintptr_t objc_xref_t;
284
285OBJC_EXPORT objc_xref_t _object_addExternalReference(id object, objc_xref_type_t type)
286     __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
287OBJC_EXPORT void _object_removeExternalReference(objc_xref_t xref)
288     __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
289OBJC_EXPORT id _object_readExternalReference(objc_xref_t xref)
290     __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
291
292OBJC_EXPORT uintptr_t _object_getExternalHash(id object)
293     __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
294
295/**
296 * Returns the method implementation of an object.
297 *
298 * @param obj An Objective-C object.
299 * @param name An Objective-C selector.
300 *
301 * @return The IMP corresponding to the instance method implemented by
302 * the class of \e obj.
303 *
304 * @note Equivalent to:
305 *
306 * class_getMethodImplementation(object_getClass(obj), name);
307 */
308OBJC_EXPORT IMP object_getMethodImplementation(id obj, SEL name)
309    __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0);
310
311OBJC_EXPORT IMP object_getMethodImplementation_stret(id obj, SEL name)
312    __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
313    OBJC_ARM64_UNAVAILABLE;
314
315
316// Instance-specific instance variable layout.
317
318OBJC_EXPORT void _class_setIvarLayoutAccessor(Class cls_gen, const uint8_t* (*accessor) (id object))
319     __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
320OBJC_EXPORT const uint8_t *_object_getIvarLayout(Class cls_gen, id object)
321     __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
322
323OBJC_EXPORT BOOL _class_usesAutomaticRetainRelease(Class cls)
324    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
325
326OBJC_EXPORT BOOL _class_isFutureClass(Class cls)
327    __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0);
328
329
330// Obsolete ARC conversions.
331
332// hack - remove and reinstate objc.h's definitions
333#undef objc_retainedObject
334#undef objc_unretainedObject
335#undef objc_unretainedPointer
336OBJC_EXPORT id objc_retainedObject(objc_objectptr_t pointer)
337    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
338OBJC_EXPORT id objc_unretainedObject(objc_objectptr_t pointer)
339    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
340OBJC_EXPORT objc_objectptr_t objc_unretainedPointer(id object)
341    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
342#if __has_feature(objc_arc)
343#   define objc_retainedObject(o) ((__bridge_transfer id)(objc_objectptr_t)(o))
344#   define objc_unretainedObject(o) ((__bridge id)(objc_objectptr_t)(o))
345#   define objc_unretainedPointer(o) ((__bridge objc_objectptr_t)(id)(o))
346#else
347#   define objc_retainedObject(o) ((id)(objc_objectptr_t)(o))
348#   define objc_unretainedObject(o) ((id)(objc_objectptr_t)(o))
349#   define objc_unretainedPointer(o) ((objc_objectptr_t)(id)(o))
350#endif
351
352// API to only be called by root classes like NSObject or NSProxy
353
354OBJC_EXPORT
355id
356_objc_rootRetain(id obj)
357    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
358
359OBJC_EXPORT
360void
361_objc_rootRelease(id obj)
362    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
363
364OBJC_EXPORT
365bool
366_objc_rootReleaseWasZero(id obj)
367    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
368
369OBJC_EXPORT
370bool
371_objc_rootTryRetain(id obj)
372__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
373
374OBJC_EXPORT
375bool
376_objc_rootIsDeallocating(id obj)
377__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
378
379OBJC_EXPORT
380id
381_objc_rootAutorelease(id obj)
382    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
383
384OBJC_EXPORT
385uintptr_t
386_objc_rootRetainCount(id obj)
387    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
388
389OBJC_EXPORT
390id
391_objc_rootInit(id obj)
392    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
393
394OBJC_EXPORT
395id
396_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone)
397    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
398
399OBJC_EXPORT
400id
401_objc_rootAlloc(Class cls)
402    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
403
404OBJC_EXPORT
405void
406_objc_rootDealloc(id obj)
407    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
408
409OBJC_EXPORT
410void
411_objc_rootFinalize(id obj)
412    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
413
414OBJC_EXPORT
415malloc_zone_t *
416_objc_rootZone(id obj)
417    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
418
419OBJC_EXPORT
420uintptr_t
421_objc_rootHash(id obj)
422    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
423
424OBJC_EXPORT
425void *
426objc_autoreleasePoolPush(void)
427    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
428
429OBJC_EXPORT
430void
431objc_autoreleasePoolPop(void *context)
432    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
433
434
435OBJC_EXPORT id objc_alloc(Class cls)
436    __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0);
437
438OBJC_EXPORT id objc_allocWithZone(Class cls)
439    __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0);
440
441OBJC_EXPORT id objc_retain(id obj)
442    __asm__("_objc_retain")
443    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
444
445OBJC_EXPORT void objc_release(id obj)
446    __asm__("_objc_release")
447    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
448
449OBJC_EXPORT id objc_autorelease(id obj)
450    __asm__("_objc_autorelease")
451    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
452
453// wraps objc_autorelease(obj) in a useful way when used with return values
454OBJC_EXPORT
455id
456objc_autoreleaseReturnValue(id obj)
457    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
458
459// wraps objc_autorelease(objc_retain(obj)) in a useful way when used with return values
460OBJC_EXPORT
461id
462objc_retainAutoreleaseReturnValue(id obj)
463    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
464
465// called ONLY by ARR by callers to undo the autorelease (if possible), otherwise objc_retain
466OBJC_EXPORT
467id
468objc_retainAutoreleasedReturnValue(id obj)
469    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
470
471OBJC_EXPORT
472void
473objc_storeStrong(id *location, id obj)
474    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
475
476OBJC_EXPORT
477id
478objc_retainAutorelease(id obj)
479    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
480
481// obsolete.
482OBJC_EXPORT id objc_retain_autorelease(id obj)
483    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
484
485OBJC_EXPORT
486id
487objc_loadWeakRetained(id *location)
488    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
489
490OBJC_EXPORT
491id
492objc_initWeak(id *addr, id val)
493    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
494
495OBJC_EXPORT
496void
497objc_destroyWeak(id *addr)
498    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
499
500OBJC_EXPORT
501void
502objc_copyWeak(id *to, id *from)
503    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
504
505OBJC_EXPORT
506void
507objc_moveWeak(id *to, id *from)
508    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
509
510
511OBJC_EXPORT
512void
513_objc_autoreleasePoolPrint(void)
514    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
515
516OBJC_EXPORT BOOL objc_should_deallocate(id object)
517    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
518
519OBJC_EXPORT void objc_clear_deallocating(id object)
520    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
521
522
523// to make CF link for now
524
525OBJC_EXPORT
526void *
527_objc_autoreleasePoolPush(void)
528    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
529
530OBJC_EXPORT
531void
532_objc_autoreleasePoolPop(void *context)
533    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
534
535
536// Extra @encode data for XPC, or NULL
537OBJC_EXPORT const char *_protocol_getMethodTypeEncoding(Protocol *p, SEL sel, BOOL isRequiredMethod, BOOL isInstanceMethod)
538    __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0);
539
540
541// API to only be called by classes that provide their own reference count storage
542
543OBJC_EXPORT
544void
545_objc_deallocOnMainThreadHelper(void *context)
546    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
547
548// On async versus sync deallocation and the _dealloc2main flag
549//
550// Theory:
551//
552// If order matters, then code must always: [self dealloc].
553// If order doesn't matter, then always async should be safe.
554//
555// Practice:
556//
557// The _dealloc2main bit is set for GUI objects that may be retained by other
558// threads. Once deallocation begins on the main thread, doing more async
559// deallocation will at best cause extra UI latency and at worst cause
560// use-after-free bugs in unretained delegate style patterns. Yes, this is
561// extremely fragile. Yes, in the long run, developers should switch to weak
562// references.
563//
564// Note is NOT safe to do any equality check against the result of
565// dispatch_get_current_queue(). The main thread can and does drain more than
566// one dispatch queue. That is why we call pthread_main_np().
567//
568
569typedef enum {
570    _OBJC_RESURRECT_OBJECT = -1,        /* _logicBlock has called -retain, and scheduled a -release for later. */
571    _OBJC_DEALLOC_OBJECT_NOW = 1,       /* call [self dealloc] immediately. */
572    _OBJC_DEALLOC_OBJECT_LATER = 2      /* call [self dealloc] on the main queue. */
573} _objc_object_disposition_t;
574
575#define _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC_BLOCK(_rc_ivar, _logicBlock)        \
576    -(id)retain {                                                               \
577        /* this will fail to compile if _rc_ivar is an unsigned type */         \
578        int _retain_count_ivar_must_not_be_unsigned[0L - (__typeof__(_rc_ivar))-1] __attribute__((unused)); \
579        __typeof__(_rc_ivar) _prev = __sync_fetch_and_add(&_rc_ivar, 2);        \
580        if (_prev < -2) { /* specifically allow resurrection from logical 0. */ \
581            __builtin_trap(); /* BUG: retain of over-released ref */            \
582        }                                                                       \
583        return self;                                                            \
584    }                                                                           \
585    -(oneway void)release {                                                     \
586        __typeof__(_rc_ivar) _prev = __sync_fetch_and_sub(&_rc_ivar, 2);        \
587        if (_prev > 0) {                                                        \
588            return;                                                             \
589        } else if (_prev < 0) {                                                 \
590            __builtin_trap(); /* BUG: over-release */                           \
591        }                                                                       \
592        _objc_object_disposition_t fate = _logicBlock(self);                    \
593        if (fate == _OBJC_RESURRECT_OBJECT) {                                   \
594            return;                                                             \
595        }                                                                       \
596        /* mark the object as deallocating. */                                  \
597        if (!__sync_bool_compare_and_swap(&_rc_ivar, -2, 1)) {                  \
598            __builtin_trap(); /* BUG: dangling ref did a retain */              \
599        }                                                                       \
600        if (fate == _OBJC_DEALLOC_OBJECT_NOW) {                                 \
601            [self dealloc];                                                     \
602        } else if (fate == _OBJC_DEALLOC_OBJECT_LATER) {                        \
603            dispatch_barrier_async_f(dispatch_get_main_queue(), self,           \
604                _objc_deallocOnMainThreadHelper);                               \
605        } else {                                                                \
606            __builtin_trap(); /* BUG: bogus fate value */                       \
607        }                                                                       \
608    }                                                                           \
609    -(NSUInteger)retainCount {                                                  \
610        return (_rc_ivar + 2) >> 1;                                             \
611    }                                                                           \
612    -(BOOL)_tryRetain {                                                         \
613        __typeof__(_rc_ivar) _prev;                                             \
614        do {                                                                    \
615            _prev = _rc_ivar;                                                   \
616            if (_prev & 1) {                                                    \
617                return 0;                                                       \
618            } else if (_prev == -2) {                                           \
619                return 0;                                                       \
620            } else if (_prev < -2) {                                            \
621                __builtin_trap(); /* BUG: over-release elsewhere */             \
622            }                                                                   \
623        } while ( ! __sync_bool_compare_and_swap(&_rc_ivar, _prev, _prev + 2)); \
624        return 1;                                                               \
625    }                                                                           \
626    -(BOOL)_isDeallocating {                                                    \
627        if (_rc_ivar == -2) {                                                   \
628            return 1;                                                           \
629        } else if (_rc_ivar < -2) {                                             \
630            __builtin_trap(); /* BUG: over-release elsewhere */                 \
631        }                                                                       \
632        return _rc_ivar & 1;                                                    \
633    }
634
635#define _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, _dealloc2main)            \
636    _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC_BLOCK(_rc_ivar, (^(id _self_ __attribute__((unused))) { \
637        if (_dealloc2main && !pthread_main_np()) {                              \
638            return _OBJC_DEALLOC_OBJECT_LATER;                                  \
639        } else {                                                                \
640            return _OBJC_DEALLOC_OBJECT_NOW;                                    \
641        }                                                                       \
642    }))
643
644#define _OBJC_SUPPORTED_INLINE_REFCNT(_rc_ivar) _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, 0)
645#define _OBJC_SUPPORTED_INLINE_REFCNT_WITH_DEALLOC2MAIN(_rc_ivar) _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, 1)
646
647__END_DECLS
648
649#endif
650