]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-internal.h
e8e36dfcfa601a14fd4b68fa190124f122ef3450
[apple/objc4.git] / runtime / objc-internal.h
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.
58 OBJC_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__
70 struct objc_image_info;
71 OBJC_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().
77 OBJC_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.
83 OBJC_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.
87 OBJC_EXPORT BOOL objc_isAuto(id object)
88 __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_NA);
89
90 // env NSObjCMessageLoggingEnabled
91 OBJC_EXPORT void instrumentObjcMessageSends(BOOL flag)
92 __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
93
94 // Initializer called by libSystem
95 #if __OBJC2__
96 OBJC_EXPORT void _objc_init(void)
97 __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0);
98 #endif
99
100 // GC startup callback from Foundation
101 OBJC_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.
105 OBJC_EXPORT id objc_assign_strongCast_generic(id value, id *dest)
106 UNAVAILABLE_ATTRIBUTE;
107 OBJC_EXPORT id objc_assign_global_generic(id value, id *dest)
108 UNAVAILABLE_ATTRIBUTE;
109 OBJC_EXPORT id objc_assign_threadlocal_generic(id value, id *dest)
110 UNAVAILABLE_ATTRIBUTE;
111 OBJC_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.
115 OBJC_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.
119 OBJC_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__
124 OBJC_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__
130 OBJC_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
154 enum objc_tag_index_t : uint8_t
155 #else
156 typedef uint8_t objc_tag_index_t;
157 enum
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)
170 typedef enum objc_tag_index_t objc_tag_index_t;
171 #endif
172
173 OBJC_EXPORT void _objc_registerTaggedPointerClass(objc_tag_index_t tag, Class cls)
174 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0);
175
176 OBJC_EXPORT Class _objc_getClassForTag(objc_tag_index_t tag)
177 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0);
178
179 static 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
189 static 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
198 static inline bool
199 _objc_isTaggedPointer(const void *ptr)
200 {
201 return (intptr_t)ptr < 0; // a.k.a. ptr & 0x8000000000000000
202 }
203
204 static 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
211 static inline uintptr_t
212 _objc_getTaggedPointerValue(const void *ptr)
213 {
214 // assert(_objc_isTaggedPointer(ptr));
215 return (uintptr_t)ptr & 0x0fffffffffffffff;
216 }
217
218 static 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
230 static 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
239 static inline bool
240 _objc_isTaggedPointer(const void *ptr)
241 {
242 return (uintptr_t)ptr & 1;
243 }
244
245 static 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
252 static inline uintptr_t
253 _objc_getTaggedPointerValue(const void *ptr)
254 {
255 // assert(_objc_isTaggedPointer(ptr));
256 return (uintptr_t)ptr >> 4;
257 }
258
259 static 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
270 OBJC_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
278 enum {
279 OBJC_XREF_STRONG = 1,
280 OBJC_XREF_WEAK = 2
281 };
282 typedef uintptr_t objc_xref_type_t;
283 typedef uintptr_t objc_xref_t;
284
285 OBJC_EXPORT objc_xref_t _object_addExternalReference(id object, objc_xref_type_t type)
286 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
287 OBJC_EXPORT void _object_removeExternalReference(objc_xref_t xref)
288 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
289 OBJC_EXPORT id _object_readExternalReference(objc_xref_t xref)
290 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
291
292 OBJC_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 */
308 OBJC_EXPORT IMP object_getMethodImplementation(id obj, SEL name)
309 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0);
310
311 OBJC_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
318 OBJC_EXPORT void _class_setIvarLayoutAccessor(Class cls_gen, const uint8_t* (*accessor) (id object))
319 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
320 OBJC_EXPORT const uint8_t *_object_getIvarLayout(Class cls_gen, id object)
321 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
322
323 OBJC_EXPORT BOOL _class_usesAutomaticRetainRelease(Class cls)
324 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
325
326 OBJC_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
336 OBJC_EXPORT id objc_retainedObject(objc_objectptr_t pointer)
337 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
338 OBJC_EXPORT id objc_unretainedObject(objc_objectptr_t pointer)
339 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
340 OBJC_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
354 OBJC_EXPORT
355 id
356 _objc_rootRetain(id obj)
357 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
358
359 OBJC_EXPORT
360 void
361 _objc_rootRelease(id obj)
362 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
363
364 OBJC_EXPORT
365 bool
366 _objc_rootReleaseWasZero(id obj)
367 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
368
369 OBJC_EXPORT
370 bool
371 _objc_rootTryRetain(id obj)
372 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
373
374 OBJC_EXPORT
375 bool
376 _objc_rootIsDeallocating(id obj)
377 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
378
379 OBJC_EXPORT
380 id
381 _objc_rootAutorelease(id obj)
382 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
383
384 OBJC_EXPORT
385 uintptr_t
386 _objc_rootRetainCount(id obj)
387 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
388
389 OBJC_EXPORT
390 id
391 _objc_rootInit(id obj)
392 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
393
394 OBJC_EXPORT
395 id
396 _objc_rootAllocWithZone(Class cls, malloc_zone_t *zone)
397 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
398
399 OBJC_EXPORT
400 id
401 _objc_rootAlloc(Class cls)
402 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
403
404 OBJC_EXPORT
405 void
406 _objc_rootDealloc(id obj)
407 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
408
409 OBJC_EXPORT
410 void
411 _objc_rootFinalize(id obj)
412 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
413
414 OBJC_EXPORT
415 malloc_zone_t *
416 _objc_rootZone(id obj)
417 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
418
419 OBJC_EXPORT
420 uintptr_t
421 _objc_rootHash(id obj)
422 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
423
424 OBJC_EXPORT
425 void *
426 objc_autoreleasePoolPush(void)
427 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
428
429 OBJC_EXPORT
430 void
431 objc_autoreleasePoolPop(void *context)
432 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
433
434
435 OBJC_EXPORT id objc_alloc(Class cls)
436 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0);
437
438 OBJC_EXPORT id objc_allocWithZone(Class cls)
439 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0);
440
441 OBJC_EXPORT id objc_retain(id obj)
442 __asm__("_objc_retain")
443 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
444
445 OBJC_EXPORT void objc_release(id obj)
446 __asm__("_objc_release")
447 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
448
449 OBJC_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
454 OBJC_EXPORT
455 id
456 objc_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
460 OBJC_EXPORT
461 id
462 objc_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
466 OBJC_EXPORT
467 id
468 objc_retainAutoreleasedReturnValue(id obj)
469 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
470
471 OBJC_EXPORT
472 void
473 objc_storeStrong(id *location, id obj)
474 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
475
476 OBJC_EXPORT
477 id
478 objc_retainAutorelease(id obj)
479 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
480
481 // obsolete.
482 OBJC_EXPORT id objc_retain_autorelease(id obj)
483 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
484
485 OBJC_EXPORT
486 id
487 objc_loadWeakRetained(id *location)
488 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
489
490 OBJC_EXPORT
491 id
492 objc_initWeak(id *addr, id val)
493 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
494
495 OBJC_EXPORT
496 void
497 objc_destroyWeak(id *addr)
498 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
499
500 OBJC_EXPORT
501 void
502 objc_copyWeak(id *to, id *from)
503 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
504
505 OBJC_EXPORT
506 void
507 objc_moveWeak(id *to, id *from)
508 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
509
510
511 OBJC_EXPORT
512 void
513 _objc_autoreleasePoolPrint(void)
514 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
515
516 OBJC_EXPORT BOOL objc_should_deallocate(id object)
517 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
518
519 OBJC_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
525 OBJC_EXPORT
526 void *
527 _objc_autoreleasePoolPush(void)
528 __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0);
529
530 OBJC_EXPORT
531 void
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
537 OBJC_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
543 OBJC_EXPORT
544 void
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
569 typedef 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