]>
Commit | Line | Data |
---|---|---|
13d88034 | 1 | /* |
8972963c | 2 | * Copyright (c) 2009 Apple Inc. All Rights Reserved. |
13d88034 | 3 | * |
b3962a83 | 4 | * @APPLE_LICENSE_HEADER_START@ |
390d5862 A |
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. | |
13d88034 A |
12 | * |
13 | * The Original Code and all software distributed under the License are | |
390d5862 | 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
13d88034 A |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
390d5862 A |
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. | |
13d88034 A |
20 | * |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
7af964d1 A |
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. | |
13d88034 A |
34 | */ |
35 | ||
8972963c A |
36 | /* |
37 | * objc-internal.h: Private SPI for use by other system frameworks. | |
38 | */ | |
39 | ||
7af964d1 | 40 | #include <objc/objc.h> |
7257e56c | 41 | #include <objc/runtime.h> |
7af964d1 | 42 | #include <Availability.h> |
8972963c A |
43 | #include <malloc/malloc.h> |
44 | #include <dispatch/dispatch.h> | |
7af964d1 | 45 | |
8972963c A |
46 | __BEGIN_DECLS |
47 | ||
8070259c A |
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 | ||
8972963c | 53 | // In-place construction of an Objective-C class. |
8070259c A |
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) | |
8972963c A |
59 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0); |
60 | ||
8070259c A |
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 | ||
8972963c A |
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 | ||
8972963c A |
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 | ||
cd5f04f5 A |
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 | ||
8972963c A |
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 | ||
cd5f04f5 A |
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 | ||
8972963c A |
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 | ||
7257e56c A |
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) | |
8070259c | 174 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); |
7257e56c A |
175 | |
176 | OBJC_EXPORT Class _objc_getClassForTag(objc_tag_index_t tag) | |
8070259c | 177 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); |
7257e56c A |
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 | ||
8070259c A |
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 | ||
7257e56c A |
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 | ||
8070259c A |
266 | // not TARGET_OS_IPHONE |
267 | #endif | |
268 | ||
7257e56c A |
269 | |
270 | OBJC_EXPORT void _objc_insert_tagged_isa(unsigned char slotNumber, Class isa) | |
8070259c | 271 | __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7,__MAC_10_9, __IPHONE_4_3,__IPHONE_7_0); |
7257e56c A |
272 | |
273 | #endif | |
274 | ||
275 | ||
8972963c A |
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 | ||
7257e56c A |
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) | |
8070259c A |
312 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0) |
313 | OBJC_ARM64_UNAVAILABLE; | |
7257e56c A |
314 | |
315 | ||
8972963c A |
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 | ||
7257e56c A |
326 | OBJC_EXPORT BOOL _class_isFutureClass(Class cls) |
327 | __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); | |
328 | ||
329 | ||
cd5f04f5 A |
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 | ||
8972963c A |
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 | ||
7257e56c A |
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 | ||
8972963c A |
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 | ||
cd5f04f5 A |
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 | ||
8972963c A |
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 | ||
cd5f04f5 A |
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 */ \ | |
8972963c | 578 | int _retain_count_ivar_must_not_be_unsigned[0L - (__typeof__(_rc_ivar))-1] __attribute__((unused)); \ |
cd5f04f5 A |
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 | } \ | |
8972963c | 623 | } while ( ! __sync_bool_compare_and_swap(&_rc_ivar, _prev, _prev + 2)); \ |
cd5f04f5 A |
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; \ | |
8972963c A |
633 | } |
634 | ||
cd5f04f5 A |
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 | ||
8972963c A |
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 | |
13d88034 | 648 | |
13d88034 | 649 | #endif |