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-2011, 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
39 #include <mach-o/dyld.h>
40 #include <mach/mach.h>
41 #include <crt_externs.h>
44 #include <CoreFoundation/CFStringDefaultEncoding.h>
49 #if DEPLOYMENT_TARGET_WINDOWS
54 // retain/release recording constants -- must match values
55 // used by OA for now; probably will change in the future
56 __kCFRetainEvent
= 28,
57 __kCFReleaseEvent
= 29
60 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
63 #include <malloc/malloc.h>
66 #define FAKE_INSTRUMENTS 0
68 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
70 bool __CFOASafe
= false;
72 void (*__CFObjectAllocRecordAllocationFunction
)(int, void *, int64_t , uint64_t, const char *) = NULL
;
73 void (*__CFObjectAllocSetLastAllocEventNameFunction
)(void *, const char *) = NULL
;
75 void __CFOAInitialize(void) {
76 static void (*dyfunc
)(void) = (void *)~0;
77 if (NULL
== __CFgetenv("OAKeepAllocationStatistics")) return;
78 if ((void *)~0 == dyfunc
) {
79 dyfunc
= dlsym(RTLD_DEFAULT
, "_OAInitialize");
83 __CFObjectAllocRecordAllocationFunction
= dlsym(RTLD_DEFAULT
, "_OARecordAllocationEvent");
84 __CFObjectAllocSetLastAllocEventNameFunction
= dlsym(RTLD_DEFAULT
, "_OASetLastAllocationEventName");
89 void __CFRecordAllocationEvent(int eventnum
, void *ptr
, int64_t size
, uint64_t data
, const char *classname
) {
90 if (!__CFOASafe
|| !__CFObjectAllocRecordAllocationFunction
) return;
91 __CFObjectAllocRecordAllocationFunction(eventnum
, ptr
, size
, data
, classname
);
94 void __CFSetLastAllocationEventName(void *ptr
, const char *classname
) {
95 if (!__CFOASafe
|| !__CFObjectAllocSetLastAllocEventNameFunction
) return;
96 __CFObjectAllocSetLastAllocEventNameFunction(ptr
, classname
);
99 #elif FAKE_INSTRUMENTS
101 CF_EXPORT
bool __CFOASafe
= true;
103 void __CFOAInitialize(void) { }
105 void __CFRecordAllocationEvent(int eventnum
, void *ptr
, int64_t size
, uint64_t data
, const char *classname
) {
106 if (!__CFOASafe
) return;
107 if (!classname
) classname
= "(no class)";
108 const char *event
= "unknown event";
114 case __kCFReleaseEvent
:
118 case __kCFRetainEvent
:
122 fprintf(stdout
, "event,%d,%s,%p,%ld,%lu,%s\n", eventnum
, event
, ptr
, (long)size
, (unsigned long)data
, classname
);
125 void __CFSetLastAllocationEventName(void *ptr
, const char *classname
) {
126 if (!__CFOASafe
) return;
127 if (!classname
) classname
= "(no class)";
128 fprintf(stdout
, "name,%p,%s\n", ptr
, classname
? classname
: "(no class)");
133 bool __CFOASafe
= false;
135 void __CFOAInitialize(void) { }
136 void __CFRecordAllocationEvent(int eventnum
, void *ptr
, int64_t size
, uint64_t data
, const char *classname
) { }
137 void __CFSetLastAllocationEventName(void *ptr
, const char *classname
) { }
141 extern void __HALT(void);
143 static CFTypeID __kCFNotATypeTypeID
= _kCFRuntimeNotATypeID
;
145 #if !defined (__cplusplus)
146 static const CFRuntimeClass __CFNotATypeClass
= {
158 static CFTypeID __kCFTypeTypeID
= _kCFRuntimeNotATypeID
;
160 static const CFRuntimeClass __CFTypeClass
= {
172 void SIG1(CFTypeRef
){__HALT();};;
173 CFTypeRef
SIG2(CFAllocatorRef
,CFTypeRef
){__HALT();return NULL
;};
174 Boolean
SIG3(CFTypeRef
,CFTypeRef
){__HALT();return FALSE
;};
175 CFHashCode
SIG4(CFTypeRef
){__HALT(); return 0;};
176 CFStringRef
SIG5(CFTypeRef
,CFDictionaryRef
){__HALT();return NULL
;};
177 CFStringRef
SIG6(CFTypeRef
){__HALT();return NULL
;};
179 static const CFRuntimeClass __CFNotATypeClass
= {
191 static CFTypeID __kCFTypeTypeID
= _kCFRuntimeNotATypeID
;
193 static const CFRuntimeClass __CFTypeClass
= {
206 // the lock does not protect most reading of these; we just leak the old table to allow read-only accesses to continue to work
207 static CFSpinLock_t __CFBigRuntimeFunnel
= CFSpinLockInit
;
208 static CFRuntimeClass
* __CFRuntimeClassTable
[__CFRuntimeClassTableSize
] = {0};
209 static int32_t __CFRuntimeClassTableCount
= 0;
211 __private_extern__
uintptr_t __CFRuntimeObjCClassTable
[__CFRuntimeClassTableSize
] = {0};
213 #if !defined(__CFObjCIsCollectable)
214 bool (*__CFObjCIsCollectable
)(void *) = NULL
;
217 // Compiler uses this symbol name; must match compiler built-in decl, so we use 'int'
219 int __CFConstantStringClassReference
[24] = {0};
221 int __CFConstantStringClassReference
[12] = {0};
223 void *__CFConstantStringClassReferencePtr
= &__CFConstantStringClassReference
;
225 Boolean
_CFIsObjC(CFTypeID typeID
, void *obj
) {
226 return CF_IS_OBJC(typeID
, obj
);
229 CFTypeID
_CFRuntimeRegisterClass(const CFRuntimeClass
* const cls
) {
230 // className must be pure ASCII string, non-null
231 if ((cls
->version
& _kCFRuntimeCustomRefCount
) && !cls
->refcount
) {
232 CFLog(kCFLogLevelWarning
, CFSTR("*** _CFRuntimeRegisterClass() given inconsistent class '%s'. Program will crash soon."), cls
->className
);
233 return _kCFRuntimeNotATypeID
;
235 __CFSpinLock(&__CFBigRuntimeFunnel
);
236 if (__CFMaxRuntimeTypes
<= __CFRuntimeClassTableCount
) {
237 CFLog(kCFLogLevelWarning
, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls
->className
);
238 __CFSpinUnlock(&__CFBigRuntimeFunnel
);
239 return _kCFRuntimeNotATypeID
;
241 if (__CFRuntimeClassTableSize
<= __CFRuntimeClassTableCount
) {
242 CFLog(kCFLogLevelWarning
, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls
->className
);
243 __CFSpinUnlock(&__CFBigRuntimeFunnel
);
244 return _kCFRuntimeNotATypeID
;
246 __CFRuntimeClassTable
[__CFRuntimeClassTableCount
++] = (CFRuntimeClass
*)cls
;
247 CFTypeID typeID
= __CFRuntimeClassTableCount
- 1;
248 __CFSpinUnlock(&__CFBigRuntimeFunnel
);
253 const CFRuntimeClass
* _CFRuntimeGetClassWithTypeID(CFTypeID typeID
) {
254 return __CFRuntimeClassTable
[typeID
]; // hopelessly unthreadsafe
257 void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID
) {
258 __CFSpinLock(&__CFBigRuntimeFunnel
);
259 __CFRuntimeClassTable
[typeID
] = NULL
;
260 __CFSpinUnlock(&__CFBigRuntimeFunnel
);
264 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
266 __private_extern__
uint8_t __CFZombieEnabled
= 0;
267 __private_extern__
uint8_t __CFDeallocateZombies
= 0;
269 void _CFEnableZombies(void) {
270 __CFZombieEnabled
= 0xFF;
275 // XXX_PCB: use the class version field as a bitmask, to allow classes to opt-in for GC scanning.
277 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
278 CF_INLINE CFOptionFlags
CF_GET_COLLECTABLE_MEMORY_TYPE(const CFRuntimeClass
*cls
)
280 return ((cls
->version
& _kCFRuntimeScannedObject
) ? __kCFAllocatorGCScannedMemory
: 0) | __kCFAllocatorGCObjectMemory
;
283 #define CF_GET_COLLECTABLE_MEMORY_TYPE(x) (0)
286 CFTypeRef
_CFRuntimeCreateInstance(CFAllocatorRef allocator
, CFTypeID typeID
, CFIndex extraBytes
, unsigned char *category
) {
287 if (__CFRuntimeClassTableSize
<= typeID
) HALT
;
288 CFAssert1(typeID
!= _kCFRuntimeNotATypeID
, __kCFLogAssertion
, "%s(): Uninitialized type id", __PRETTY_FUNCTION__
);
289 CFRuntimeClass
*cls
= __CFRuntimeClassTable
[typeID
];
293 Boolean customRC
= !!(cls
->version
& _kCFRuntimeCustomRefCount
);
294 if (customRC
&& !cls
->refcount
) {
295 CFLog(kCFLogLevelWarning
, CFSTR("*** _CFRuntimeCreateInstance() found inconsistent class '%s'."), cls
->className
);
298 if (customRC
&& kCFUseCollectableAllocator
&& (kCFAllocatorSystemDefaultGCRefZero
== allocator
|| kCFAllocatorDefaultGCRefZero
== allocator
)) {
299 CFLog(kCFLogLevelWarning
, CFSTR("*** _CFRuntimeCreateInstance(): special zero-ref allocators cannot be used with class '%s' with custom ref counting."), cls
->className
);
302 CFAllocatorRef realAllocator
= _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator
);
303 if (kCFAllocatorNull
== realAllocator
) {
306 Boolean usesSystemDefaultAllocator
= _CFAllocatorIsSystemDefault(realAllocator
);
307 CFIndex size
= sizeof(CFRuntimeBase
) + extraBytes
+ (usesSystemDefaultAllocator
? 0 : sizeof(CFAllocatorRef
));
308 size
= (size
+ 0xF) & ~0xF; // CF objects are multiples of 16 in size
309 // CFType version 0 objects are unscanned by default since they don't have write-barriers and hard retain their innards
310 // CFType version 1 objects are scanned and use hand coded write-barriers to store collectable storage within
311 CFRuntimeBase
*memory
= (CFRuntimeBase
*)CFAllocatorAllocate(allocator
, size
, CF_GET_COLLECTABLE_MEMORY_TYPE(cls
));
312 if (NULL
== memory
) {
315 if (!kCFUseCollectableAllocator
|| !CF_IS_COLLECTABLE_ALLOCATOR(allocator
) || !(CF_GET_COLLECTABLE_MEMORY_TYPE(cls
) & __kCFAllocatorGCScannedMemory
)) {
316 memset(memory
, 0, size
);
318 if (__CFOASafe
&& category
) {
319 __CFSetLastAllocationEventName(memory
, (char *)category
);
320 } else if (__CFOASafe
) {
321 __CFSetLastAllocationEventName(memory
, (char *)cls
->className
);
323 if (!usesSystemDefaultAllocator
) {
324 // add space to hold allocator ref for non-standard allocators.
325 // (this screws up 8 byte alignment but seems to work)
326 *(CFAllocatorRef
*)((char *)memory
) = (CFAllocatorRef
)CFRetain(realAllocator
);
327 memory
= (CFRuntimeBase
*)((char *)memory
+ sizeof(CFAllocatorRef
));
329 memory
->_cfisa
= __CFISAForTypeID(typeID
);
332 if (!kCFUseCollectableAllocator
|| (kCFAllocatorSystemDefaultGCRefZero
!= allocator
&& kCFAllocatorDefaultGCRefZero
!= allocator
)) {
336 memory
->_rc
= 0xFFFFFFFFU
;
340 if (!kCFUseCollectableAllocator
|| (kCFAllocatorSystemDefaultGCRefZero
!= allocator
&& kCFAllocatorDefaultGCRefZero
!= allocator
)) {
347 uint32_t *cfinfop
= (uint32_t *)&(memory
->_cfinfo
);
348 *cfinfop
= (uint32_t)((rc
<< 24) | (customRC
? 0x800000 : 0x0) | ((uint32_t)typeID
<< 8) | (usesSystemDefaultAllocator
? 0x80 : 0x00));
349 if (NULL
!= cls
->init
) {
355 void _CFRuntimeInitStaticInstance(void *ptr
, CFTypeID typeID
) {
356 CFAssert1(typeID
!= _kCFRuntimeNotATypeID
, __kCFLogAssertion
, "%s(): Uninitialized type id", __PRETTY_FUNCTION__
);
357 if (__CFRuntimeClassTableSize
<= typeID
) HALT
;
358 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
359 Boolean customRC
= !!(cfClass
->version
& _kCFRuntimeCustomRefCount
);
361 CFLog(kCFLogLevelError
, CFSTR("*** Cannot initialize a static instance to a class (%s) with custom ref counting"), cfClass
->className
);
364 CFRuntimeBase
*memory
= (CFRuntimeBase
*)ptr
;
365 memory
->_cfisa
= __CFISAForTypeID(typeID
);
366 uint32_t *cfinfop
= (uint32_t *)&(memory
->_cfinfo
);
367 *cfinfop
= (uint32_t)(((customRC
? 0xFF : 0) << 24) | (customRC
? 0x800000 : 0x0) | ((uint32_t)typeID
<< 8) | 0x80);
369 memory
->_rc
= customRC
? 0xFFFFFFFFU
: 0x0;
371 if (NULL
!= cfClass
->init
) {
372 (cfClass
->init
)(memory
);
376 void _CFRuntimeSetInstanceTypeID(CFTypeRef cf
, CFTypeID newTypeID
) {
377 if (__CFRuntimeClassTableSize
<= newTypeID
) HALT
;
378 uint32_t *cfinfop
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
379 CFTypeID currTypeID
= (*cfinfop
>> 8) & 0x03FF; // mask up to 0x0FFF
380 CFRuntimeClass
*newcfClass
= __CFRuntimeClassTable
[newTypeID
];
381 Boolean newCustomRC
= (newcfClass
->version
& _kCFRuntimeCustomRefCount
);
382 CFRuntimeClass
*currcfClass
= __CFRuntimeClassTable
[currTypeID
];
383 Boolean currCustomRC
= (currcfClass
->version
& _kCFRuntimeCustomRefCount
);
384 if (currCustomRC
|| (0 != currTypeID
&& newCustomRC
)) {
385 CFLog(kCFLogLevelError
, CFSTR("*** Cannot change the CFTypeID of a %s to a %s due to custom ref counting"), currcfClass
->className
, newcfClass
->className
);
388 // Going from current type ID of 0 to anything is allowed, but if
389 // the object has somehow already been retained and the transition
390 // is to a class doing custom ref counting, the ref count isn't
391 // transferred and there will probably be a crash later when the
392 // object is freed too early.
393 *cfinfop
= (*cfinfop
& 0xFFF000FFU
) | ((uint32_t)newTypeID
<< 8);
398 __kCFObjectRetainedEvent
= 12,
399 __kCFObjectReleasedEvent
= 13
402 #if DEPLOYMENT_TARGET_MACOSX
403 #define NUM_EXTERN_TABLES 8
404 #define EXTERN_TABLE_IDX(O) (((uintptr_t)(O) >> 8) & 0x7)
405 #elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
406 #define NUM_EXTERN_TABLES 1
407 #define EXTERN_TABLE_IDX(O) 0
412 // we disguise pointers so that programs like 'leaks' forget about these references
413 #define DISGUISE(O) (~(uintptr_t)(O))
417 CFBasicHashRef table
;
418 uint8_t padding
[64 - sizeof(CFBasicHashRef
) - sizeof(CFSpinLock_t
)];
419 } __NSRetainCounters
[NUM_EXTERN_TABLES
];
421 CF_EXPORT
uintptr_t __CFDoExternRefOperation(uintptr_t op
, id obj
) {
422 if (nil
== obj
) HALT
;
423 uintptr_t idx
= EXTERN_TABLE_IDX(obj
);
424 uintptr_t disguised
= DISGUISE(obj
);
425 CFSpinLock_t
*lock
= &__NSRetainCounters
[idx
].lock
;
426 CFBasicHashRef table
= __NSRetainCounters
[idx
].table
;
429 case 300: // increment
430 case 350: // increment, no event
432 CFBasicHashAddValue(table
, disguised
, disguised
);
433 __CFSpinUnlock(lock
);
434 if (__CFOASafe
&& op
!= 350) __CFRecordAllocationEvent(__kCFObjectRetainedEvent
, obj
, 0, 0, NULL
);
435 return (uintptr_t)obj
;
436 case 400: // decrement
437 if (__CFOASafe
) __CFRecordAllocationEvent(__kCFObjectReleasedEvent
, obj
, 0, 0, NULL
);
438 case 450: // decrement, no event
440 count
= (uintptr_t)CFBasicHashRemoveValue(table
, disguised
);
441 __CFSpinUnlock(lock
);
445 count
= (uintptr_t)CFBasicHashGetCountOfKey(table
, disguised
);
446 __CFSpinUnlock(lock
);
452 static void __CFExternRefNullFreeCallbacks(CFConstBasicHashRef ht
, CFAllocatorRef allocator
, CFBasicHashCallbacks
*cb
) {
455 static uintptr_t __CFExternRefNullRetainValue(CFConstBasicHashRef ht
, uintptr_t stack_value
) {
459 static uintptr_t __CFExternRefNullRetainKey(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
463 static void __CFExternRefNullReleaseValue(CFConstBasicHashRef ht
, uintptr_t stack_value
) {
466 static void __CFExternRefNullReleaseKey(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
469 static Boolean
__CFExternRefNullEquateValues(CFConstBasicHashRef ht
, uintptr_t coll_value1
, uintptr_t stack_value2
) {
470 return coll_value1
== stack_value2
;
473 static Boolean
__CFExternRefNullEquateKeys(CFConstBasicHashRef ht
, uintptr_t coll_key1
, uintptr_t stack_key2
) {
474 return coll_key1
== stack_key2
;
477 static uintptr_t __CFExternRefNullHashKey(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
481 static uintptr_t __CFExternRefNullGetIndirectKey(CFConstBasicHashRef ht
, uintptr_t coll_value
) {
485 static CFStringRef
__CFExternRefNullCopyValueDescription(CFConstBasicHashRef ht
, uintptr_t stack_value
) {
486 return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%p>"), (void *)stack_value
);
489 static CFStringRef
__CFExternRefNullCopyKeyDescription(CFConstBasicHashRef ht
, uintptr_t stack_key
) {
490 return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%p>"), (void *)stack_key
);
493 static CFBasicHashCallbacks
*__CFExternRefNullCopyCallbacks(CFConstBasicHashRef ht
, CFAllocatorRef allocator
, CFBasicHashCallbacks
*cb
);
495 static const CFBasicHashCallbacks CFExternRefCallbacks
= {
496 __CFExternRefNullCopyCallbacks
,
497 __CFExternRefNullFreeCallbacks
,
498 __CFExternRefNullRetainValue
,
499 __CFExternRefNullRetainKey
,
500 __CFExternRefNullReleaseValue
,
501 __CFExternRefNullReleaseKey
,
502 __CFExternRefNullEquateValues
,
503 __CFExternRefNullEquateKeys
,
504 __CFExternRefNullHashKey
,
505 __CFExternRefNullGetIndirectKey
,
506 __CFExternRefNullCopyValueDescription
,
507 __CFExternRefNullCopyKeyDescription
510 static CFBasicHashCallbacks
*__CFExternRefNullCopyCallbacks(CFConstBasicHashRef ht
, CFAllocatorRef allocator
, CFBasicHashCallbacks
*cb
) {
511 return (CFBasicHashCallbacks
*)&CFExternRefCallbacks
;
514 CF_EXPORT CFTypeID
CFNumberGetTypeID(void);
516 CF_INLINE CFTypeID
__CFGenericTypeID_inline(const void *cf
) {
517 // yes, 10 bits masked off, though 12 bits are there for the type field; __CFRuntimeClassTableSize is 1024
518 uint32_t *cfinfop
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
519 CFTypeID typeID
= (*cfinfop
>> 8) & 0x03FF; // mask up to 0x0FFF
523 CFTypeID
__CFGenericTypeID(const void *cf
) {
524 return __CFGenericTypeID_inline(cf
);
527 CFTypeID
CFTypeGetTypeID(void) {
528 return __kCFTypeTypeID
;
531 __private_extern__
void __CFGenericValidateType_(CFTypeRef cf
, CFTypeID type
, const char *func
) {
532 if (cf
&& CF_IS_OBJC(type
, cf
)) return;
533 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
); \
534 CFAssert3(__CFGenericTypeID_inline(cf
) == type
, __kCFLogAssertion
, "%s(): pointer %p is not a %s", func
, cf
, __CFRuntimeClassTable
[type
]->className
); \
537 #define __CFGenericAssertIsCF(cf) \
538 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);
541 #define CFTYPE_IS_OBJC(obj) (false)
542 #define CFTYPE_OBJC_FUNCDISPATCH0(rettype, obj, sel) do {} while (0)
543 #define CFTYPE_OBJC_FUNCDISPATCH1(rettype, obj, sel, a1) do {} while (0)
546 CFTypeID
CFGetTypeID(CFTypeRef cf
) {
548 if (NULL
== cf
) HALT
;
550 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeID
, cf
, _cfTypeID
);
551 __CFGenericAssertIsCF(cf
);
552 return __CFGenericTypeID_inline(cf
);
555 CFStringRef
CFCopyTypeIDDescription(CFTypeID type
) {
556 CFAssert2((NULL
!= __CFRuntimeClassTable
[type
]) && __kCFNotATypeTypeID
!= type
&& __kCFTypeTypeID
!= type
, __kCFLogAssertion
, "%s(): type %d is not a CF type ID", __PRETTY_FUNCTION__
, type
);
557 return CFStringCreateWithCString(kCFAllocatorSystemDefault
, __CFRuntimeClassTable
[type
]->className
, kCFStringEncodingASCII
);
560 // Bit 31 (highest bit) in second word of cf instance indicates external ref count
562 static CFTypeRef
_CFRetain(CFTypeRef cf
, Boolean tryR
);
564 CFTypeRef
CFRetain(CFTypeRef cf
) {
565 if (NULL
== cf
) HALT
;
566 if (cf
) __CFGenericAssertIsCF(cf
);
567 return _CFRetain(cf
, false);
570 static void _CFRelease(CFTypeRef cf
);
572 void CFRelease(CFTypeRef cf
) {
573 if (NULL
== cf
) HALT
;
575 void **addrs
[2] = {&&start
, &&end
};
577 if (addrs
[0] <= __builtin_return_address(0) && __builtin_return_address(0) <= addrs
[1]) {
578 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]);
582 if (cf
) __CFGenericAssertIsCF(cf
);
590 __private_extern__
void __CFAllocatorDeallocate(CFTypeRef cf
);
592 __private_extern__
const void *__CFStringCollectionCopy(CFAllocatorRef allocator
, const void *ptr
) {
593 if (NULL
== ptr
) HALT
;
594 CFStringRef theString
= (CFStringRef
)ptr
;
595 CFStringRef result
= CFStringCreateCopy(_CFConvertAllocatorToGCRefZeroEquivalent(allocator
), theString
);
596 return (const void *)result
;
599 extern void CFCollection_non_gc_storage_error(void);
601 __private_extern__
const void *__CFTypeCollectionRetain(CFAllocatorRef allocator
, const void *ptr
) {
602 if (NULL
== ptr
) HALT
;
603 CFTypeRef cf
= (CFTypeRef
)ptr
;
604 // only collections allocated in the GC zone can opt-out of reference counting.
605 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
606 if (CFTYPE_IS_OBJC(cf
)) return cf
; // do nothing for OBJC objects.
607 if (auto_zone_is_valid_pointer(objc_collectableZone(), ptr
)) {
608 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)];
609 if (cfClass
->version
& _kCFRuntimeResourcefulObject
) {
610 // GC: If this a CF object in the GC heap that is marked resourceful, then
611 // it must be retained keep it alive in a CF collection.
615 ; // don't retain normal CF objects
618 // support constant CFTypeRef objects.
620 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
622 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
];
624 if (lowBits
== 0) return cf
;
625 // complain about non-GC objects in GC containers.
626 CFLog(kCFLogLevelWarning
, CFSTR("storing a non-GC object %p in a GC collection, break on CFCollection_non_gc_storage_error to debug."), cf
);
627 CFCollection_non_gc_storage_error();
628 // XXX should halt, except Patrick is using this somewhere.
636 __private_extern__
void __CFTypeCollectionRelease(CFAllocatorRef allocator
, const void *ptr
) {
637 if (NULL
== ptr
) HALT
;
638 CFTypeRef cf
= (CFTypeRef
)ptr
;
639 // only collections allocated in the GC zone can opt-out of reference counting.
640 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
641 if (CFTYPE_IS_OBJC(cf
)) return; // do nothing for OBJC objects.
642 if (auto_zone_is_valid_pointer(objc_collectableZone(), cf
)) {
643 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
644 // GC: If this a CF object in the GC heap that is marked uncollectable, then
645 // must balance the retain done in __CFTypeCollectionRetain().
646 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)];
647 if (cfClass
->version
& _kCFRuntimeResourcefulObject
) {
648 // reclaim is called by _CFRelease(), which must be called to keep the
649 // CF and GC retain counts in sync.
652 // avoid releasing normal CF objects. Like other collections, for example
657 // support constant CFTypeRef objects.
659 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
661 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
];
663 if (lowBits
== 0) return;
670 static CFSpinLock_t __CFRuntimeExternRefCountTableLock
= CFSpinLockInit
;
673 static uint64_t __CFGetFullRetainCount(CFTypeRef cf
) {
674 if (NULL
== cf
) HALT
;
676 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
678 return (uint64_t)0x0fffffffffffffffULL
;
682 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
];
684 return (uint64_t)0x0fffffffffffffffULL
;
686 uint64_t highBits
= 0;
687 if ((lowBits
& 0x80) != 0) {
688 highBits
= __CFDoExternRefOperation(500, (id
)cf
);
690 uint64_t compositeRC
= (lowBits
& 0x7f) + (highBits
<< 6);
695 CFIndex
CFGetRetainCount(CFTypeRef cf
) {
696 if (NULL
== cf
) HALT
;
697 uint32_t cfinfo
= *(uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
698 if (cfinfo
& 0x800000) { // custom ref counting for object
699 CFTypeID typeID
= (cfinfo
>> 8) & 0x03FF; // mask up to 0x0FFF
700 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
701 uint32_t (*refcount
)(intptr_t, CFTypeRef
) = cfClass
->refcount
;
702 if (!refcount
|| !(cfClass
->version
& _kCFRuntimeCustomRefCount
) || (((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
] != 0xFF)) {
703 HALT
; // bogus object
706 if (((CFRuntimeBase
*)cf
)->_rc
!= 0xFFFFFFFFU
) {
707 HALT
; // bogus object
710 uint32_t rc
= refcount(0, cf
);
714 return (rc
< LONG_MAX
) ? (CFIndex
)rc
: (CFIndex
)LONG_MAX
;
717 uint64_t rc
= __CFGetFullRetainCount(cf
);
718 return (rc
< (uint64_t)LONG_MAX
) ? (CFIndex
)rc
: (CFIndex
)LONG_MAX
;
721 CFTypeRef
CFMakeCollectable(CFTypeRef cf
) {
722 if (NULL
== cf
) return NULL
;
726 CFTypeRef
CFMakeUncollectable(CFTypeRef cf
) {
727 if (NULL
== cf
) return NULL
;
728 if (CF_IS_COLLECTABLE(cf
)) {
734 Boolean
CFEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
735 if (NULL
== cf1
) HALT
;
736 if (NULL
== cf2
) HALT
;
737 if (cf1
== cf2
) return true;
738 CFTYPE_OBJC_FUNCDISPATCH1(Boolean
, cf1
, isEqual
:, cf2
);
739 CFTYPE_OBJC_FUNCDISPATCH1(Boolean
, cf2
, isEqual
:, cf1
);
740 __CFGenericAssertIsCF(cf1
);
741 __CFGenericAssertIsCF(cf2
);
742 if (__CFGenericTypeID_inline(cf1
) != __CFGenericTypeID_inline(cf2
)) return false;
743 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf1
)]->equal
) {
744 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf1
)]->equal(cf1
, cf2
);
749 CFHashCode
CFHash(CFTypeRef cf
) {
750 if (NULL
== cf
) HALT
;
751 CFTYPE_OBJC_FUNCDISPATCH0(CFHashCode
, cf
, hash
);
752 __CFGenericAssertIsCF(cf
);
753 CFHashCode (*hash
)(CFTypeRef cf
) = __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->hash
;
757 if (CF_IS_COLLECTABLE(cf
)) return (CFHashCode
)_object_getExternalHash((id
)cf
);
758 return (CFHashCode
)cf
;
761 // definition: produces a normally non-NULL debugging description of the object
762 CFStringRef
CFCopyDescription(CFTypeRef cf
) {
763 if (NULL
== cf
) return NULL
;
764 // CFTYPE_OBJC_FUNCDISPATCH0(CFStringRef, cf, _copyDescription); // XXX returns 0 refcounted item under GC
765 __CFGenericAssertIsCF(cf
);
766 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyDebugDesc
) {
767 CFStringRef result
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyDebugDesc(cf
);
768 if (NULL
!= result
) return result
;
770 return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%s %p [%p]>"), __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->className
, cf
, CFGetAllocator(cf
));
773 // Definition: if type produces a formatting description, return that string, otherwise NULL
774 __private_extern__ CFStringRef
__CFCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
775 if (NULL
== cf
) return NULL
;
776 __CFGenericAssertIsCF(cf
);
777 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyFormattingDesc
) {
778 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyFormattingDesc(cf
, formatOptions
);
783 extern CFAllocatorRef
__CFAllocatorGetAllocator(CFTypeRef
);
785 CFAllocatorRef
CFGetAllocator(CFTypeRef cf
) {
786 if (NULL
== cf
) return kCFAllocatorSystemDefault
;
787 if (__kCFAllocatorTypeID_CONST
== __CFGenericTypeID_inline(cf
)) {
788 return __CFAllocatorGetAllocator(cf
);
790 return __CFGetAllocator(cf
);
793 extern void __CFNullInitialize(void);
794 extern void __CFAllocatorInitialize(void);
795 extern void __CFStringInitialize(void);
796 extern void __CFArrayInitialize(void);
797 extern void __CFBooleanInitialize(void);
798 extern void __CFCharacterSetInitialize(void);
799 extern void __CFDataInitialize(void);
800 extern void __CFNumberInitialize(void);
801 extern void __CFStorageInitialize(void);
802 extern void __CFErrorInitialize(void);
803 extern void __CFTreeInitialize(void);
804 extern void __CFURLInitialize(void);
805 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
806 extern void __CFMachPortInitialize(void);
808 extern void __CFMessagePortInitialize(void);
809 extern void __CFRunLoopInitialize(void);
810 extern void __CFRunLoopObserverInitialize(void);
811 extern void __CFRunLoopSourceInitialize(void);
812 extern void __CFRunLoopTimerInitialize(void);
813 extern void __CFBundleInitialize(void);
814 extern void __CFPlugInInitialize(void);
815 extern void __CFPlugInInstanceInitialize(void);
816 extern void __CFUUIDInitialize(void);
817 extern void __CFBinaryHeapInitialize(void);
818 extern void __CFBitVectorInitialize(void);
819 #if DEPLOYMENT_TARGET_LINUX
820 __private_extern__
void __CFTSDLinuxInitialize();
822 #if DEPLOYMENT_TARGET_WINDOWS
824 __private_extern__
void __CFTSDWindowsInitialize(void);
825 __private_extern__
void __CFTSDWindowsCleanup(void);
826 __private_extern__
void __CFFinalizeWindowsThreadData();
828 extern void __CFStreamInitialize(void);
829 extern void __CFCalendarInitialize();
830 extern void __CFTimeZoneInitialize();
831 #if DEPLOYMENT_TARGET_LINUX
832 extern void __CFCalendarInitialize();
833 extern void __CFTimeZoneInitialize();
836 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
837 __private_extern__
uint8_t __CF120290
= false;
838 __private_extern__
uint8_t __CF120291
= false;
839 __private_extern__
uint8_t __CF120293
= false;
840 __private_extern__
char * __crashreporter_info__
= NULL
;
841 asm(".desc ___crashreporter_info__, 0x10");
843 static void __01121__(void) {
844 __CF120291
= pthread_is_threaded_np() ? true : false;
847 static void __01123__(void) {
848 // Ideally, child-side atfork handlers should be async-cancel-safe, as fork()
849 // is async-cancel-safe and can be called from signal handlers. See also
850 // http://standards.ieee.org/reading/ieee/interp/1003-1c-95_int/pasc-1003.1c-37.html
851 // This is not a problem for CF.
855 __crashreporter_info__
= "*** multi-threaded process forked ***";
857 __crashreporter_info__
= "*** single-threaded process forked ***";
862 #define EXEC_WARNING_STRING_1 "The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec().\n"
863 #define EXEC_WARNING_STRING_2 "Break on __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__() to debug.\n"
865 __private_extern__
void __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__(void) {
866 write(2, EXEC_WARNING_STRING_1
, sizeof(EXEC_WARNING_STRING_1
) - 1);
867 write(2, EXEC_WARNING_STRING_2
, sizeof(EXEC_WARNING_STRING_2
) - 1);
873 CF_EXPORT
const void *__CFArgStuff
;
874 const void *__CFArgStuff
= NULL
;
875 __private_extern__
void *__CFAppleLanguages
= NULL
;
890 {"DYLD_IMAGE_SUFFIX", NULL
},
891 {"CFProcessPath", NULL
},
892 {"CFFIXED_USER_HOME", NULL
},
893 {"CFNETWORK_LIBRARY_PATH", NULL
},
894 {"CFUUIDVersionNumber", NULL
},
895 {"CFDebugNamedDataSharing", NULL
},
896 {"CFPropertyListAllowImmutableCollections", NULL
},
897 {"CFBundleUseDYLD", NULL
},
898 {"CFBundleDisableStringsSharing", NULL
},
899 {"CFCharacterSetCheckForExpandedSet", NULL
},
900 {"__CF_DEBUG_EXPANDED_SET", NULL
},
901 {"CFStringDisableROM", NULL
},
902 {"CF_CHARSET_PATH", NULL
},
903 {"__CF_USER_TEXT_ENCODING", NULL
},
904 {"__CFPREFERENCES_AUTOSYNC_INTERVAL", NULL
},
905 {"__CFPREFERENCES_USE_OLD_UID_BEHAVIOR", NULL
},
906 {"CFNumberDisableCache", NULL
},
907 {NULL
, NULL
}, // the last one is for optional "COMMAND_MODE" "legacy", do not use this slot, insert before
910 __private_extern__
const char *__CFgetenv(const char *n
) {
911 for (CFIndex idx
= 0; idx
< sizeof(__CFEnv
) / sizeof(__CFEnv
[0]); idx
++) {
912 if (__CFEnv
[idx
].name
&& 0 == strcmp(n
, __CFEnv
[idx
].name
)) return __CFEnv
[idx
].value
;
917 #if DEPLOYMENT_TARGET_WINDOWS
918 #define kNilPthreadT { nil, nil }
920 #define kNilPthreadT (pthread_t)0
924 CF_EXPORT pthread_t _CFMainPThread
;
925 pthread_t _CFMainPThread
= kNilPthreadT
;
927 #undef kCFUseCollectableAllocator
928 CF_EXPORT
bool kCFUseCollectableAllocator
;
929 bool kCFUseCollectableAllocator
= false;
931 __private_extern__ Boolean __CFProphylacticAutofsAccess
= false;
932 __private_extern__ Boolean __CFInitializing
= 0;
933 __private_extern__ Boolean __CFInitialized
= 0;
935 #if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
936 static void __CFInitialize(void) __attribute__ ((constructor
));
939 #if DEPLOYMENT_TARGET_WINDOWS
942 void __CFInitialize(void) {
944 if (!__CFInitialized
&& !__CFInitializing
) {
945 __CFInitializing
= 1;
947 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
948 if (!pthread_main_np()) HALT
; // CoreFoundation must be initialized on the main thread
951 _CFMainPThread
= pthread_self();
953 #if DEPLOYMENT_TARGET_WINDOWS
954 // Must not call any CF functions
955 __CFTSDWindowsInitialize();
956 #elif DEPLOYMENT_TARGET_LINUX
957 __CFTSDLinuxInitialize();
960 __CFProphylacticAutofsAccess
= true;
962 for (CFIndex idx
= 0; idx
< sizeof(__CFEnv
) / sizeof(__CFEnv
[0]); idx
++) {
963 __CFEnv
[idx
].value
= __CFEnv
[idx
].name
? getenv(__CFEnv
[idx
].name
) : NULL
;
966 #if !defined(kCFUseCollectableAllocator)
967 kCFUseCollectableAllocator
= objc_collectingEnabled();
969 if (kCFUseCollectableAllocator
) {
970 #if !defined(__CFObjCIsCollectable)
971 __CFObjCIsCollectable
= (bool (*)(void *))objc_isAuto
;
974 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
976 __CFStringGetUserDefaultEncoding(&s
, &r
); // force the potential setenv to occur early
977 pthread_atfork(__01121__
, NULL
, __01123__
);
980 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
981 const char *value
= __CFgetenv("NSZombieEnabled");
982 if (value
&& (*value
== 'Y' || *value
== 'y')) __CFZombieEnabled
= 0xff;
983 value
= __CFgetenv("NSDeallocateZombies");
984 if (value
&& (*value
== 'Y' || *value
== 'y')) __CFDeallocateZombies
= 0xff;
988 memset(__CFRuntimeClassTable
, 0, sizeof(__CFRuntimeClassTable
));
989 memset(__CFRuntimeObjCClassTable
, 0, sizeof(__CFRuntimeObjCClassTable
));
992 /* Here so that two runtime classes get indices 0, 1. */
993 __kCFNotATypeTypeID
= _CFRuntimeRegisterClass(&__CFNotATypeClass
);
994 __kCFTypeTypeID
= _CFRuntimeRegisterClass(&__CFTypeClass
);
996 /* Here so that __kCFAllocatorTypeID gets index 2. */
997 __CFAllocatorInitialize();
999 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1002 char **args
= *_NSGetArgv();
1003 cnt
= *_NSGetArgc();
1004 for (idx
= 1; idx
< cnt
- 1; idx
++) {
1005 if (NULL
== args
[idx
]) continue;
1006 if (0 == strcmp(args
[idx
], "-AppleLanguages") && args
[idx
+ 1]) {
1007 CFIndex length
= strlen(args
[idx
+ 1]);
1008 __CFAppleLanguages
= malloc(length
+ 1);
1009 memmove(__CFAppleLanguages
, args
[idx
+ 1], length
+ 1);
1017 CFBasicHashGetTypeID();
1020 for (CFIndex idx
= 0; idx
< NUM_EXTERN_TABLES
; idx
++) {
1021 __NSRetainCounters
[idx
].table
= CFBasicHashCreate(kCFAllocatorSystemDefault
, kCFBasicHashHasCounts
| kCFBasicHashLinearHashing
| kCFBasicHashAggressiveGrowth
, &CFExternRefCallbacks
);
1022 CFBasicHashSetCapacity(__NSRetainCounters
[idx
].table
, 40);
1023 __NSRetainCounters
[idx
].lock
= CFSpinLockInit
;
1026 /*** _CFRuntimeCreateInstance() can finally be called generally after this line. ***/
1028 __CFRuntimeClassTableCount
= 7;
1029 __CFStringInitialize(); // CFString's TypeID must be 0x7, now and forever
1031 __CFRuntimeClassTableCount
= 16;
1032 __CFNullInitialize(); // See above for hard-coding of this position
1033 CFSetGetTypeID(); // See above for hard-coding of this position
1034 CFDictionaryGetTypeID(); // See above for hard-coding of this position
1035 __CFArrayInitialize(); // See above for hard-coding of this position
1036 __CFDataInitialize(); // See above for hard-coding of this position
1037 __CFBooleanInitialize(); // See above for hard-coding of this position
1038 __CFNumberInitialize(); // See above for hard-coding of this position
1040 __CFBinaryHeapInitialize();
1041 __CFBitVectorInitialize();
1042 __CFCharacterSetInitialize();
1043 __CFStorageInitialize();
1044 __CFErrorInitialize();
1045 __CFTreeInitialize();
1046 __CFURLInitialize();
1048 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
1049 __CFBundleInitialize();
1051 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1052 __CFPlugInInitialize();
1053 __CFPlugInInstanceInitialize();
1055 __CFUUIDInitialize();
1056 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
1057 __CFMessagePortInitialize();
1059 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1060 __CFMachPortInitialize();
1062 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
1063 __CFStreamInitialize();
1065 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
1066 __CFRunLoopInitialize();
1067 __CFRunLoopObserverInitialize();
1068 __CFRunLoopSourceInitialize();
1069 __CFRunLoopTimerInitialize();
1071 __CFTimeZoneInitialize();
1072 __CFCalendarInitialize();
1073 #if DEPLOYMENT_TARGET_LINUX
1074 __CFTimeZoneInitialize();
1075 __CFCalendarInitialize();
1082 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1083 args
= *_NSGetArgv();
1084 cnt
= *_NSGetArgc();
1085 #elif DEPLOYMENT_TARGET_WINDOWS
1086 wchar_t *commandLine
= GetCommandLineW();
1087 // result is actually pointer to wchar_t *, make sure to account for that below
1088 args
= (char **)CommandLineToArgvW(commandLine
, (int *)&cnt
);
1091 CFStringRef
*list
, buffer
[256];
1092 list
= (cnt
<= 256) ? buffer
: (CFStringRef
*)malloc(cnt
* sizeof(CFStringRef
));
1093 for (idx
= 0, count
= 0; idx
< cnt
; idx
++) {
1094 if (NULL
== args
[idx
]) continue;
1095 #if DEPLOYMENT_TARGET_WINDOWS
1096 list
[count
] = CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)args
[idx
], wcslen((wchar_t *)args
[idx
]));
1098 list
[count
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, args
[idx
], kCFStringEncodingUTF8
);
1099 if (NULL
== list
[count
]) {
1100 list
[count
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, args
[idx
], kCFStringEncodingISOLatin1
);
1101 // We CANNOT use the string SystemEncoding here;
1102 // Do not argue: it is not initialized yet, but these
1103 // arguments MUST be initialized before it is.
1104 // We should just ignore the argument if the UTF-8
1105 // conversion fails, but out of charity we try once
1106 // more with ISO Latin1, a standard unix encoding.
1109 if (NULL
!= list
[count
]) count
++;
1111 __CFArgStuff
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)list
, count
, &kCFTypeArrayCallBacks
);
1112 if (list
!= buffer
) free(list
);
1113 #if DEPLOYMENT_TARGET_WINDOWS
1118 _CFProcessPath(); // cache this early
1121 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1125 if (__CFRuntimeClassTableCount
< 256) __CFRuntimeClassTableCount
= 256;
1128 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED)
1129 CFLog(kCFLogLevelWarning
, CFSTR("Assertions enabled"));
1132 __CFProphylacticAutofsAccess
= false;
1133 __CFInitializing
= 0;
1134 __CFInitialized
= 1;
1139 #if DEPLOYMENT_TARGET_WINDOWS
1141 static CFBundleRef
RegisterCoreFoundationBundle(void) {
1143 // might be nice to get this from the project file at some point
1144 wchar_t *DLLFileName
= (wchar_t *)L
"CoreFoundation_debug.dll";
1146 wchar_t *DLLFileName
= (wchar_t *)L
"CoreFoundation.dll";
1148 wchar_t path
[MAX_PATH
+1];
1149 path
[0] = path
[1] = 0;
1152 HMODULE ourModule
= GetModuleHandleW(DLLFileName
);
1154 CFAssert(ourModule
, __kCFLogAssertion
, "GetModuleHandle failed");
1156 wResult
= GetModuleFileNameW(ourModule
, path
, MAX_PATH
+1);
1157 CFAssert1(wResult
> 0, __kCFLogAssertion
, "GetModuleFileName failed: %d", GetLastError());
1158 CFAssert1(wResult
< MAX_PATH
+1, __kCFLogAssertion
, "GetModuleFileName result truncated: %s", path
);
1160 // strip off last component, the DLL name
1161 for (idx
= wResult
- 1; idx
; idx
--) {
1162 if ('\\' == path
[idx
]) {
1168 CFStringRef fsPath
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)path
, idx
);
1169 CFURLRef dllURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, fsPath
, kCFURLWindowsPathStyle
, TRUE
);
1170 CFURLRef bundleURL
= CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault
, dllURL
, CFSTR("CoreFoundation.resources"), TRUE
);
1174 // this registers us so subsequent calls to CFBundleGetBundleWithIdentifier will succeed
1175 CFBundleRef bundle
= CFBundleCreate(kCFAllocatorSystemDefault
, bundleURL
);
1176 CFRelease(bundleURL
);
1182 #define DLL_PROCESS_ATTACH 1
1183 #define DLL_THREAD_ATTACH 2
1184 #define DLL_THREAD_DETACH 3
1185 #define DLL_PROCESS_DETACH 0
1187 int DllMain( HINSTANCE hInstance
, DWORD dwReason
, LPVOID pReserved
) {
1188 static CFBundleRef cfBundle
= NULL
;
1189 if (dwReason
== DLL_PROCESS_ATTACH
) {
1191 cfBundle
= RegisterCoreFoundationBundle();
1192 } else if (dwReason
== DLL_PROCESS_DETACH
&& pReserved
== 0) {
1193 // Only cleanup if we are being unloaded dynamically (pReserved == 0) <rdar://problem/7480873>
1194 __CFStreamCleanup();
1195 __CFSocketCleanup();
1196 __CFUniCharCleanup();
1198 #if DEPLOYMENT_TARGET_WINDOWS
1199 // No CF functions should access TSD after this is called
1200 __CFTSDWindowsCleanup();
1204 if (cfBundle
) CFRelease(cfBundle
);
1205 __CFStringCleanup();
1206 } else if (dwReason
== DLL_THREAD_DETACH
) {
1207 __CFFinalizeWindowsThreadData();
1214 #if __CF_BIG_ENDIAN__
1215 #define RC_INCREMENT (1ULL)
1216 #define RC_MASK (0xFFFFFFFFULL)
1217 #define RC_GET(V) ((V) & RC_MASK)
1218 #define RC_DEALLOCATING_BIT (0x400000ULL << 32)
1220 #define RC_INCREMENT (1ULL << 32)
1221 #define RC_MASK (0xFFFFFFFFULL << 32)
1222 #define RC_GET(V) (((V) & RC_MASK) >> 32)
1223 #define RC_DEALLOCATING_BIT (0x400000ULL)
1226 #if COCOA_ARR1 && __LP64__
1227 static bool (*CAS64
)(int64_t, int64_t, volatile int64_t *) = OSAtomicCompareAndSwap64Barrier
;
1229 static bool (*CAS32
)(int32_t, int32_t, volatile int32_t *) = OSAtomicCompareAndSwap32Barrier
;
1232 // For "tryR==true", a return of NULL means "failed".
1233 static CFTypeRef
_CFRetain(CFTypeRef cf
, Boolean tryR
) {
1234 uint32_t cfinfo
= *(uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1235 if (cfinfo
& 0x800000) { // custom ref counting for object
1236 if (tryR
) return NULL
;
1237 CFTypeID typeID
= (cfinfo
>> 8) & 0x03FF; // mask up to 0x0FFF
1238 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1239 uint32_t (*refcount
)(intptr_t, CFTypeRef
) = cfClass
->refcount
;
1240 if (!refcount
|| !(cfClass
->version
& _kCFRuntimeCustomRefCount
) || (((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
] != 0xFF)) {
1241 HALT
; // bogus object
1244 if (((CFRuntimeBase
*)cf
)->_rc
!= 0xFFFFFFFFU
) {
1245 HALT
; // bogus object
1252 Boolean didAuto
= false;
1254 if (0 == ((CFRuntimeBase
*)cf
)->_rc
&& !CF_IS_COLLECTABLE(cf
)) return cf
; // Constant CFTypeRef
1258 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1259 if (tryR
&& (allBits
& RC_DEALLOCATING_BIT
)) return NULL
;
1260 } while (!CAS64(allBits
, allBits
+ RC_INCREMENT
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
));
1261 // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1262 if (RC_GET(allBits
) == 0 && CF_IS_COLLECTABLE(cf
)) {
1263 auto_zone_retain(objc_collectableZone(), (void*)cf
);
1269 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
1270 } while (!CAS32(lowBits
, lowBits
+ 1, (int32_t *)&((CFRuntimeBase
*)cf
)->_rc
));
1271 // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1272 if (lowBits
== 0 && CF_IS_COLLECTABLE(cf
)) {
1273 auto_zone_retain(objc_collectableZone(), (void*)cf
);
1280 volatile uint32_t *infoLocation
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1281 CFIndex rcLowBits
= __CFBitfieldGetValue(cfinfo
, RC_END
, RC_START
);
1282 if (__builtin_expect(0 == rcLowBits
, 0) && !CF_IS_COLLECTABLE(cf
)) return cf
; // Constant CFTypeRef
1285 cfinfo
= *infoLocation
;
1287 // if already deallocating, don't allow new retain
1288 if (tryR
&& (cfinfo
& 0x400000)) return NULL
;
1290 uint32_t prospectiveNewInfo
= cfinfo
; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1291 prospectiveNewInfo
+= (1 << RC_START
);
1292 rcLowBits
= __CFBitfieldGetValue(prospectiveNewInfo
, RC_END
, RC_START
);
1293 if (__builtin_expect((rcLowBits
& 0x7f) == 0, 0)) {
1294 /* Roll over another bit to the external ref count
1295 Real ref count = low 7 bits of info[CF_RC_BITS] + external ref count << 6
1296 Bit 8 of low bits indicates that external ref count is in use.
1297 External ref count is shifted by 6 rather than 7 so that we can set the low
1298 bits to to 1100 0000 rather than 1000 0000.
1299 This prevents needing to access the external ref count for successive retains and releases
1300 when the composite retain count is right around a multiple of 1 << 7.
1302 prospectiveNewInfo
= cfinfo
;
1303 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, ((1 << 7) | (1 << 6)));
1304 __CFSpinLock(&__CFRuntimeExternRefCountTableLock
);
1305 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1306 if (__builtin_expect(success
, 1)) {
1307 __CFDoExternRefOperation(350, (id
)cf
);
1309 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock
);
1311 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1312 // XXX_PCB: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1313 if (success
&& __CFBitfieldGetValue(cfinfo
, RC_END
, RC_START
) == 0 && CF_IS_COLLECTABLE(cf
)) {
1314 auto_zone_retain(objc_collectableZone(), (void*)cf
);
1318 } while (__builtin_expect(!success
, 0));
1320 if (!didAuto
&& __builtin_expect(__CFOASafe
, 0)) {
1321 __CFRecordAllocationEvent(__kCFRetainEvent
, (void *)cf
, 0, CFGetRetainCount(cf
), NULL
);
1326 // Never called under GC, only called via ARR weak subsystem; a return of NULL is failure
1327 CFTypeRef
_CFTryRetain(CFTypeRef cf
) {
1328 if (NULL
== cf
) return NULL
;
1329 return _CFRetain(cf
, true);
1332 Boolean
_CFIsDeallocating(CFTypeRef cf
) {
1333 if (NULL
== cf
) return false;
1334 uint32_t cfinfo
= *(uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1335 if (cfinfo
& 0x800000) { // custom ref counting for object
1336 return true; // lie for now; this weak references to these objects cannot be formed
1338 return (cfinfo
& 0x400000) ? true : false;
1341 static void _CFRelease(CFTypeRef cf
) {
1343 uint32_t cfinfo
= *(uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1344 CFTypeID typeID
= (cfinfo
>> 8) & 0x03FF; // mask up to 0x0FFF
1345 if (cfinfo
& 0x800000) { // custom ref counting for object
1346 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1347 uint32_t (*refcount
)(intptr_t, CFTypeRef
) = cfClass
->refcount
;
1348 if (!refcount
|| !(cfClass
->version
& _kCFRuntimeCustomRefCount
) || (((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
] != 0xFF)) {
1349 HALT
; // bogus object
1352 if (((CFRuntimeBase
*)cf
)->_rc
!= 0xFFFFFFFFU
) {
1353 HALT
; // bogus object
1360 Boolean isAllocator
= (__kCFAllocatorTypeID_CONST
== typeID
);
1361 Boolean didAuto
= false;
1368 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1369 lowBits
= RC_GET(allBits
);
1371 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(objc_collectableZone(), (void*)cf
);
1372 return; // Constant CFTypeRef
1375 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1376 if ((cfClass
->version
& _kCFRuntimeResourcefulObject
) && cfClass
->reclaim
!= NULL
) {
1377 cfClass
->reclaim(cf
);
1379 if (!CF_IS_COLLECTABLE(cf
)) {
1380 uint64_t newAllBits
= allBits
| RC_DEALLOCATING_BIT
;
1381 if (!CAS64(allBits
, newAllBits
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
)) {
1384 allBits
= newAllBits
;
1385 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1389 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1390 lowBits
= RC_GET(allBits
);
1391 if (isAllocator
|| ((1 == lowBits
) && CAS64(allBits
, allBits
- RC_INCREMENT
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
))) {
1394 Boolean success
= false;
1395 do { // drop the deallocating bit; racey, but this resurrection stuff isn't thread-safe anyway
1396 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1397 uint64_t newAllBits
= allBits
& ~RC_DEALLOCATING_BIT
;
1398 success
= CAS64(allBits
, newAllBits
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
);
1400 goto again
; // still need to have the effect of a CFRelease
1403 } while (!CAS64(allBits
, allBits
- RC_INCREMENT
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
));
1404 if (lowBits
== 1 && CF_IS_COLLECTABLE(cf
)) {
1405 // GC: release the collector's hold over the object, which will call the finalize function later on.
1406 auto_zone_release(objc_collectableZone(), (void*)cf
);
1412 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
1414 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(objc_collectableZone(), (void*)cf
);
1415 return; // Constant CFTypeRef
1418 // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION
1419 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1420 if ((cfClass
->version
& _kCFRuntimeResourcefulObject
) && cfClass
->reclaim
!= NULL
) {
1421 cfClass
->reclaim(cf
);
1423 if (!CF_IS_COLLECTABLE(cf
)) {
1424 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1428 if (isAllocator
|| CAS32(1, 0, (int32_t *)&((CFRuntimeBase
*)cf
)->_rc
)) {
1433 } while (!CAS32(lowBits
, lowBits
- 1, (int32_t *)&((CFRuntimeBase
*)cf
)->_rc
));
1434 if (lowBits
== 1 && CF_IS_COLLECTABLE(cf
)) {
1435 // GC: release the collector's hold over the object, which will call the finalize function later on.
1436 auto_zone_release(objc_collectableZone(), (void*)cf
);
1443 volatile uint32_t *infoLocation
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1444 CFIndex rcLowBits
= __CFBitfieldGetValue(cfinfo
, RC_END
, RC_START
);
1445 if (__builtin_expect(0 == rcLowBits
, 0)) {
1446 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(objc_collectableZone(), (void*)cf
);
1447 return; // Constant CFTypeRef
1450 Boolean whack
= false;
1452 cfinfo
= *infoLocation
;
1453 rcLowBits
= __CFBitfieldGetValue(cfinfo
, RC_END
, RC_START
);
1454 if (__builtin_expect(1 == rcLowBits
, 0)) {
1455 // we think cf should be deallocated
1456 uint32_t prospectiveNewInfo
= cfinfo
| (0x400000);
1457 if (CF_IS_COLLECTABLE(cf
)) {
1458 prospectiveNewInfo
-= (1 << RC_START
);
1460 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1461 if (success
) whack
= true;
1464 uint32_t prospectiveNewInfo
= cfinfo
; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1465 if (__builtin_expect((1 << 7) == rcLowBits
, 0)) {
1466 // Time to remove a bit from the external ref count
1467 __CFSpinLock(&__CFRuntimeExternRefCountTableLock
);
1468 CFIndex rcHighBitsCnt
= __CFDoExternRefOperation(500, (id
)cf
);
1469 if (1 == rcHighBitsCnt
) {
1470 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, (1 << 6) - 1);
1472 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, ((1 << 6) | (1 << 7)) - 1);
1474 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1475 if (__builtin_expect(success
, 1)) {
1476 __CFDoExternRefOperation(450, (id
)cf
);
1478 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock
);
1480 prospectiveNewInfo
-= (1 << RC_START
);
1481 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1484 } while (__builtin_expect(!success
, 0));
1487 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1488 if ((cfClass
->version
& _kCFRuntimeResourcefulObject
) && cfClass
->reclaim
!= NULL
) {
1489 cfClass
->reclaim(cf
);
1491 if (CF_IS_COLLECTABLE(cf
)) {
1492 // GC: release the collector's hold over the object, which will call the finalize function later on.
1493 auto_zone_release(objc_collectableZone(), (void*)cf
);
1499 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1503 rcLowBits
= __CFBitfieldGetValue(*infoLocation
, RC_END
, RC_START
);
1504 if (1 == rcLowBits
) {
1507 do { // drop the deallocating bit; racey, but this resurrection stuff isn't thread-safe anyway
1508 cfinfo
= *infoLocation
;
1509 uint32_t prospectiveNewInfo
= (cfinfo
& ~(0x400000));
1510 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1517 volatile uint32_t *infoLocation
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1518 CFIndex rcLowBits
= __CFBitfieldGetValue(*infoLocation
, RC_END
, RC_START
);
1519 if (__builtin_expect(0 == rcLowBits
, 0)) {
1520 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(objc_collectableZone(), (void*)cf
);
1521 return; // Constant CFTypeRef
1525 uint32_t initialCheckInfo
= *infoLocation
;
1526 rcLowBits
= __CFBitfieldGetValue(initialCheckInfo
, RC_END
, RC_START
);
1527 if (__builtin_expect(1 == rcLowBits
, 0)) {
1528 // we think cf should be deallocated
1529 // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION
1530 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1531 if ((cfClass
->version
& _kCFRuntimeResourcefulObject
) && cfClass
->reclaim
!= NULL
) {
1532 cfClass
->reclaim(cf
);
1534 if (CF_IS_COLLECTABLE(cf
)) {
1535 uint32_t prospectiveNewInfo
= initialCheckInfo
- (1 << RC_START
);
1536 success
= CAS32(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1537 // GC: release the collector's hold over the object, which will call the finalize function later on.
1539 auto_zone_release(objc_collectableZone(), (void*)cf
);
1546 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1550 // We recheck rcLowBits to see if the object has been retained again during
1551 // the finalization process. This allows for the finalizer to resurrect,
1552 // but the main point is to allow finalizers to be able to manage the
1553 // removal of objects from uniquing caches, which may race with other threads
1554 // which are allocating (looking up and finding) objects from those caches,
1555 // which (that thread) would be the thing doing the extra retain in that case.
1556 rcLowBits
= __CFBitfieldGetValue(*infoLocation
, RC_END
, RC_START
);
1557 success
= (1 == rcLowBits
);
1558 if (__builtin_expect(success
, 1)) {
1565 uint32_t prospectiveNewInfo
= initialCheckInfo
; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1566 if (__builtin_expect((1 << 7) == rcLowBits
, 0)) {
1567 // Time to remove a bit from the external ref count
1568 __CFSpinLock(&__CFRuntimeExternRefCountTableLock
);
1569 CFIndex rcHighBitsCnt
= __CFDoExternRefOperation(500, (id
)cf
);
1570 if (1 == rcHighBitsCnt
) {
1571 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, (1 << 6) - 1);
1573 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, ((1 << 6) | (1 << 7)) - 1);
1575 success
= CAS32(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1576 if (__builtin_expect(success
, 1)) {
1577 __CFDoExternRefOperation(450, (id
)cf
);
1579 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock
);
1581 prospectiveNewInfo
-= (1 << RC_START
);
1582 success
= CAS32(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1585 } while (__builtin_expect(!success
, 0));
1588 if (!didAuto
&& __builtin_expect(__CFOASafe
, 0)) {
1589 __CFRecordAllocationEvent(__kCFReleaseEvent
, (void *)cf
, 0, CFGetRetainCount(cf
), NULL
);
1594 if (!didAuto
&& __builtin_expect(__CFOASafe
, 0)) {
1595 // do not use CFGetRetainCount() because cf has been freed if it was an allocator
1596 __CFRecordAllocationEvent(__kCFReleaseEvent
, (void *)cf
, 0, 0, NULL
);
1598 // cannot zombify allocators, which get deallocated by __CFAllocatorDeallocate (finalize)
1600 __CFAllocatorDeallocate((void *)cf
);
1602 CFAllocatorRef allocator
= kCFAllocatorSystemDefault
;
1603 Boolean usesSystemDefaultAllocator
= true;
1605 if (!__CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 7, 7)) {
1606 allocator
= CFGetAllocator(cf
);
1607 usesSystemDefaultAllocator
= _CFAllocatorIsSystemDefault(allocator
);
1611 CFAllocatorDeallocate(allocator
, (uint8_t *)cf
- (usesSystemDefaultAllocator
? 0 : sizeof(CFAllocatorRef
)));
1614 if (kCFAllocatorSystemDefault
!= allocator
) {
1615 CFRelease(allocator
);
1620 #undef __kCFAllocatorTypeID_CONST
1621 #undef __CFGenericAssertIsCF