/* * Copyright (c) 2009 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #ifndef _OBJC_INTERNAL_H #define _OBJC_INTERNAL_H /* * WARNING DANGER HAZARD BEWARE EEK * * Everything in this file is for Apple Internal use only. * These will change in arbitrary OS updates and in unpredictable ways. * When your program breaks, you get to keep both pieces. */ /* * objc-internal.h: Private SPI for use by other system frameworks. */ #include #include #include #include __BEGIN_DECLS // In-place construction of an Objective-C class. OBJC_EXPORT Class objc_initializeClassPair(Class superclass_gen, const char *name, Class cls_gen, Class meta_gen) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0); #if __OBJC2__ && __LP64__ // Register a tagged pointer class. OBJC_EXPORT void _objc_insert_tagged_isa(unsigned char slotNumber, Class isa) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); #endif // Batch object allocation using malloc_zone_batch_malloc(). OBJC_EXPORT unsigned class_createInstances(Class cls, size_t extraBytes, id *results, unsigned num_requested) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3) OBJC_ARC_UNAVAILABLE; // Get the isa pointer written into objects just before being freed. OBJC_EXPORT Class _objc_getFreedObjectClass(void) __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0); // Substitute receiver for messages to nil. // Not supported for all messages to nil. OBJC_EXPORT id _objc_setNilReceiver(id newNilReceiver) __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA); OBJC_EXPORT id _objc_getNilReceiver(void) __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA); // Return NO if no instance of `cls` has ever owned an associative reference. OBJC_EXPORT BOOL class_instancesHaveAssociatedObjects(Class cls) __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_0); // Return YES if GC is on and `object` is a GC allocation. OBJC_EXPORT BOOL objc_isAuto(id object) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_NA); // env NSObjCMessageLoggingEnabled OBJC_EXPORT void instrumentObjcMessageSends(BOOL flag) __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0); // Initializer called by libSystem #if __OBJC2__ OBJC_EXPORT void _objc_init(void) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0); #endif // GC startup callback from Foundation OBJC_EXPORT malloc_zone_t *objc_collect_init(int (*callback)(void)) __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_NA); // Plainly-implemented GC barriers. Rosetta used to use these. OBJC_EXPORT id objc_assign_strongCast_generic(id value, id *dest) UNAVAILABLE_ATTRIBUTE; OBJC_EXPORT id objc_assign_global_generic(id value, id *dest) UNAVAILABLE_ATTRIBUTE; OBJC_EXPORT id objc_assign_threadlocal_generic(id value, id *dest) UNAVAILABLE_ATTRIBUTE; OBJC_EXPORT id objc_assign_ivar_generic(id value, id dest, ptrdiff_t offset) UNAVAILABLE_ATTRIBUTE; // Install missing-class callback. Used by the late unlamented ZeroLink. OBJC_EXPORT void _objc_setClassLoader(BOOL (*newClassLoader)(const char *)) OBJC2_UNAVAILABLE; // Install handler for allocation failures. // Handler may abort, or throw, or provide an object to return. OBJC_EXPORT void _objc_setBadAllocHandler(id (*newHandler)(Class isa)) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0); // This can go away when AppKit stops calling it (rdar://7811851) #if __OBJC2__ OBJC_EXPORT void objc_setMultithreaded (BOOL flag) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0,__MAC_10_5, __IPHONE_NA,__IPHONE_NA); #endif // Used by ExceptionHandling.framework #if !__OBJC2__ OBJC_EXPORT void _objc_error(id rcv, const char *fmt, va_list args) __attribute__((noreturn)) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_0,__MAC_10_5, __IPHONE_NA,__IPHONE_NA); #endif // External Reference support. Used to support compaction. enum { OBJC_XREF_STRONG = 1, OBJC_XREF_WEAK = 2 }; typedef uintptr_t objc_xref_type_t; typedef uintptr_t objc_xref_t; OBJC_EXPORT objc_xref_t _object_addExternalReference(id object, objc_xref_type_t type) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); OBJC_EXPORT void _object_removeExternalReference(objc_xref_t xref) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); OBJC_EXPORT id _object_readExternalReference(objc_xref_t xref) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); OBJC_EXPORT uintptr_t _object_getExternalHash(id object) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); // Instance-specific instance variable layout. OBJC_EXPORT void _class_setIvarLayoutAccessor(Class cls_gen, const uint8_t* (*accessor) (id object)) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); OBJC_EXPORT const uint8_t *_object_getIvarLayout(Class cls_gen, id object) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA); OBJC_EXPORT BOOL _class_usesAutomaticRetainRelease(Class cls) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); // Obsolete ARC conversions. // hack - remove and reinstate objc.h's definitions #undef objc_retainedObject #undef objc_unretainedObject #undef objc_unretainedPointer OBJC_EXPORT id objc_retainedObject(objc_objectptr_t pointer) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT id objc_unretainedObject(objc_objectptr_t pointer) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT objc_objectptr_t objc_unretainedPointer(id object) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); #if __has_feature(objc_arc) # define objc_retainedObject(o) ((__bridge_transfer id)(objc_objectptr_t)(o)) # define objc_unretainedObject(o) ((__bridge id)(objc_objectptr_t)(o)) # define objc_unretainedPointer(o) ((__bridge objc_objectptr_t)(id)(o)) #else # define objc_retainedObject(o) ((id)(objc_objectptr_t)(o)) # define objc_unretainedObject(o) ((id)(objc_objectptr_t)(o)) # define objc_unretainedPointer(o) ((objc_objectptr_t)(id)(o)) #endif // API to only be called by root classes like NSObject or NSProxy OBJC_EXPORT id _objc_rootRetain(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT void _objc_rootRelease(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT bool _objc_rootReleaseWasZero(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT bool _objc_rootTryRetain(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT bool _objc_rootIsDeallocating(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT id _objc_rootAutorelease(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT uintptr_t _objc_rootRetainCount(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT id _objc_rootInit(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT id _objc_rootAllocWithZone(Class cls, malloc_zone_t *zone) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT id _objc_rootAlloc(Class cls) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT void _objc_rootDealloc(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT void _objc_rootFinalize(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT malloc_zone_t * _objc_rootZone(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT uintptr_t _objc_rootHash(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT void * objc_autoreleasePoolPush(void) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT void objc_autoreleasePoolPop(void *context) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT id objc_retain(id obj) __asm__("_objc_retain") __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT void objc_release(id obj) __asm__("_objc_release") __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT id objc_autorelease(id obj) __asm__("_objc_autorelease") __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); // wraps objc_autorelease(obj) in a useful way when used with return values OBJC_EXPORT id objc_autoreleaseReturnValue(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); // wraps objc_autorelease(objc_retain(obj)) in a useful way when used with return values OBJC_EXPORT id objc_retainAutoreleaseReturnValue(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); // called ONLY by ARR by callers to undo the autorelease (if possible), otherwise objc_retain OBJC_EXPORT id objc_retainAutoreleasedReturnValue(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT void objc_storeStrong(id *location, id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT id objc_retainAutorelease(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); // obsolete. OBJC_EXPORT id objc_retain_autorelease(id obj) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT id objc_loadWeakRetained(id *location) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT id objc_initWeak(id *addr, id val) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT void objc_destroyWeak(id *addr) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT void objc_copyWeak(id *to, id *from) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT void objc_moveWeak(id *to, id *from) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT void _objc_autoreleasePoolPrint(void) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT BOOL objc_should_deallocate(id object) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT void objc_clear_deallocating(id object) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); // to make CF link for now OBJC_EXPORT void * _objc_autoreleasePoolPush(void) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); OBJC_EXPORT void _objc_autoreleasePoolPop(void *context) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); // Extra @encode data for XPC, or NULL OBJC_EXPORT const char *_protocol_getMethodTypeEncoding(Protocol *p, SEL sel, BOOL isRequiredMethod, BOOL isInstanceMethod) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0); // API to only be called by classes that provide their own reference count storage OBJC_EXPORT void _objc_deallocOnMainThreadHelper(void *context) __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0); // On async versus sync deallocation and the _dealloc2main flag // // Theory: // // If order matters, then code must always: [self dealloc]. // If order doesn't matter, then always async should be safe. // // Practice: // // The _dealloc2main bit is set for GUI objects that may be retained by other // threads. Once deallocation begins on the main thread, doing more async // deallocation will at best cause extra UI latency and at worst cause // use-after-free bugs in unretained delegate style patterns. Yes, this is // extremely fragile. Yes, in the long run, developers should switch to weak // references. // // Note is NOT safe to do any equality check against the result of // dispatch_get_current_queue(). The main thread can and does drain more than // one dispatch queue. That is why we call pthread_main_np(). // typedef enum { _OBJC_RESURRECT_OBJECT = -1, /* _logicBlock has called -retain, and scheduled a -release for later. */ _OBJC_DEALLOC_OBJECT_NOW = 1, /* call [self dealloc] immediately. */ _OBJC_DEALLOC_OBJECT_LATER = 2 /* call [self dealloc] on the main queue. */ } _objc_object_disposition_t; #define _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC_BLOCK(_rc_ivar, _logicBlock) \ -(id)retain { \ /* this will fail to compile if _rc_ivar is an unsigned type */ \ int _retain_count_ivar_must_not_be_unsigned[0L - (__typeof__(_rc_ivar))-1] __attribute__((unused)); \ __typeof__(_rc_ivar) _prev = __sync_fetch_and_add(&_rc_ivar, 2); \ if (_prev < -2) { /* specifically allow resurrection from logical 0. */ \ __builtin_trap(); /* BUG: retain of over-released ref */ \ } \ return self; \ } \ -(oneway void)release { \ __typeof__(_rc_ivar) _prev = __sync_fetch_and_sub(&_rc_ivar, 2); \ if (_prev > 0) { \ return; \ } else if (_prev < 0) { \ __builtin_trap(); /* BUG: over-release */ \ } \ _objc_object_disposition_t fate = _logicBlock(self); \ if (fate == _OBJC_RESURRECT_OBJECT) { \ return; \ } \ /* mark the object as deallocating. */ \ if (!__sync_bool_compare_and_swap(&_rc_ivar, -2, 1)) { \ __builtin_trap(); /* BUG: dangling ref did a retain */ \ } \ if (fate == _OBJC_DEALLOC_OBJECT_NOW) { \ [self dealloc]; \ } else if (fate == _OBJC_DEALLOC_OBJECT_LATER) { \ dispatch_barrier_async_f(dispatch_get_main_queue(), self, \ _objc_deallocOnMainThreadHelper); \ } else { \ __builtin_trap(); /* BUG: bogus fate value */ \ } \ } \ -(NSUInteger)retainCount { \ return (_rc_ivar + 2) >> 1; \ } \ -(BOOL)_tryRetain { \ __typeof__(_rc_ivar) _prev; \ do { \ _prev = _rc_ivar; \ if (_prev & 1) { \ return 0; \ } else if (_prev == -2) { \ return 0; \ } else if (_prev < -2) { \ __builtin_trap(); /* BUG: over-release elsewhere */ \ } \ } while ( ! __sync_bool_compare_and_swap(&_rc_ivar, _prev, _prev + 2)); \ return 1; \ } \ -(BOOL)_isDeallocating { \ if (_rc_ivar == -2) { \ return 1; \ } else if (_rc_ivar < -2) { \ __builtin_trap(); /* BUG: over-release elsewhere */ \ } \ return _rc_ivar & 1; \ } #define _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, _dealloc2main) \ _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC_BLOCK(_rc_ivar, (^(id _self_ __attribute__((unused))) { \ if (_dealloc2main && !pthread_main_np()) { \ return _OBJC_DEALLOC_OBJECT_LATER; \ } else { \ return _OBJC_DEALLOC_OBJECT_NOW; \ } \ })) #define _OBJC_SUPPORTED_INLINE_REFCNT(_rc_ivar) _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, 0) #define _OBJC_SUPPORTED_INLINE_REFCNT_WITH_DEALLOC2MAIN(_rc_ivar) _OBJC_SUPPORTED_INLINE_REFCNT_LOGIC(_rc_ivar, 1) __END_DECLS #endif