2 * Copyright (c) 2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 Copyright (c) 1999-2012, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
29 #define ENABLE_ZOMBIES 1
31 #include <CoreFoundation/CFRuntime.h>
32 #include "CFInternal.h"
33 #include "CFBasicHash.h"
37 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
39 #include <mach-o/dyld.h>
40 #include <mach/mach.h>
41 #include <crt_externs.h>
44 #include <CoreFoundation/CFStringDefaultEncoding.h>
46 #if DEPLOYMENT_TARGET_EMBEDDED
47 // This isn't in the embedded runtime.h header
48 OBJC_EXPORT
void *objc_destructInstance(id obj
);
53 #if DEPLOYMENT_TARGET_WINDOWS
58 // retain/release recording constants -- must match values
59 // used by OA for now; probably will change in the future
60 __kCFRetainEvent
= 28,
61 __kCFReleaseEvent
= 29
64 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
67 #include <malloc/malloc.h>
70 #define FAKE_INSTRUMENTS 0
72 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
73 __private_extern__
void __CFOAInitializeNSObject(void); // from NSObject.m
75 bool __CFOASafe
= false;
77 void (*__CFObjectAllocRecordAllocationFunction
)(int, void *, int64_t , uint64_t, const char *) = NULL
;
78 void (*__CFObjectAllocSetLastAllocEventNameFunction
)(void *, const char *) = NULL
;
80 void __CFOAInitialize(void) {
83 void __CFRecordAllocationEvent(int eventnum
, void *ptr
, int64_t size
, uint64_t data
, const char *classname
) {
84 if (!__CFOASafe
|| !__CFObjectAllocRecordAllocationFunction
) return;
85 __CFObjectAllocRecordAllocationFunction(eventnum
, ptr
, size
, data
, classname
);
88 void __CFSetLastAllocationEventName(void *ptr
, const char *classname
) {
89 if (!__CFOASafe
|| !__CFObjectAllocSetLastAllocEventNameFunction
) return;
90 __CFObjectAllocSetLastAllocEventNameFunction(ptr
, classname
);
93 #elif FAKE_INSTRUMENTS
95 CF_EXPORT
bool __CFOASafe
= true;
97 void __CFOAInitialize(void) { }
99 void __CFRecordAllocationEvent(int eventnum
, void *ptr
, int64_t size
, uint64_t data
, const char *classname
) {
100 if (!__CFOASafe
) return;
101 if (!classname
) classname
= "(no class)";
102 const char *event
= "unknown event";
108 case __kCFReleaseEvent
:
112 case __kCFRetainEvent
:
116 fprintf(stdout
, "event,%d,%s,%p,%ld,%lu,%s\n", eventnum
, event
, ptr
, (long)size
, (unsigned long)data
, classname
);
119 void __CFSetLastAllocationEventName(void *ptr
, const char *classname
) {
120 if (!__CFOASafe
) return;
121 if (!classname
) classname
= "(no class)";
122 fprintf(stdout
, "name,%p,%s\n", ptr
, classname
? classname
: "(no class)");
127 bool __CFOASafe
= false;
129 void __CFOAInitialize(void) { }
130 void __CFRecordAllocationEvent(int eventnum
, void *ptr
, int64_t size
, uint64_t data
, const char *classname
) { }
131 void __CFSetLastAllocationEventName(void *ptr
, const char *classname
) { }
135 extern void __HALT(void);
137 static CFTypeID __kCFNotATypeTypeID
= _kCFRuntimeNotATypeID
;
139 #if !defined (__cplusplus)
140 static const CFRuntimeClass __CFNotATypeClass
= {
152 static CFTypeID __kCFTypeTypeID
= _kCFRuntimeNotATypeID
;
154 static const CFRuntimeClass __CFTypeClass
= {
166 void SIG1(CFTypeRef
){__HALT();};;
167 CFTypeRef
SIG2(CFAllocatorRef
,CFTypeRef
){__HALT();return NULL
;};
168 Boolean
SIG3(CFTypeRef
,CFTypeRef
){__HALT();return FALSE
;};
169 CFHashCode
SIG4(CFTypeRef
){__HALT(); return 0;};
170 CFStringRef
SIG5(CFTypeRef
,CFDictionaryRef
){__HALT();return NULL
;};
171 CFStringRef
SIG6(CFTypeRef
){__HALT();return NULL
;};
173 static const CFRuntimeClass __CFNotATypeClass
= {
185 static CFTypeID __kCFTypeTypeID
= _kCFRuntimeNotATypeID
;
187 static const CFRuntimeClass __CFTypeClass
= {
200 // the lock does not protect most reading of these; we just leak the old table to allow read-only accesses to continue to work
201 static CFSpinLock_t __CFBigRuntimeFunnel
= CFSpinLockInit
;
202 __private_extern__ CFRuntimeClass
* __CFRuntimeClassTable
[__CFRuntimeClassTableSize
] = {0};
203 __private_extern__
int32_t __CFRuntimeClassTableCount
= 0;
205 __private_extern__
uintptr_t __CFRuntimeObjCClassTable
[__CFRuntimeClassTableSize
] = {0};
207 #if !defined(__CFObjCIsCollectable)
208 bool (*__CFObjCIsCollectable
)(void *) = NULL
;
211 #if !__CONSTANT_CFSTRINGS__ || DEPLOYMENT_TARGET_EMBEDDED_MINI
212 // Compiler uses this symbol name; must match compiler built-in decl, so we use 'int'
214 int __CFConstantStringClassReference
[24] = {0};
216 int __CFConstantStringClassReference
[12] = {0};
221 int __CFConstantStringClassReference
[24] = {0};
223 int __CFConstantStringClassReference
[12] = {0};
226 void *__CFConstantStringClassReferencePtr
= NULL
;
228 Boolean
_CFIsObjC(CFTypeID typeID
, void *obj
) {
229 return CF_IS_OBJC(typeID
, obj
);
232 CFTypeID
_CFRuntimeRegisterClass(const CFRuntimeClass
* const cls
) {
233 // className must be pure ASCII string, non-null
234 if ((cls
->version
& _kCFRuntimeCustomRefCount
) && !cls
->refcount
) {
235 CFLog(kCFLogLevelWarning
, CFSTR("*** _CFRuntimeRegisterClass() given inconsistent class '%s'. Program will crash soon."), cls
->className
);
236 return _kCFRuntimeNotATypeID
;
238 __CFSpinLock(&__CFBigRuntimeFunnel
);
239 if (__CFMaxRuntimeTypes
<= __CFRuntimeClassTableCount
) {
240 CFLog(kCFLogLevelWarning
, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls
->className
);
241 __CFSpinUnlock(&__CFBigRuntimeFunnel
);
242 return _kCFRuntimeNotATypeID
;
244 if (__CFRuntimeClassTableSize
<= __CFRuntimeClassTableCount
) {
245 CFLog(kCFLogLevelWarning
, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls
->className
);
246 __CFSpinUnlock(&__CFBigRuntimeFunnel
);
247 return _kCFRuntimeNotATypeID
;
249 __CFRuntimeClassTable
[__CFRuntimeClassTableCount
++] = (CFRuntimeClass
*)cls
;
250 CFTypeID typeID
= __CFRuntimeClassTableCount
- 1;
251 __CFSpinUnlock(&__CFBigRuntimeFunnel
);
256 const CFRuntimeClass
* _CFRuntimeGetClassWithTypeID(CFTypeID typeID
) {
257 return __CFRuntimeClassTable
[typeID
]; // hopelessly unthreadsafe
260 void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID
) {
261 __CFSpinLock(&__CFBigRuntimeFunnel
);
262 __CFRuntimeClassTable
[typeID
] = NULL
;
263 __CFSpinUnlock(&__CFBigRuntimeFunnel
);
267 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
269 __private_extern__
uint8_t __CFZombieEnabled
= 0;
270 __private_extern__
uint8_t __CFDeallocateZombies
= 0;
272 extern void __CFZombifyNSObject(void); // from NSObject.m
274 void _CFEnableZombies(void) {
279 // XXX_PCB: use the class version field as a bitmask, to allow classes to opt-in for GC scanning.
281 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
282 CF_INLINE CFOptionFlags
CF_GET_COLLECTABLE_MEMORY_TYPE(const CFRuntimeClass
*cls
)
284 return ((cls
->version
& _kCFRuntimeScannedObject
) ? __kCFAllocatorGCScannedMemory
: 0) | __kCFAllocatorGCObjectMemory
;
287 #define CF_GET_COLLECTABLE_MEMORY_TYPE(x) (0)
290 CFTypeRef
_CFRuntimeCreateInstance(CFAllocatorRef allocator
, CFTypeID typeID
, CFIndex extraBytes
, unsigned char *category
) {
291 if (__CFRuntimeClassTableSize
<= typeID
) HALT
;
292 CFAssert1(typeID
!= _kCFRuntimeNotATypeID
, __kCFLogAssertion
, "%s(): Uninitialized type id", __PRETTY_FUNCTION__
);
293 CFRuntimeClass
*cls
= __CFRuntimeClassTable
[typeID
];
297 Boolean customRC
= !!(cls
->version
& _kCFRuntimeCustomRefCount
);
298 if (customRC
&& !cls
->refcount
) {
299 CFLog(kCFLogLevelWarning
, CFSTR("*** _CFRuntimeCreateInstance() found inconsistent class '%s'."), cls
->className
);
302 if (customRC
&& kCFUseCollectableAllocator
&& (kCFAllocatorSystemDefaultGCRefZero
== allocator
|| kCFAllocatorDefaultGCRefZero
== allocator
)) {
303 CFLog(kCFLogLevelWarning
, CFSTR("*** _CFRuntimeCreateInstance(): special zero-ref allocators cannot be used with class '%s' with custom ref counting."), cls
->className
);
306 CFAllocatorRef realAllocator
= _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator
);
307 if (kCFAllocatorNull
== realAllocator
) {
310 Boolean usesSystemDefaultAllocator
= _CFAllocatorIsSystemDefault(realAllocator
);
311 CFIndex size
= sizeof(CFRuntimeBase
) + extraBytes
+ (usesSystemDefaultAllocator
? 0 : sizeof(CFAllocatorRef
));
312 size
= (size
+ 0xF) & ~0xF; // CF objects are multiples of 16 in size
313 // CFType version 0 objects are unscanned by default since they don't have write-barriers and hard retain their innards
314 // CFType version 1 objects are scanned and use hand coded write-barriers to store collectable storage within
315 CFRuntimeBase
*memory
= (CFRuntimeBase
*)CFAllocatorAllocate(allocator
, size
, CF_GET_COLLECTABLE_MEMORY_TYPE(cls
));
316 if (NULL
== memory
) {
319 if (!kCFUseCollectableAllocator
|| !CF_IS_COLLECTABLE_ALLOCATOR(allocator
) || !(CF_GET_COLLECTABLE_MEMORY_TYPE(cls
) & __kCFAllocatorGCScannedMemory
)) {
320 memset(memory
, 0, size
);
322 if (__CFOASafe
&& category
) {
323 __CFSetLastAllocationEventName(memory
, (char *)category
);
324 } else if (__CFOASafe
) {
325 __CFSetLastAllocationEventName(memory
, (char *)cls
->className
);
327 if (!usesSystemDefaultAllocator
) {
328 // add space to hold allocator ref for non-standard allocators.
329 // (this screws up 8 byte alignment but seems to work)
330 *(CFAllocatorRef
*)((char *)memory
) = (CFAllocatorRef
)CFRetain(realAllocator
);
331 memory
= (CFRuntimeBase
*)((char *)memory
+ sizeof(CFAllocatorRef
));
333 memory
->_cfisa
= __CFISAForTypeID(typeID
);
336 if (!kCFUseCollectableAllocator
|| (kCFAllocatorSystemDefaultGCRefZero
!= allocator
&& kCFAllocatorDefaultGCRefZero
!= allocator
)) {
340 memory
->_rc
= 0xFFFFFFFFU
;
344 if (!kCFUseCollectableAllocator
|| (kCFAllocatorSystemDefaultGCRefZero
!= allocator
&& kCFAllocatorDefaultGCRefZero
!= allocator
)) {
351 uint32_t *cfinfop
= (uint32_t *)&(memory
->_cfinfo
);
352 *cfinfop
= (uint32_t)((rc
<< 24) | (customRC
? 0x800000 : 0x0) | ((uint32_t)typeID
<< 8) | (usesSystemDefaultAllocator
? 0x80 : 0x00));
353 if (NULL
!= cls
->init
) {
359 void _CFRuntimeInitStaticInstance(void *ptr
, CFTypeID typeID
) {
360 CFAssert1(typeID
!= _kCFRuntimeNotATypeID
, __kCFLogAssertion
, "%s(): Uninitialized type id", __PRETTY_FUNCTION__
);
361 if (__CFRuntimeClassTableSize
<= typeID
) HALT
;
362 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
363 Boolean customRC
= !!(cfClass
->version
& _kCFRuntimeCustomRefCount
);
365 CFLog(kCFLogLevelError
, CFSTR("*** Cannot initialize a static instance to a class (%s) with custom ref counting"), cfClass
->className
);
368 CFRuntimeBase
*memory
= (CFRuntimeBase
*)ptr
;
369 memory
->_cfisa
= __CFISAForTypeID(typeID
);
370 uint32_t *cfinfop
= (uint32_t *)&(memory
->_cfinfo
);
371 *cfinfop
= (uint32_t)(((customRC
? 0xFF : 0) << 24) | (customRC
? 0x800000 : 0x0) | ((uint32_t)typeID
<< 8) | 0x80);
373 memory
->_rc
= customRC
? 0xFFFFFFFFU
: 0x0;
375 if (NULL
!= cfClass
->init
) {
376 (cfClass
->init
)(memory
);
380 void _CFRuntimeSetInstanceTypeID(CFTypeRef cf
, CFTypeID newTypeID
) {
381 if (__CFRuntimeClassTableSize
<= newTypeID
) HALT
;
382 uint32_t *cfinfop
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
383 CFTypeID currTypeID
= (*cfinfop
>> 8) & 0x03FF; // mask up to 0x0FFF
384 CFRuntimeClass
*newcfClass
= __CFRuntimeClassTable
[newTypeID
];
385 Boolean newCustomRC
= (newcfClass
->version
& _kCFRuntimeCustomRefCount
);
386 CFRuntimeClass
*currcfClass
= __CFRuntimeClassTable
[currTypeID
];
387 Boolean currCustomRC
= (currcfClass
->version
& _kCFRuntimeCustomRefCount
);
388 if (currCustomRC
|| (0 != currTypeID
&& newCustomRC
)) {
389 CFLog(kCFLogLevelError
, CFSTR("*** Cannot change the CFTypeID of a %s to a %s due to custom ref counting"), currcfClass
->className
, newcfClass
->className
);
392 // Going from current type ID of 0 to anything is allowed, but if
393 // the object has somehow already been retained and the transition
394 // is to a class doing custom ref counting, the ref count isn't
395 // transferred and there will probably be a crash later when the
396 // object is freed too early.
397 *cfinfop
= (*cfinfop
& 0xFFF000FFU
) | ((uint32_t)newTypeID
<< 8);
402 __kCFObjectRetainedEvent
= 12,
403 __kCFObjectReleasedEvent
= 13
406 #if DEPLOYMENT_TARGET_MACOSX
407 #define NUM_EXTERN_TABLES 8
408 #define EXTERN_TABLE_IDX(O) (((uintptr_t)(O) >> 8) & 0x7)
409 #elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
410 #define NUM_EXTERN_TABLES 1
411 #define EXTERN_TABLE_IDX(O) 0
416 // we disguise pointers so that programs like 'leaks' forget about these references
417 #define DISGUISE(O) (~(uintptr_t)(O))
421 CFBasicHashRef table
;
422 uint8_t padding
[64 - sizeof(CFBasicHashRef
) - sizeof(CFSpinLock_t
)];
423 } __NSRetainCounters
[NUM_EXTERN_TABLES
];
425 CF_EXPORT
uintptr_t __CFDoExternRefOperation(uintptr_t op
, id obj
) {
426 if (nil
== obj
) HALT
;
427 uintptr_t idx
= EXTERN_TABLE_IDX(obj
);
428 uintptr_t disguised
= DISGUISE(obj
);
429 CFSpinLock_t
*lock
= &__NSRetainCounters
[idx
].lock
;
430 CFBasicHashRef table
= __NSRetainCounters
[idx
].table
;
433 case 300: // increment
434 case 350: // increment, no event
436 CFBasicHashAddValue(table
, disguised
, disguised
);
437 __CFSpinUnlock(lock
);
438 if (__CFOASafe
&& op
!= 350) __CFRecordAllocationEvent(__kCFObjectRetainedEvent
, obj
, 0, 0, NULL
);
439 return (uintptr_t)obj
;
440 case 400: // decrement
441 if (__CFOASafe
) __CFRecordAllocationEvent(__kCFObjectReleasedEvent
, obj
, 0, 0, NULL
);
442 case 450: // decrement, no event
444 count
= (uintptr_t)CFBasicHashRemoveValue(table
, disguised
);
445 __CFSpinUnlock(lock
);
449 count
= (uintptr_t)CFBasicHashGetCountOfKey(table
, disguised
);
450 __CFSpinUnlock(lock
);
456 static void __CFExternRefNullFreeCallbacks(CFConstBasicHashRef ht
, CFAllocatorRef allocator
, CFBasicHashCallbacks
*cb
) {
459 static uintptr_t __CFExternRefNullRetainValue(CFConstBasicHashRef ht
, uintptr_t stack_value
) {
463 static uintptr_t __CFExternRefNullRetainKey(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
467 static void __CFExternRefNullReleaseValue(CFConstBasicHashRef ht
, uintptr_t stack_value
) {
470 static void __CFExternRefNullReleaseKey(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
473 static Boolean
__CFExternRefNullEquateValues(CFConstBasicHashRef ht
, uintptr_t coll_value1
, uintptr_t stack_value2
) {
474 return coll_value1
== stack_value2
;
477 static Boolean
__CFExternRefNullEquateKeys(CFConstBasicHashRef ht
, uintptr_t coll_key1
, uintptr_t stack_key2
) {
478 return coll_key1
== stack_key2
;
481 static uintptr_t __CFExternRefNullHashKey(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
485 static uintptr_t __CFExternRefNullGetIndirectKey(CFConstBasicHashRef ht
, uintptr_t coll_value
) {
489 static CFStringRef
__CFExternRefNullCopyValueDescription(CFConstBasicHashRef ht
, uintptr_t stack_value
) {
490 return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%p>"), (void *)stack_value
);
493 static CFStringRef
__CFExternRefNullCopyKeyDescription(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
494 return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%p>"), (void *)stack_key
);
497 static CFBasicHashCallbacks
*__CFExternRefNullCopyCallbacks(CFConstBasicHashRef ht
, CFAllocatorRef allocator
, CFBasicHashCallbacks
*cb
);
499 static const CFBasicHashCallbacks CFExternRefCallbacks
= {
500 __CFExternRefNullCopyCallbacks
,
501 __CFExternRefNullFreeCallbacks
,
502 __CFExternRefNullRetainValue
,
503 __CFExternRefNullRetainKey
,
504 __CFExternRefNullReleaseValue
,
505 __CFExternRefNullReleaseKey
,
506 __CFExternRefNullEquateValues
,
507 __CFExternRefNullEquateKeys
,
508 __CFExternRefNullHashKey
,
509 __CFExternRefNullGetIndirectKey
,
510 __CFExternRefNullCopyValueDescription
,
511 __CFExternRefNullCopyKeyDescription
514 static CFBasicHashCallbacks
*__CFExternRefNullCopyCallbacks(CFConstBasicHashRef ht
, CFAllocatorRef allocator
, CFBasicHashCallbacks
*cb
) {
515 return (CFBasicHashCallbacks
*)&CFExternRefCallbacks
;
518 CF_EXPORT CFTypeID
CFNumberGetTypeID(void);
520 CF_INLINE CFTypeID
__CFGenericTypeID_inline(const void *cf
) {
521 // yes, 10 bits masked off, though 12 bits are there for the type field; __CFRuntimeClassTableSize is 1024
522 uint32_t *cfinfop
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
523 CFTypeID typeID
= (*cfinfop
>> 8) & 0x03FF; // mask up to 0x0FFF
527 CFTypeID
__CFGenericTypeID(const void *cf
) {
528 return __CFGenericTypeID_inline(cf
);
531 CFTypeID
CFTypeGetTypeID(void) {
532 return __kCFTypeTypeID
;
535 __private_extern__
void __CFGenericValidateType_(CFTypeRef cf
, CFTypeID type
, const char *func
) {
536 if (cf
&& CF_IS_OBJC(type
, cf
)) return;
537 CFAssert2((cf
!= NULL
) && (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]) && (__kCFNotATypeTypeID
!= __CFGenericTypeID_inline(cf
)) && (__kCFTypeTypeID
!= __CFGenericTypeID_inline(cf
)), __kCFLogAssertion
, "%s(): pointer %p is not a CF object", func
, cf
); \
538 CFAssert3(__CFGenericTypeID_inline(cf
) == type
, __kCFLogAssertion
, "%s(): pointer %p is not a %s", func
, cf
, __CFRuntimeClassTable
[type
]->className
); \
541 #define __CFGenericAssertIsCF(cf) \
542 CFAssert2(cf != NULL && (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]) && (__kCFNotATypeTypeID != __CFGenericTypeID_inline(cf)) && (__kCFTypeTypeID != __CFGenericTypeID_inline(cf)), __kCFLogAssertion, "%s(): pointer %p is not a CF object", __PRETTY_FUNCTION__, cf);
545 #define CFTYPE_IS_OBJC(obj) (false)
546 #define CFTYPE_OBJC_FUNCDISPATCH0(rettype, obj, sel) do {} while (0)
547 #define CFTYPE_OBJC_FUNCDISPATCH1(rettype, obj, sel, a1) do {} while (0)
550 CFTypeID
CFGetTypeID(CFTypeRef cf
) {
552 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFGetTypeID() called with NULL ***"); HALT
; }
554 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeID
, cf
, _cfTypeID
);
555 __CFGenericAssertIsCF(cf
);
556 return __CFGenericTypeID_inline(cf
);
559 CFStringRef
CFCopyTypeIDDescription(CFTypeID type
) {
560 CFAssert2((NULL
!= __CFRuntimeClassTable
[type
]) && __kCFNotATypeTypeID
!= type
&& __kCFTypeTypeID
!= type
, __kCFLogAssertion
, "%s(): type %d is not a CF type ID", __PRETTY_FUNCTION__
, type
);
561 return CFStringCreateWithCString(kCFAllocatorSystemDefault
, __CFRuntimeClassTable
[type
]->className
, kCFStringEncodingASCII
);
564 // Bit 31 (highest bit) in second word of cf instance indicates external ref count
566 static CFTypeRef
_CFRetain(CFTypeRef cf
, Boolean tryR
);
568 CFTypeRef
CFRetain(CFTypeRef cf
) {
569 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFRetain() called with NULL ***"); HALT
; }
570 if (cf
) __CFGenericAssertIsCF(cf
);
571 return _CFRetain(cf
, false);
574 static void _CFRelease(CFTypeRef cf
);
576 void CFRelease(CFTypeRef cf
) {
577 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFRelease() called with NULL ***"); HALT
; }
579 void **addrs
[2] = {&&start
, &&end
};
581 if (addrs
[0] <= __builtin_return_address(0) && __builtin_return_address(0) <= addrs
[1]) {
582 CFLog(3, CFSTR("*** WARNING: Recursion in CFRelease(%p) : %p '%s' : 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx"), cf
, object_getClass(cf
), object_getClassName(cf
), ((uintptr_t *)cf
)[0], ((uintptr_t *)cf
)[1], ((uintptr_t *)cf
)[2], ((uintptr_t *)cf
)[3], ((uintptr_t *)cf
)[4], ((uintptr_t *)cf
)[5]);
586 if (cf
) __CFGenericAssertIsCF(cf
);
594 __private_extern__
void __CFAllocatorDeallocate(CFTypeRef cf
);
596 __private_extern__
const void *__CFStringCollectionCopy(CFAllocatorRef allocator
, const void *ptr
) {
597 if (NULL
== ptr
) { CRSetCrashLogMessage("*** __CFStringCollectionCopy() called with NULL ***"); HALT
; }
598 CFStringRef theString
= (CFStringRef
)ptr
;
599 CFStringRef result
= CFStringCreateCopy(_CFConvertAllocatorToGCRefZeroEquivalent(allocator
), theString
);
600 return (const void *)result
;
603 extern void CFCollection_non_gc_storage_error(void);
605 __private_extern__
const void *__CFTypeCollectionRetain(CFAllocatorRef allocator
, const void *ptr
) {
606 if (NULL
== ptr
) { CRSetCrashLogMessage("*** __CFTypeCollectionRetain() called with NULL; likely a collection has been corrupted ***"); HALT
; }
607 CFTypeRef cf
= (CFTypeRef
)ptr
;
608 // only collections allocated in the GC zone can opt-out of reference counting.
609 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
610 if (CFTYPE_IS_OBJC(cf
)) return cf
; // do nothing for OBJC objects.
611 if (auto_zone_is_valid_pointer(objc_collectableZone(), ptr
)) {
612 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)];
613 if (cfClass
->version
& _kCFRuntimeResourcefulObject
) {
614 // GC: If this a CF object in the GC heap that is marked resourceful, then
615 // it must be retained keep it alive in a CF collection.
619 ; // don't retain normal CF objects
622 // support constant CFTypeRef objects.
624 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
626 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
];
628 if (lowBits
== 0) return cf
;
629 // complain about non-GC objects in GC containers.
630 CFLog(kCFLogLevelWarning
, CFSTR("storing a non-GC object %p in a GC collection, break on CFCollection_non_gc_storage_error to debug."), cf
);
631 CFCollection_non_gc_storage_error();
632 // XXX should halt, except Patrick is using this somewhere.
640 __private_extern__
void __CFTypeCollectionRelease(CFAllocatorRef allocator
, const void *ptr
) {
641 if (NULL
== ptr
) { CRSetCrashLogMessage("*** __CFTypeCollectionRelease() called with NULL; likely a collection has been corrupted ***"); HALT
; }
642 CFTypeRef cf
= (CFTypeRef
)ptr
;
643 // only collections allocated in the GC zone can opt-out of reference counting.
644 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
645 if (CFTYPE_IS_OBJC(cf
)) return; // do nothing for OBJC objects.
646 if (auto_zone_is_valid_pointer(objc_collectableZone(), cf
)) {
647 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
648 // GC: If this a CF object in the GC heap that is marked uncollectable, then
649 // must balance the retain done in __CFTypeCollectionRetain().
650 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)];
651 if (cfClass
->version
& _kCFRuntimeResourcefulObject
) {
652 // reclaim is called by _CFRelease(), which must be called to keep the
653 // CF and GC retain counts in sync.
656 // avoid releasing normal CF objects. Like other collections, for example
661 // support constant CFTypeRef objects.
663 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
665 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
];
667 if (lowBits
== 0) return;
674 static CFSpinLock_t __CFRuntimeExternRefCountTableLock
= CFSpinLockInit
;
677 static uint64_t __CFGetFullRetainCount(CFTypeRef cf
) {
678 if (NULL
== cf
) { CRSetCrashLogMessage("*** __CFGetFullRetainCount() called with NULL ***"); HALT
; }
680 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
682 return (uint64_t)0x0fffffffffffffffULL
;
686 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
];
688 return (uint64_t)0x0fffffffffffffffULL
;
690 uint64_t highBits
= 0;
691 if ((lowBits
& 0x80) != 0) {
692 highBits
= __CFDoExternRefOperation(500, (id
)cf
);
694 uint64_t compositeRC
= (lowBits
& 0x7f) + (highBits
<< 6);
699 CFIndex
CFGetRetainCount(CFTypeRef cf
) {
700 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFGetRetainCount() called with NULL ***"); HALT
; }
701 uint32_t cfinfo
= *(uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
702 if (cfinfo
& 0x800000) { // custom ref counting for object
703 CFTypeID typeID
= (cfinfo
>> 8) & 0x03FF; // mask up to 0x0FFF
704 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
705 uint32_t (*refcount
)(intptr_t, CFTypeRef
) = cfClass
->refcount
;
706 if (!refcount
|| !(cfClass
->version
& _kCFRuntimeCustomRefCount
) || (((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
] != 0xFF)) {
707 HALT
; // bogus object
710 if (((CFRuntimeBase
*)cf
)->_rc
!= 0xFFFFFFFFU
) {
711 HALT
; // bogus object
714 uint32_t rc
= refcount(0, cf
);
718 return (rc
< LONG_MAX
) ? (CFIndex
)rc
: (CFIndex
)LONG_MAX
;
721 uint64_t rc
= __CFGetFullRetainCount(cf
);
722 return (rc
< (uint64_t)LONG_MAX
) ? (CFIndex
)rc
: (CFIndex
)LONG_MAX
;
725 CFTypeRef
CFMakeCollectable(CFTypeRef cf
) {
726 if (NULL
== cf
) return NULL
;
730 CFTypeRef
CFMakeUncollectable(CFTypeRef cf
) {
731 if (NULL
== cf
) return NULL
;
732 if (CF_IS_COLLECTABLE(cf
)) {
738 Boolean
CFEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
739 if (NULL
== cf1
) { CRSetCrashLogMessage("*** CFEqual() called with NULL first argument ***"); HALT
; }
740 if (NULL
== cf2
) { CRSetCrashLogMessage("*** CFEqual() called with NULL second argument ***"); HALT
; }
741 if (cf1
== cf2
) return true;
742 CFTYPE_OBJC_FUNCDISPATCH1(Boolean
, cf1
, isEqual
:, cf2
);
743 CFTYPE_OBJC_FUNCDISPATCH1(Boolean
, cf2
, isEqual
:, cf1
);
744 __CFGenericAssertIsCF(cf1
);
745 __CFGenericAssertIsCF(cf2
);
746 if (__CFGenericTypeID_inline(cf1
) != __CFGenericTypeID_inline(cf2
)) return false;
747 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf1
)]->equal
) {
748 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf1
)]->equal(cf1
, cf2
);
753 CFHashCode
CFHash(CFTypeRef cf
) {
754 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFHash() called with NULL ***"); HALT
; }
755 CFTYPE_OBJC_FUNCDISPATCH0(CFHashCode
, cf
, hash
);
756 __CFGenericAssertIsCF(cf
);
757 CFHashCode (*hash
)(CFTypeRef cf
) = __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->hash
;
761 if (CF_IS_COLLECTABLE(cf
)) return (CFHashCode
)_object_getExternalHash((id
)cf
);
762 return (CFHashCode
)cf
;
765 // definition: produces a normally non-NULL debugging description of the object
766 CFStringRef
CFCopyDescription(CFTypeRef cf
) {
767 if (NULL
== cf
) return NULL
;
768 // CFTYPE_OBJC_FUNCDISPATCH0(CFStringRef, cf, _copyDescription); // XXX returns 0 refcounted item under GC
769 __CFGenericAssertIsCF(cf
);
770 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyDebugDesc
) {
771 CFStringRef result
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyDebugDesc(cf
);
772 if (NULL
!= result
) return result
;
774 return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%s %p [%p]>"), __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->className
, cf
, CFGetAllocator(cf
));
777 // Definition: if type produces a formatting description, return that string, otherwise NULL
778 __private_extern__ CFStringRef
__CFCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
779 if (NULL
== cf
) return NULL
;
780 __CFGenericAssertIsCF(cf
);
781 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyFormattingDesc
) {
782 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyFormattingDesc(cf
, formatOptions
);
787 extern CFAllocatorRef
__CFAllocatorGetAllocator(CFTypeRef
);
789 CFAllocatorRef
CFGetAllocator(CFTypeRef cf
) {
790 if (NULL
== cf
) return kCFAllocatorSystemDefault
;
791 if (__kCFAllocatorTypeID_CONST
== __CFGenericTypeID_inline(cf
)) {
792 return __CFAllocatorGetAllocator(cf
);
794 return __CFGetAllocator(cf
);
797 extern void __CFNullInitialize(void);
798 extern void __CFAllocatorInitialize(void);
799 extern void __CFStringInitialize(void);
800 extern void __CFArrayInitialize(void);
801 extern void __CFBooleanInitialize(void);
802 extern void __CFCharacterSetInitialize(void);
803 extern void __CFDataInitialize(void);
804 extern void __CFNumberInitialize(void);
805 extern void __CFStorageInitialize(void);
806 extern void __CFErrorInitialize(void);
807 extern void __CFTreeInitialize(void);
808 extern void __CFURLInitialize(void);
809 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
810 extern void __CFMachPortInitialize(void);
812 extern void __CFMessagePortInitialize(void);
813 extern void __CFRunLoopInitialize(void);
814 extern void __CFRunLoopObserverInitialize(void);
815 extern void __CFRunLoopSourceInitialize(void);
816 extern void __CFRunLoopTimerInitialize(void);
817 extern void __CFPFactoryInitialize(void);
818 extern void __CFBundleInitialize(void);
819 extern void __CFPlugInInitialize(void);
820 extern void __CFPlugInInstanceInitialize(void);
821 extern void __CFUUIDInitialize(void);
822 extern void __CFBinaryHeapInitialize(void);
823 extern void __CFBitVectorInitialize(void);
824 #if DEPLOYMENT_TARGET_LINUX
825 __private_extern__
void __CFTSDLinuxInitialize();
827 #if DEPLOYMENT_TARGET_WINDOWS
829 __private_extern__
void __CFTSDWindowsInitialize(void);
830 __private_extern__
void __CFTSDWindowsCleanup(void);
831 __private_extern__
void __CFFinalizeWindowsThreadData();
833 extern void __CFStreamInitialize(void);
834 extern void __CFCalendarInitialize();
835 extern void __CFTimeZoneInitialize();
836 #if DEPLOYMENT_TARGET_LINUX
837 extern void __CFCalendarInitialize();
838 extern void __CFTimeZoneInitialize();
840 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
841 extern void __CFXPreferencesInitialize(void);
844 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
845 __private_extern__
uint8_t __CF120290
= false;
846 __private_extern__
uint8_t __CF120291
= false;
847 __private_extern__
uint8_t __CF120293
= false;
848 __private_extern__
char * __crashreporter_info__
= NULL
; // Keep this symbol, since it was exported and other things may be linking against it, like GraphicsServices.framework on iOS
849 asm(".desc ___crashreporter_info__, 0x10");
851 static void __01121__(void) {
852 __CF120291
= pthread_is_threaded_np() ? true : false;
855 static void __01123__(void) {
856 // Ideally, child-side atfork handlers should be async-cancel-safe, as fork()
857 // is async-cancel-safe and can be called from signal handlers. See also
858 // http://standards.ieee.org/reading/ieee/interp/1003-1c-95_int/pasc-1003.1c-37.html
859 // This is not a problem for CF.
862 #if DEPLOYMENT_TARGET_MACOSX
864 CRSetCrashLogMessage2("*** multi-threaded process forked ***");
866 CRSetCrashLogMessage2("*** single-threaded process forked ***");
872 #define EXEC_WARNING_STRING_1 "The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec().\n"
873 #define EXEC_WARNING_STRING_2 "Break on __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__() to debug.\n"
875 __private_extern__
void __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__(void) {
876 write(2, EXEC_WARNING_STRING_1
, sizeof(EXEC_WARNING_STRING_1
) - 1);
877 write(2, EXEC_WARNING_STRING_2
, sizeof(EXEC_WARNING_STRING_2
) - 1);
883 CF_EXPORT
const void *__CFArgStuff
;
884 const void *__CFArgStuff
= NULL
;
885 __private_extern__
void *__CFAppleLanguages
= NULL
;
887 // do not cache CFFIXED_USER_HOME or HOME, there are situations where they can change
901 {"DYLD_IMAGE_SUFFIX", NULL
},
902 {"CFProcessPath", NULL
},
903 {"CFNETWORK_LIBRARY_PATH", NULL
},
904 {"CFUUIDVersionNumber", NULL
},
905 {"CFDebugNamedDataSharing", NULL
},
906 {"CFPropertyListAllowImmutableCollections", NULL
},
907 {"CFBundleUseDYLD", NULL
},
908 {"CFBundleDisableStringsSharing", NULL
},
909 {"CFCharacterSetCheckForExpandedSet", NULL
},
910 {"__CF_DEBUG_EXPANDED_SET", NULL
},
911 {"CFStringDisableROM", NULL
},
912 {"CF_CHARSET_PATH", NULL
},
913 {"__CF_USER_TEXT_ENCODING", NULL
},
914 {"__CFPREFERENCES_AUTOSYNC_INTERVAL", NULL
},
915 {"__CFPREFERENCES_LOG_FAILURES", NULL
},
916 {"CFNumberDisableCache", NULL
},
917 {"__CFPREFERENCES_AVOID_DAEMON", NULL
},
918 {NULL
, NULL
}, // the last one is for optional "COMMAND_MODE" "legacy", do not use this slot, insert before
921 __private_extern__
const char *__CFgetenv(const char *n
) {
922 for (CFIndex idx
= 0; idx
< sizeof(__CFEnv
) / sizeof(__CFEnv
[0]); idx
++) {
923 if (__CFEnv
[idx
].name
&& 0 == strcmp(n
, __CFEnv
[idx
].name
)) return __CFEnv
[idx
].value
;
928 #if DEPLOYMENT_TARGET_WINDOWS
929 #define kNilPthreadT { nil, nil }
931 #define kNilPthreadT (pthread_t)0
935 CF_EXPORT pthread_t _CFMainPThread
;
936 pthread_t _CFMainPThread
= kNilPthreadT
;
938 #undef kCFUseCollectableAllocator
939 CF_EXPORT
bool kCFUseCollectableAllocator
;
940 bool kCFUseCollectableAllocator
= false;
942 __private_extern__ Boolean __CFProphylacticAutofsAccess
= false;
943 __private_extern__ Boolean __CFInitializing
= 0;
944 __private_extern__ Boolean __CFInitialized
= 0;
946 #if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
947 static void __CFInitialize(void) __attribute__ ((constructor
));
950 #if DEPLOYMENT_TARGET_WINDOWS
953 void __CFInitialize(void) {
955 if (!__CFInitialized
&& !__CFInitializing
) {
956 __CFInitializing
= 1;
958 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
959 if (!pthread_main_np()) HALT
; // CoreFoundation must be initialized on the main thread
962 _CFMainPThread
= pthread_self();
964 #if DEPLOYMENT_TARGET_WINDOWS
965 // Must not call any CF functions
966 __CFTSDWindowsInitialize();
967 #elif DEPLOYMENT_TARGET_LINUX
968 __CFTSDLinuxInitialize();
971 __CFProphylacticAutofsAccess
= true;
973 for (CFIndex idx
= 0; idx
< sizeof(__CFEnv
) / sizeof(__CFEnv
[0]); idx
++) {
974 __CFEnv
[idx
].value
= __CFEnv
[idx
].name
? getenv(__CFEnv
[idx
].name
) : NULL
;
977 #if !defined(kCFUseCollectableAllocator)
978 kCFUseCollectableAllocator
= objc_collectingEnabled();
980 if (kCFUseCollectableAllocator
) {
981 #if !defined(__CFObjCIsCollectable)
982 __CFObjCIsCollectable
= (bool (*)(void *))objc_isAuto
;
985 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
987 __CFStringGetUserDefaultEncoding(&s
, &r
); // force the potential setenv to occur early
988 pthread_atfork(__01121__
, NULL
, __01123__
);
992 memset(__CFRuntimeClassTable
, 0, sizeof(__CFRuntimeClassTable
));
993 memset(__CFRuntimeObjCClassTable
, 0, sizeof(__CFRuntimeObjCClassTable
));
996 /* Here so that two runtime classes get indices 0, 1. */
997 __kCFNotATypeTypeID
= _CFRuntimeRegisterClass(&__CFNotATypeClass
);
998 __kCFTypeTypeID
= _CFRuntimeRegisterClass(&__CFTypeClass
);
1000 /* Here so that __kCFAllocatorTypeID gets index 2. */
1001 __CFAllocatorInitialize();
1003 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1006 char **args
= *_NSGetArgv();
1007 cnt
= *_NSGetArgc();
1008 for (idx
= 1; idx
< cnt
- 1; idx
++) {
1009 if (NULL
== args
[idx
]) continue;
1010 if (0 == strcmp(args
[idx
], "-AppleLanguages") && args
[idx
+ 1]) {
1011 CFIndex length
= strlen(args
[idx
+ 1]);
1012 __CFAppleLanguages
= malloc(length
+ 1);
1013 memmove(__CFAppleLanguages
, args
[idx
+ 1], length
+ 1);
1021 CFBasicHashGetTypeID();
1024 for (CFIndex idx
= 0; idx
< NUM_EXTERN_TABLES
; idx
++) {
1025 __NSRetainCounters
[idx
].table
= CFBasicHashCreate(kCFAllocatorSystemDefault
, kCFBasicHashHasCounts
| kCFBasicHashLinearHashing
| kCFBasicHashAggressiveGrowth
, &CFExternRefCallbacks
);
1026 CFBasicHashSetCapacity(__NSRetainCounters
[idx
].table
, 40);
1027 __NSRetainCounters
[idx
].lock
= CFSpinLockInit
;
1030 /*** _CFRuntimeCreateInstance() can finally be called generally after this line. ***/
1032 __CFRuntimeClassTableCount
= 7;
1033 __CFStringInitialize(); // CFString's TypeID must be 0x7, now and forever
1035 __CFRuntimeClassTableCount
= 16;
1036 __CFNullInitialize(); // See above for hard-coding of this position
1037 CFSetGetTypeID(); // See above for hard-coding of this position
1038 CFDictionaryGetTypeID(); // See above for hard-coding of this position
1039 __CFArrayInitialize(); // See above for hard-coding of this position
1040 __CFDataInitialize(); // See above for hard-coding of this position
1041 __CFBooleanInitialize(); // See above for hard-coding of this position
1042 __CFNumberInitialize(); // See above for hard-coding of this position
1044 __CFBinaryHeapInitialize();
1045 __CFBitVectorInitialize();
1046 __CFCharacterSetInitialize();
1047 __CFStorageInitialize();
1048 __CFErrorInitialize();
1049 __CFTreeInitialize();
1050 __CFURLInitialize();
1052 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
1053 __CFBundleInitialize();
1054 __CFPFactoryInitialize();
1056 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1057 __CFPlugInInitialize();
1058 __CFPlugInInstanceInitialize();
1060 __CFUUIDInitialize();
1061 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
1062 __CFMessagePortInitialize();
1064 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1065 __CFMachPortInitialize();
1067 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
1068 __CFStreamInitialize();
1070 #if DEPLOYMENT_TARGET_WINDOWS
1071 __CFWindowsNamedPipeInitialize();
1073 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
1074 __CFRunLoopInitialize();
1075 __CFRunLoopObserverInitialize();
1076 __CFRunLoopSourceInitialize();
1077 __CFRunLoopTimerInitialize();
1079 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1080 __CFTimeZoneInitialize();
1081 __CFCalendarInitialize();
1082 #if DEPLOYMENT_TARGET_LINUX
1083 __CFTimeZoneInitialize();
1084 __CFCalendarInitialize();
1091 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1092 args
= *_NSGetArgv();
1093 cnt
= *_NSGetArgc();
1094 #elif DEPLOYMENT_TARGET_WINDOWS
1095 wchar_t *commandLine
= GetCommandLineW();
1096 // result is actually pointer to wchar_t *, make sure to account for that below
1097 args
= (char **)CommandLineToArgvW(commandLine
, (int *)&cnt
);
1100 CFStringRef
*list
, buffer
[256];
1101 list
= (cnt
<= 256) ? buffer
: (CFStringRef
*)malloc(cnt
* sizeof(CFStringRef
));
1102 for (idx
= 0, count
= 0; idx
< cnt
; idx
++) {
1103 if (NULL
== args
[idx
]) continue;
1104 #if DEPLOYMENT_TARGET_WINDOWS
1105 list
[count
] = CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)args
[idx
], wcslen((wchar_t *)args
[idx
]));
1107 list
[count
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, args
[idx
], kCFStringEncodingUTF8
);
1108 if (NULL
== list
[count
]) {
1109 list
[count
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, args
[idx
], kCFStringEncodingISOLatin1
);
1110 // We CANNOT use the string SystemEncoding here;
1111 // Do not argue: it is not initialized yet, but these
1112 // arguments MUST be initialized before it is.
1113 // We should just ignore the argument if the UTF-8
1114 // conversion fails, but out of charity we try once
1115 // more with ISO Latin1, a standard unix encoding.
1118 if (NULL
!= list
[count
]) count
++;
1120 __CFArgStuff
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)list
, count
, &kCFTypeArrayCallBacks
);
1121 if (list
!= buffer
) free(list
);
1122 #if DEPLOYMENT_TARGET_WINDOWS
1127 _CFProcessPath(); // cache this early
1132 if (__CFRuntimeClassTableCount
< 256) __CFRuntimeClassTableCount
= 256;
1135 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
1136 const char *value
= __CFgetenv("NSZombieEnabled");
1137 if (value
&& (*value
== 'Y' || *value
== 'y')) _CFEnableZombies();
1138 value
= __CFgetenv("NSDeallocateZombies");
1139 if (value
&& (*value
== 'Y' || *value
== 'y')) __CFDeallocateZombies
= 0xff;
1142 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED)
1143 CFLog(kCFLogLevelWarning
, CFSTR("Assertions enabled"));
1146 __CFProphylacticAutofsAccess
= false;
1147 __CFInitializing
= 0;
1148 __CFInitialized
= 1;
1153 #if DEPLOYMENT_TARGET_WINDOWS
1155 __private_extern__
void __CFStringCleanup(void);
1156 __private_extern__
void __CFSocketCleanup(void);
1157 __private_extern__
void __CFUniCharCleanup(void);
1158 __private_extern__
void __CFStreamCleanup(void);
1160 static CFBundleRef
RegisterCoreFoundationBundle(void) {
1162 // might be nice to get this from the project file at some point
1163 wchar_t *DLLFileName
= (wchar_t *)L
"CoreFoundation_debug.dll";
1165 wchar_t *DLLFileName
= (wchar_t *)L
"CoreFoundation.dll";
1167 wchar_t path
[MAX_PATH
+1];
1168 path
[0] = path
[1] = 0;
1171 HMODULE ourModule
= GetModuleHandleW(DLLFileName
);
1173 CFAssert(ourModule
, __kCFLogAssertion
, "GetModuleHandle failed");
1175 wResult
= GetModuleFileNameW(ourModule
, path
, MAX_PATH
+1);
1176 CFAssert1(wResult
> 0, __kCFLogAssertion
, "GetModuleFileName failed: %d", GetLastError());
1177 CFAssert1(wResult
< MAX_PATH
+1, __kCFLogAssertion
, "GetModuleFileName result truncated: %s", path
);
1179 // strip off last component, the DLL name
1180 for (idx
= wResult
- 1; idx
; idx
--) {
1181 if ('\\' == path
[idx
]) {
1187 CFStringRef fsPath
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)path
, idx
);
1188 CFURLRef dllURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, fsPath
, kCFURLWindowsPathStyle
, TRUE
);
1189 CFURLRef bundleURL
= CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault
, dllURL
, CFSTR("CoreFoundation.resources"), TRUE
);
1193 // this registers us so subsequent calls to CFBundleGetBundleWithIdentifier will succeed
1194 CFBundleRef bundle
= CFBundleCreate(kCFAllocatorSystemDefault
, bundleURL
);
1195 CFRelease(bundleURL
);
1201 #define DLL_PROCESS_ATTACH 1
1202 #define DLL_THREAD_ATTACH 2
1203 #define DLL_THREAD_DETACH 3
1204 #define DLL_PROCESS_DETACH 0
1206 int DllMain( HINSTANCE hInstance
, DWORD dwReason
, LPVOID pReserved
) {
1207 static CFBundleRef cfBundle
= NULL
;
1208 if (dwReason
== DLL_PROCESS_ATTACH
) {
1210 cfBundle
= RegisterCoreFoundationBundle();
1211 } else if (dwReason
== DLL_PROCESS_DETACH
&& pReserved
== 0) {
1212 // Only cleanup if we are being unloaded dynamically (pReserved == 0) <rdar://problem/7480873>
1213 __CFStreamCleanup();
1214 __CFSocketCleanup();
1215 __CFUniCharCleanup();
1217 #if DEPLOYMENT_TARGET_WINDOWS
1218 // No CF functions should access TSD after this is called
1219 __CFTSDWindowsCleanup();
1223 if (cfBundle
) CFRelease(cfBundle
);
1224 __CFStringCleanup();
1225 } else if (dwReason
== DLL_THREAD_DETACH
) {
1226 __CFFinalizeWindowsThreadData();
1233 #if __CF_BIG_ENDIAN__
1234 #define RC_INCREMENT (1ULL)
1235 #define RC_MASK (0xFFFFFFFFULL)
1236 #define RC_GET(V) ((V) & RC_MASK)
1237 #define RC_DEALLOCATING_BIT (0x400000ULL << 32)
1239 #define RC_INCREMENT (1ULL << 32)
1240 #define RC_MASK (0xFFFFFFFFULL << 32)
1241 #define RC_GET(V) (((V) & RC_MASK) >> 32)
1242 #define RC_DEALLOCATING_BIT (0x400000ULL)
1245 #if !DEPLOYMENT_TARGET_WINDOWS && __LP64__
1246 static bool (*CAS64
)(int64_t, int64_t, volatile int64_t *) = OSAtomicCompareAndSwap64Barrier
;
1248 static bool (*CAS32
)(int32_t, int32_t, volatile int32_t *) = OSAtomicCompareAndSwap32Barrier
;
1251 // For "tryR==true", a return of NULL means "failed".
1252 static CFTypeRef
_CFRetain(CFTypeRef cf
, Boolean tryR
) {
1253 uint32_t cfinfo
= *(uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1254 if (cfinfo
& 0x800000) { // custom ref counting for object
1255 if (tryR
) return NULL
;
1256 CFTypeID typeID
= (cfinfo
>> 8) & 0x03FF; // mask up to 0x0FFF
1257 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1258 uint32_t (*refcount
)(intptr_t, CFTypeRef
) = cfClass
->refcount
;
1259 if (!refcount
|| !(cfClass
->version
& _kCFRuntimeCustomRefCount
) || (((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
] != 0xFF)) {
1260 HALT
; // bogus object
1263 if (((CFRuntimeBase
*)cf
)->_rc
!= 0xFFFFFFFFU
) {
1264 HALT
; // bogus object
1271 Boolean didAuto
= false;
1273 if (0 == ((CFRuntimeBase
*)cf
)->_rc
&& !CF_IS_COLLECTABLE(cf
)) return cf
; // Constant CFTypeRef
1274 #if !DEPLOYMENT_TARGET_WINDOWS
1277 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1278 if (tryR
&& (allBits
& RC_DEALLOCATING_BIT
)) return NULL
;
1279 } while (!CAS64(allBits
, allBits
+ RC_INCREMENT
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
));
1280 // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1281 if (RC_GET(allBits
) == 0 && CF_IS_COLLECTABLE(cf
)) {
1282 auto_zone_retain(objc_collectableZone(), (void*)cf
);
1288 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
1289 } while (!CAS32(lowBits
, lowBits
+ 1, (int32_t *)&((CFRuntimeBase
*)cf
)->_rc
));
1290 // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1291 if (lowBits
== 0 && CF_IS_COLLECTABLE(cf
)) {
1292 auto_zone_retain(objc_collectableZone(), (void*)cf
);
1299 volatile uint32_t *infoLocation
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1300 CFIndex rcLowBits
= __CFBitfieldGetValue(cfinfo
, RC_END
, RC_START
);
1301 if (__builtin_expect(0 == rcLowBits
, 0) && !CF_IS_COLLECTABLE(cf
)) return cf
; // Constant CFTypeRef
1304 cfinfo
= *infoLocation
;
1305 #if !DEPLOYMENT_TARGET_WINDOWS
1306 // if already deallocating, don't allow new retain
1307 if (tryR
&& (cfinfo
& 0x400000)) return NULL
;
1309 uint32_t prospectiveNewInfo
= cfinfo
; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1310 prospectiveNewInfo
+= (1 << RC_START
);
1311 rcLowBits
= __CFBitfieldGetValue(prospectiveNewInfo
, RC_END
, RC_START
);
1312 if (__builtin_expect((rcLowBits
& 0x7f) == 0, 0)) {
1313 /* Roll over another bit to the external ref count
1314 Real ref count = low 7 bits of info[CF_RC_BITS] + external ref count << 6
1315 Bit 8 of low bits indicates that external ref count is in use.
1316 External ref count is shifted by 6 rather than 7 so that we can set the low
1317 bits to to 1100 0000 rather than 1000 0000.
1318 This prevents needing to access the external ref count for successive retains and releases
1319 when the composite retain count is right around a multiple of 1 << 7.
1321 prospectiveNewInfo
= cfinfo
;
1322 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, ((1 << 7) | (1 << 6)));
1323 __CFSpinLock(&__CFRuntimeExternRefCountTableLock
);
1324 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1325 if (__builtin_expect(success
, 1)) {
1326 __CFDoExternRefOperation(350, (id
)cf
);
1328 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock
);
1330 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1331 // XXX_PCB: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1332 if (success
&& __CFBitfieldGetValue(cfinfo
, RC_END
, RC_START
) == 0 && CF_IS_COLLECTABLE(cf
)) {
1333 auto_zone_retain(objc_collectableZone(), (void*)cf
);
1337 } while (__builtin_expect(!success
, 0));
1339 if (!didAuto
&& __builtin_expect(__CFOASafe
, 0)) {
1340 __CFRecordAllocationEvent(__kCFRetainEvent
, (void *)cf
, 0, CFGetRetainCount(cf
), NULL
);
1345 // Never called under GC, only called via ARR weak subsystem; a return of NULL is failure
1346 CFTypeRef
_CFTryRetain(CFTypeRef cf
) {
1347 if (NULL
== cf
) return NULL
;
1348 if (CF_IS_TAGGED_OBJ(cf
)) return cf
; // success
1349 return _CFRetain(cf
, true);
1352 Boolean
_CFIsDeallocating(CFTypeRef cf
) {
1353 if (NULL
== cf
) return false;
1354 if (CF_IS_TAGGED_OBJ(cf
)) return false;
1355 uint32_t cfinfo
= *(uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1356 if (cfinfo
& 0x800000) { // custom ref counting for object
1357 return true; // lie for now; this weak references to these objects cannot be formed
1359 return (cfinfo
& 0x400000) ? true : false;
1362 static void _CFRelease(CFTypeRef cf
) {
1364 uint32_t cfinfo
= *(uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1365 CFTypeID typeID
= (cfinfo
>> 8) & 0x03FF; // mask up to 0x0FFF
1366 if (cfinfo
& 0x800000) { // custom ref counting for object
1367 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1368 uint32_t (*refcount
)(intptr_t, CFTypeRef
) = cfClass
->refcount
;
1369 if (!refcount
|| !(cfClass
->version
& _kCFRuntimeCustomRefCount
) || (((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
] != 0xFF)) {
1370 HALT
; // bogus object
1373 if (((CFRuntimeBase
*)cf
)->_rc
!= 0xFFFFFFFFU
) {
1374 HALT
; // bogus object
1381 CFIndex start_rc
= __builtin_expect(__CFOASafe
, 0) ? CFGetRetainCount(cf
) : 0;
1382 Boolean isAllocator
= (__kCFAllocatorTypeID_CONST
== typeID
);
1383 Boolean didAuto
= false;
1385 #if !DEPLOYMENT_TARGET_WINDOWS
1390 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1391 lowBits
= RC_GET(allBits
);
1393 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(objc_collectableZone(), (void*)cf
);
1394 return; // Constant CFTypeRef
1397 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1398 if ((cfClass
->version
& _kCFRuntimeResourcefulObject
) && cfClass
->reclaim
!= NULL
) {
1399 cfClass
->reclaim(cf
);
1401 if (!CF_IS_COLLECTABLE(cf
)) {
1402 uint64_t newAllBits
= allBits
| RC_DEALLOCATING_BIT
;
1403 if (!CAS64(allBits
, newAllBits
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
)) {
1406 allBits
= newAllBits
;
1407 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1411 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1412 lowBits
= RC_GET(allBits
);
1413 if (isAllocator
|| ((1 == lowBits
) && CAS64(allBits
, allBits
- RC_INCREMENT
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
))) {
1416 Boolean success
= false;
1417 do { // drop the deallocating bit; racey, but this resurrection stuff isn't thread-safe anyway
1418 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1419 uint64_t newAllBits
= allBits
& ~RC_DEALLOCATING_BIT
;
1420 success
= CAS64(allBits
, newAllBits
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
);
1422 goto again
; // still need to have the effect of a CFRelease
1425 } while (!CAS64(allBits
, allBits
- RC_INCREMENT
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
));
1426 if (lowBits
== 1 && CF_IS_COLLECTABLE(cf
)) {
1427 // GC: release the collector's hold over the object, which will call the finalize function later on.
1428 auto_zone_release(objc_collectableZone(), (void*)cf
);
1434 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
1436 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(objc_collectableZone(), (void*)cf
);
1437 return; // Constant CFTypeRef
1440 // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION
1441 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1442 if ((cfClass
->version
& _kCFRuntimeResourcefulObject
) && cfClass
->reclaim
!= NULL
) {
1443 cfClass
->reclaim(cf
);
1445 if (!CF_IS_COLLECTABLE(cf
)) {
1446 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1450 if (isAllocator
|| CAS32(1, 0, (int32_t *)&((CFRuntimeBase
*)cf
)->_rc
)) {
1455 } while (!CAS32(lowBits
, lowBits
- 1, (int32_t *)&((CFRuntimeBase
*)cf
)->_rc
));
1456 if (lowBits
== 1 && CF_IS_COLLECTABLE(cf
)) {
1457 // GC: release the collector's hold over the object, which will call the finalize function later on.
1458 auto_zone_release(objc_collectableZone(), (void*)cf
);
1463 #if !DEPLOYMENT_TARGET_WINDOWS
1465 volatile uint32_t *infoLocation
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1466 CFIndex rcLowBits
= __CFBitfieldGetValue(cfinfo
, RC_END
, RC_START
);
1467 if (__builtin_expect(0 == rcLowBits
, 0)) {
1468 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(objc_collectableZone(), (void*)cf
);
1469 return; // Constant CFTypeRef
1472 Boolean whack
= false;
1474 cfinfo
= *infoLocation
;
1475 rcLowBits
= __CFBitfieldGetValue(cfinfo
, RC_END
, RC_START
);
1476 if (__builtin_expect(1 == rcLowBits
, 0)) {
1477 // we think cf should be deallocated
1478 uint32_t prospectiveNewInfo
= cfinfo
| (0x400000);
1479 if (CF_IS_COLLECTABLE(cf
)) {
1480 prospectiveNewInfo
-= (1 << RC_START
);
1482 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1483 if (success
) whack
= true;
1486 uint32_t prospectiveNewInfo
= cfinfo
; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1487 if (__builtin_expect((1 << 7) == rcLowBits
, 0)) {
1488 // Time to remove a bit from the external ref count
1489 __CFSpinLock(&__CFRuntimeExternRefCountTableLock
);
1490 CFIndex rcHighBitsCnt
= __CFDoExternRefOperation(500, (id
)cf
);
1491 if (1 == rcHighBitsCnt
) {
1492 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, (1 << 6) - 1);
1494 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, ((1 << 6) | (1 << 7)) - 1);
1496 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1497 if (__builtin_expect(success
, 1)) {
1498 __CFDoExternRefOperation(450, (id
)cf
);
1500 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock
);
1502 prospectiveNewInfo
-= (1 << RC_START
);
1503 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1506 } while (__builtin_expect(!success
, 0));
1509 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1510 if ((cfClass
->version
& _kCFRuntimeResourcefulObject
) && cfClass
->reclaim
!= NULL
) {
1511 cfClass
->reclaim(cf
);
1513 if (CF_IS_COLLECTABLE(cf
)) {
1514 // GC: release the collector's hold over the object, which will call the finalize function later on.
1515 auto_zone_release(objc_collectableZone(), (void*)cf
);
1521 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1525 rcLowBits
= __CFBitfieldGetValue(*infoLocation
, RC_END
, RC_START
);
1526 if (1 == rcLowBits
) {
1529 do { // drop the deallocating bit; racey, but this resurrection stuff isn't thread-safe anyway
1530 cfinfo
= *infoLocation
;
1531 uint32_t prospectiveNewInfo
= (cfinfo
& ~(0x400000));
1532 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1539 volatile uint32_t *infoLocation
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1540 CFIndex rcLowBits
= __CFBitfieldGetValue(*infoLocation
, RC_END
, RC_START
);
1541 if (__builtin_expect(0 == rcLowBits
, 0)) {
1542 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(objc_collectableZone(), (void*)cf
);
1543 return; // Constant CFTypeRef
1547 uint32_t initialCheckInfo
= *infoLocation
;
1548 rcLowBits
= __CFBitfieldGetValue(initialCheckInfo
, RC_END
, RC_START
);
1549 if (__builtin_expect(1 == rcLowBits
, 0)) {
1550 // we think cf should be deallocated
1551 // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION
1552 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1553 if ((cfClass
->version
& _kCFRuntimeResourcefulObject
) && cfClass
->reclaim
!= NULL
) {
1554 cfClass
->reclaim(cf
);
1556 if (CF_IS_COLLECTABLE(cf
)) {
1557 uint32_t prospectiveNewInfo
= initialCheckInfo
- (1 << RC_START
);
1558 success
= CAS32(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1559 // GC: release the collector's hold over the object, which will call the finalize function later on.
1561 auto_zone_release(objc_collectableZone(), (void*)cf
);
1568 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1572 // We recheck rcLowBits to see if the object has been retained again during
1573 // the finalization process. This allows for the finalizer to resurrect,
1574 // but the main point is to allow finalizers to be able to manage the
1575 // removal of objects from uniquing caches, which may race with other threads
1576 // which are allocating (looking up and finding) objects from those caches,
1577 // which (that thread) would be the thing doing the extra retain in that case.
1578 rcLowBits
= __CFBitfieldGetValue(*infoLocation
, RC_END
, RC_START
);
1579 success
= (1 == rcLowBits
);
1580 if (__builtin_expect(success
, 1)) {
1587 uint32_t prospectiveNewInfo
= initialCheckInfo
; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1588 if (__builtin_expect((1 << 7) == rcLowBits
, 0)) {
1589 // Time to remove a bit from the external ref count
1590 __CFSpinLock(&__CFRuntimeExternRefCountTableLock
);
1591 CFIndex rcHighBitsCnt
= __CFDoExternRefOperation(500, (id
)cf
);
1592 if (1 == rcHighBitsCnt
) {
1593 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, (1 << 6) - 1);
1595 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, ((1 << 6) | (1 << 7)) - 1);
1597 success
= CAS32(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1598 if (__builtin_expect(success
, 1)) {
1599 __CFDoExternRefOperation(450, (id
)cf
);
1601 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock
);
1603 prospectiveNewInfo
-= (1 << RC_START
);
1604 success
= CAS32(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1607 } while (__builtin_expect(!success
, 0));
1610 if (!didAuto
&& __builtin_expect(__CFOASafe
, 0)) {
1611 __CFRecordAllocationEvent(__kCFReleaseEvent
, (void *)cf
, 0, start_rc
- 1, NULL
);
1616 if (!didAuto
&& __builtin_expect(__CFOASafe
, 0)) {
1617 // do not use CFGetRetainCount() because cf has been freed if it was an allocator
1618 __CFRecordAllocationEvent(__kCFReleaseEvent
, (void *)cf
, 0, 0, NULL
);
1620 // cannot zombify allocators, which get deallocated by __CFAllocatorDeallocate (finalize)
1622 __CFAllocatorDeallocate((void *)cf
);
1624 CFAllocatorRef allocator
= kCFAllocatorSystemDefault
;
1625 Boolean usesSystemDefaultAllocator
= true;
1627 if (!__CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 7, 7)) {
1628 allocator
= CFGetAllocator(cf
);
1629 usesSystemDefaultAllocator
= _CFAllocatorIsSystemDefault(allocator
);
1633 CFAllocatorDeallocate(allocator
, (uint8_t *)cf
- (usesSystemDefaultAllocator
? 0 : sizeof(CFAllocatorRef
)));
1636 if (kCFAllocatorSystemDefault
!= allocator
) {
1637 CFRelease(allocator
);
1642 #undef __kCFAllocatorTypeID_CONST
1643 #undef __CFGenericAssertIsCF