2 * Copyright (c) 2014 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-2013, 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 CF_PRIVATE
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 CF_PRIVATE CFRuntimeClass
* __CFRuntimeClassTable
[__CFRuntimeClassTableSize
] = {0};
203 CF_PRIVATE
int32_t __CFRuntimeClassTableCount
= 0;
205 CF_PRIVATE
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 CF_PRIVATE
uint8_t __CFZombieEnabled
= 0;
270 CF_PRIVATE
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
&& (0 || 0)) {
303 CFLog(kCFLogLevelWarning
, CFSTR("*** _CFRuntimeCreateInstance(): special zero-ref allocators cannot be used with class '%s' with custom ref counting."), cls
->className
);
306 CFAllocatorRef realAllocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : 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
));
335 if (!kCFUseCollectableAllocator
|| (1 && 1)) {
339 memory
->_rc
= 0xFFFFFFFFU
;
343 if (!kCFUseCollectableAllocator
|| (1 && 1)) {
350 uint32_t *cfinfop
= (uint32_t *)&(memory
->_cfinfo
);
351 *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 uint32_t *cfinfop
= (uint32_t *)&(memory
->_cfinfo
);
370 *cfinfop
= (uint32_t)(((customRC
? 0xFF : 0) << 24) | (customRC
? 0x800000 : 0x0) | ((uint32_t)typeID
<< 8) | 0x80);
372 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);
400 CF_PRIVATE
void _CFRuntimeSetInstanceTypeIDAndIsa(CFTypeRef cf
, CFTypeID newTypeID
) {
401 _CFRuntimeSetInstanceTypeID(cf
, newTypeID
);
406 __kCFObjectRetainedEvent
= 12,
407 __kCFObjectReleasedEvent
= 13
410 #if DEPLOYMENT_TARGET_MACOSX
411 #define NUM_EXTERN_TABLES 8
412 #define EXTERN_TABLE_IDX(O) (((uintptr_t)(O) >> 8) & 0x7)
413 #elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
414 #define NUM_EXTERN_TABLES 1
415 #define EXTERN_TABLE_IDX(O) 0
420 // we disguise pointers so that programs like 'leaks' forget about these references
421 #define DISGUISE(O) (~(uintptr_t)(O))
425 CFBasicHashRef table
;
426 uint8_t padding
[64 - sizeof(CFBasicHashRef
) - sizeof(CFSpinLock_t
)];
427 } __NSRetainCounters
[NUM_EXTERN_TABLES
];
429 CF_EXPORT
uintptr_t __CFDoExternRefOperation(uintptr_t op
, id obj
) {
430 if (nil
== obj
) HALT
;
431 uintptr_t idx
= EXTERN_TABLE_IDX(obj
);
432 uintptr_t disguised
= DISGUISE(obj
);
433 CFSpinLock_t
*lock
= &__NSRetainCounters
[idx
].lock
;
434 CFBasicHashRef table
= __NSRetainCounters
[idx
].table
;
437 case 300: // increment
438 case 350: // increment, no event
440 CFBasicHashAddValue(table
, disguised
, disguised
);
441 __CFSpinUnlock(lock
);
442 if (__CFOASafe
&& op
!= 350) __CFRecordAllocationEvent(__kCFObjectRetainedEvent
, obj
, 0, 0, NULL
);
443 return (uintptr_t)obj
;
444 case 400: // decrement
445 if (__CFOASafe
) __CFRecordAllocationEvent(__kCFObjectReleasedEvent
, obj
, 0, 0, NULL
);
446 case 450: // decrement, no event
448 count
= (uintptr_t)CFBasicHashRemoveValue(table
, disguised
);
449 __CFSpinUnlock(lock
);
453 count
= (uintptr_t)CFBasicHashGetCountOfKey(table
, disguised
);
454 __CFSpinUnlock(lock
);
460 CF_EXPORT CFTypeID
CFNumberGetTypeID(void);
462 CF_INLINE CFTypeID
__CFGenericTypeID_inline(const void *cf
) {
463 // yes, 10 bits masked off, though 12 bits are there for the type field; __CFRuntimeClassTableSize is 1024
464 uint32_t *cfinfop
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
465 CFTypeID typeID
= (*cfinfop
>> 8) & 0x03FF; // mask up to 0x0FFF
469 CFTypeID
__CFGenericTypeID(const void *cf
) {
470 return __CFGenericTypeID_inline(cf
);
473 CFTypeID
CFTypeGetTypeID(void) {
474 return __kCFTypeTypeID
;
477 CF_PRIVATE
void __CFGenericValidateType_(CFTypeRef cf
, CFTypeID type
, const char *func
) {
478 if (cf
&& CF_IS_OBJC(type
, cf
)) return;
479 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
); \
480 CFAssert3(__CFGenericTypeID_inline(cf
) == type
, __kCFLogAssertion
, "%s(): pointer %p is not a %s", func
, cf
, __CFRuntimeClassTable
[type
]->className
); \
483 #define __CFGenericAssertIsCF(cf) \
484 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);
487 #define CFTYPE_IS_OBJC(obj) (false)
488 #define CFTYPE_OBJC_FUNCDISPATCH0(rettype, obj, sel) do {} while (0)
489 #define CFTYPE_OBJC_FUNCDISPATCH1(rettype, obj, sel, a1) do {} while (0)
492 CFTypeID
CFGetTypeID(CFTypeRef cf
) {
494 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFGetTypeID() called with NULL ***"); HALT
; }
496 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeID
, cf
, _cfTypeID
);
497 __CFGenericAssertIsCF(cf
);
498 return __CFGenericTypeID_inline(cf
);
501 CFStringRef
CFCopyTypeIDDescription(CFTypeID type
) {
502 CFAssert2((NULL
!= __CFRuntimeClassTable
[type
]) && __kCFNotATypeTypeID
!= type
&& __kCFTypeTypeID
!= type
, __kCFLogAssertion
, "%s(): type %d is not a CF type ID", __PRETTY_FUNCTION__
, type
);
503 return CFStringCreateWithCString(kCFAllocatorSystemDefault
, __CFRuntimeClassTable
[type
]->className
, kCFStringEncodingASCII
);
506 // Bit 31 (highest bit) in second word of cf instance indicates external ref count
508 static CFTypeRef
_CFRetain(CFTypeRef cf
, Boolean tryR
);
510 CFTypeRef
CFRetain(CFTypeRef cf
) {
511 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFRetain() called with NULL ***"); HALT
; }
512 if (cf
) __CFGenericAssertIsCF(cf
);
513 return _CFRetain(cf
, false);
516 CFTypeRef
CFAutorelease(CFTypeRef
__attribute__((cf_consumed
)) cf
) {
517 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFAutorelease() called with NULL ***"); HALT
; }
521 static void _CFRelease(CFTypeRef cf
);
523 void CFRelease(CFTypeRef cf
) {
524 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFRelease() called with NULL ***"); HALT
; }
526 void **addrs
[2] = {&&start
, &&end
};
528 if (addrs
[0] <= __builtin_return_address(0) && __builtin_return_address(0) <= addrs
[1]) {
529 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]);
533 if (cf
) __CFGenericAssertIsCF(cf
);
541 CF_PRIVATE
void __CFAllocatorDeallocate(CFTypeRef cf
);
543 CF_PRIVATE
const void *__CFStringCollectionCopy(CFAllocatorRef allocator
, const void *ptr
) {
544 if (NULL
== ptr
) { CRSetCrashLogMessage("*** __CFStringCollectionCopy() called with NULL ***"); HALT
; }
545 CFStringRef theString
= (CFStringRef
)ptr
;
546 CFStringRef result
= CFStringCreateCopy((allocator
), theString
);
547 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
548 result
= (CFStringRef
)CFMakeCollectable(result
);
550 return (const void *)result
;
553 extern void CFCollection_non_gc_storage_error(void);
555 CF_PRIVATE
const void *__CFTypeCollectionRetain(CFAllocatorRef allocator
, const void *ptr
) {
556 if (NULL
== ptr
) { CRSetCrashLogMessage("*** __CFTypeCollectionRetain() called with NULL; likely a collection has been corrupted ***"); HALT
; }
557 CFTypeRef cf
= (CFTypeRef
)ptr
;
558 // only collections allocated in the GC zone can opt-out of reference counting.
559 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
560 if (CFTYPE_IS_OBJC(cf
)) return cf
; // do nothing for OBJC objects.
561 if (auto_zone_is_valid_pointer(objc_collectableZone(), ptr
)) {
562 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)];
563 if (cfClass
->version
& _kCFRuntimeResourcefulObject
) {
564 // GC: If this a CF object in the GC heap that is marked resourceful, then
565 // it must be retained keep it alive in a CF collection.
569 ; // don't retain normal CF objects
572 // support constant CFTypeRef objects.
574 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
576 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
];
578 if (lowBits
== 0) return cf
;
579 // complain about non-GC objects in GC containers.
580 CFLog(kCFLogLevelWarning
, CFSTR("storing a non-GC object %p in a GC collection, break on CFCollection_non_gc_storage_error to debug."), cf
);
581 CFCollection_non_gc_storage_error();
582 // XXX should halt, except Patrick is using this somewhere.
590 CF_PRIVATE
void __CFTypeCollectionRelease(CFAllocatorRef allocator
, const void *ptr
) {
591 if (NULL
== ptr
) { CRSetCrashLogMessage("*** __CFTypeCollectionRelease() called with NULL; likely a collection has been corrupted ***"); HALT
; }
592 CFTypeRef cf
= (CFTypeRef
)ptr
;
593 // only collections allocated in the GC zone can opt-out of reference counting.
594 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
595 if (CFTYPE_IS_OBJC(cf
)) return; // do nothing for OBJC objects.
596 if (auto_zone_is_valid_pointer(objc_collectableZone(), cf
)) {
597 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
598 // GC: If this a CF object in the GC heap that is marked uncollectable, then
599 // must balance the retain done in __CFTypeCollectionRetain().
600 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)];
601 if (cfClass
->version
& _kCFRuntimeResourcefulObject
) {
602 // reclaim is called by _CFRelease(), which must be called to keep the
603 // CF and GC retain counts in sync.
606 // avoid releasing normal CF objects. Like other collections, for example
611 // support constant CFTypeRef objects.
613 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
615 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
];
617 if (lowBits
== 0) return;
624 static CFSpinLock_t __CFRuntimeExternRefCountTableLock
= CFSpinLockInit
;
627 static uint64_t __CFGetFullRetainCount(CFTypeRef cf
) {
628 if (NULL
== cf
) { CRSetCrashLogMessage("*** __CFGetFullRetainCount() called with NULL ***"); HALT
; }
630 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
632 return (uint64_t)0x0fffffffffffffffULL
;
636 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
];
638 return (uint64_t)0x0fffffffffffffffULL
;
640 uint64_t highBits
= 0;
641 if ((lowBits
& 0x80) != 0) {
642 highBits
= __CFDoExternRefOperation(500, (id
)cf
);
644 uint64_t compositeRC
= (lowBits
& 0x7f) + (highBits
<< 6);
649 CFIndex
CFGetRetainCount(CFTypeRef cf
) {
650 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFGetRetainCount() called with NULL ***"); HALT
; }
651 uint32_t cfinfo
= *(uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
652 if (cfinfo
& 0x800000) { // custom ref counting for object
653 CFTypeID typeID
= (cfinfo
>> 8) & 0x03FF; // mask up to 0x0FFF
654 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
655 uint32_t (*refcount
)(intptr_t, CFTypeRef
) = cfClass
->refcount
;
656 if (!refcount
|| !(cfClass
->version
& _kCFRuntimeCustomRefCount
) || (((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
] != 0xFF)) {
657 HALT
; // bogus object
660 if (((CFRuntimeBase
*)cf
)->_rc
!= 0xFFFFFFFFU
) {
661 HALT
; // bogus object
664 uint32_t rc
= refcount(0, cf
);
668 return (rc
< LONG_MAX
) ? (CFIndex
)rc
: (CFIndex
)LONG_MAX
;
671 uint64_t rc
= __CFGetFullRetainCount(cf
);
672 return (rc
< (uint64_t)LONG_MAX
) ? (CFIndex
)rc
: (CFIndex
)LONG_MAX
;
675 CFTypeRef
CFMakeCollectable(CFTypeRef cf
) {
676 if (NULL
== cf
) return NULL
;
680 CFTypeRef
CFMakeUncollectable(CFTypeRef cf
) {
681 if (NULL
== cf
) return NULL
;
682 if (CF_IS_COLLECTABLE(cf
)) {
688 Boolean
CFEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
689 if (NULL
== cf1
) { CRSetCrashLogMessage("*** CFEqual() called with NULL first argument ***"); HALT
; }
690 if (NULL
== cf2
) { CRSetCrashLogMessage("*** CFEqual() called with NULL second argument ***"); HALT
; }
691 if (cf1
== cf2
) return true;
692 CFTYPE_OBJC_FUNCDISPATCH1(Boolean
, cf1
, isEqual
:, cf2
);
693 CFTYPE_OBJC_FUNCDISPATCH1(Boolean
, cf2
, isEqual
:, cf1
);
694 __CFGenericAssertIsCF(cf1
);
695 __CFGenericAssertIsCF(cf2
);
696 if (__CFGenericTypeID_inline(cf1
) != __CFGenericTypeID_inline(cf2
)) return false;
697 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf1
)]->equal
) {
698 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf1
)]->equal(cf1
, cf2
);
703 CFHashCode
CFHash(CFTypeRef cf
) {
704 if (NULL
== cf
) { CRSetCrashLogMessage("*** CFHash() called with NULL ***"); HALT
; }
705 CFTYPE_OBJC_FUNCDISPATCH0(CFHashCode
, cf
, hash
);
706 __CFGenericAssertIsCF(cf
);
707 CFHashCode (*hash
)(CFTypeRef cf
) = __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->hash
;
711 if (CF_IS_COLLECTABLE(cf
)) return (CFHashCode
)_object_getExternalHash((id
)cf
);
712 return (CFHashCode
)cf
;
715 // definition: produces a normally non-NULL debugging description of the object
716 CFStringRef
CFCopyDescription(CFTypeRef cf
) {
717 if (NULL
== cf
) return NULL
;
718 // CFTYPE_OBJC_FUNCDISPATCH0(CFStringRef, cf, _copyDescription); // XXX returns 0 refcounted item under GC
719 __CFGenericAssertIsCF(cf
);
720 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyDebugDesc
) {
721 CFStringRef result
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyDebugDesc(cf
);
722 if (NULL
!= result
) return result
;
724 return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%s %p [%p]>"), __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->className
, cf
, CFGetAllocator(cf
));
727 // Definition: if type produces a formatting description, return that string, otherwise NULL
728 CF_PRIVATE CFStringRef
__CFCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
729 if (NULL
== cf
) return NULL
;
730 __CFGenericAssertIsCF(cf
);
731 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyFormattingDesc
) {
732 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyFormattingDesc(cf
, formatOptions
);
737 extern CFAllocatorRef
__CFAllocatorGetAllocator(CFTypeRef
);
739 CFAllocatorRef
CFGetAllocator(CFTypeRef cf
) {
740 if (NULL
== cf
) return kCFAllocatorSystemDefault
;
741 if (__kCFAllocatorTypeID_CONST
== __CFGenericTypeID_inline(cf
)) {
742 return __CFAllocatorGetAllocator(cf
);
744 return __CFGetAllocator(cf
);
747 extern void __CFNullInitialize(void);
748 extern void __CFAllocatorInitialize(void);
749 extern void __CFStringInitialize(void);
750 extern void __CFArrayInitialize(void);
751 extern void __CFBooleanInitialize(void);
752 extern void __CFCharacterSetInitialize(void);
753 extern void __CFDataInitialize(void);
754 extern void __CFNumberInitialize(void);
755 extern void __CFStorageInitialize(void);
756 extern void __CFErrorInitialize(void);
757 extern void __CFTreeInitialize(void);
758 extern void __CFURLInitialize(void);
759 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
760 extern void __CFMachPortInitialize(void);
762 extern void __CFMessagePortInitialize(void);
763 extern void __CFRunLoopInitialize(void);
764 extern void __CFRunLoopObserverInitialize(void);
765 extern void __CFRunLoopSourceInitialize(void);
766 extern void __CFRunLoopTimerInitialize(void);
767 extern void __CFPFactoryInitialize(void);
768 extern void __CFBundleInitialize(void);
769 extern void __CFPlugInInitialize(void);
770 extern void __CFPlugInInstanceInitialize(void);
771 extern void __CFUUIDInitialize(void);
772 extern void __CFBinaryHeapInitialize(void);
773 extern void __CFBitVectorInitialize(void);
774 CF_PRIVATE
void __CFDateInitialize(void);
775 #if DEPLOYMENT_TARGET_LINUX
776 CF_PRIVATE
void __CFTSDLinuxInitialize();
778 #if DEPLOYMENT_TARGET_WINDOWS
780 CF_PRIVATE
void __CFTSDWindowsInitialize(void);
781 CF_PRIVATE
void __CFTSDWindowsCleanup(void);
782 CF_PRIVATE
void __CFFinalizeWindowsThreadData();
784 extern void __CFStreamInitialize(void);
785 extern void __CFCalendarInitialize();
786 extern void __CFTimeZoneInitialize();
787 #if DEPLOYMENT_TARGET_LINUX
788 extern void __CFCalendarInitialize();
789 extern void __CFTimeZoneInitialize();
791 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
792 extern void __CFXPreferencesInitialize(void);
795 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
796 CF_PRIVATE
uint8_t __CF120290
= false;
797 CF_PRIVATE
uint8_t __CF120291
= false;
798 CF_PRIVATE
uint8_t __CF120293
= false;
799 CF_PRIVATE
char * __crashreporter_info__
= NULL
; // Keep this symbol, since it was exported and other things may be linking against it, like GraphicsServices.framework on iOS
800 asm(".desc ___crashreporter_info__, 0x10");
802 static void __01121__(void) {
803 __CF120291
= pthread_is_threaded_np() ? true : false;
806 static void __01123__(void) {
807 // Ideally, child-side atfork handlers should be async-cancel-safe, as fork()
808 // is async-cancel-safe and can be called from signal handlers. See also
809 // http://standards.ieee.org/reading/ieee/interp/1003-1c-95_int/pasc-1003.1c-37.html
810 // This is not a problem for CF.
813 #if DEPLOYMENT_TARGET_MACOSX
815 CRSetCrashLogMessage2("*** multi-threaded process forked ***");
817 CRSetCrashLogMessage2("*** single-threaded process forked ***");
823 #define EXEC_WARNING_STRING_1 "The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec().\n"
824 #define EXEC_WARNING_STRING_2 "Break on __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__() to debug.\n"
826 CF_PRIVATE
void __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__(void) {
827 write(2, EXEC_WARNING_STRING_1
, sizeof(EXEC_WARNING_STRING_1
) - 1);
828 write(2, EXEC_WARNING_STRING_2
, sizeof(EXEC_WARNING_STRING_2
) - 1);
834 CF_EXPORT
const void *__CFArgStuff
;
835 const void *__CFArgStuff
= NULL
;
836 CF_PRIVATE
void *__CFAppleLanguages
= NULL
;
838 // do not cache CFFIXED_USER_HOME or HOME, there are situations where they can change
852 {"DYLD_IMAGE_SUFFIX", NULL
},
853 {"CFProcessPath", NULL
},
854 {"CFNETWORK_LIBRARY_PATH", NULL
},
855 {"CFUUIDVersionNumber", NULL
},
856 {"CFDebugNamedDataSharing", NULL
},
857 {"CFPropertyListAllowImmutableCollections", NULL
},
858 {"CFBundleUseDYLD", NULL
},
859 {"CFBundleDisableStringsSharing", NULL
},
860 {"CFCharacterSetCheckForExpandedSet", NULL
},
861 {"__CF_DEBUG_EXPANDED_SET", NULL
},
862 {"CFStringDisableROM", NULL
},
863 {"CF_CHARSET_PATH", NULL
},
864 {"__CF_USER_TEXT_ENCODING", NULL
},
865 {"__CFPREFERENCES_AUTOSYNC_INTERVAL", NULL
},
866 {"__CFPREFERENCES_LOG_FAILURES", NULL
},
867 {"CFNumberDisableCache", NULL
},
868 {"__CFPREFERENCES_AVOID_DAEMON", NULL
},
869 {"APPLE_FRAMEWORKS_ROOT", NULL
},
870 {NULL
, NULL
}, // the last one is for optional "COMMAND_MODE" "legacy", do not use this slot, insert before
873 CF_PRIVATE
const char *__CFgetenv(const char *n
) {
874 for (CFIndex idx
= 0; idx
< sizeof(__CFEnv
) / sizeof(__CFEnv
[0]); idx
++) {
875 if (__CFEnv
[idx
].name
&& 0 == strcmp(n
, __CFEnv
[idx
].name
)) return __CFEnv
[idx
].value
;
880 CF_PRIVATE Boolean
__CFProcessIsRestricted() {
884 #if DEPLOYMENT_TARGET_WINDOWS
885 #define kNilPthreadT { nil, nil }
887 #define kNilPthreadT (pthread_t)0
891 #undef kCFUseCollectableAllocator
892 CF_EXPORT
bool kCFUseCollectableAllocator
;
893 bool kCFUseCollectableAllocator
= false;
895 CF_PRIVATE Boolean __CFProphylacticAutofsAccess
= false;
896 CF_PRIVATE Boolean __CFInitializing
= 0;
897 CF_PRIVATE Boolean __CFInitialized
= 0;
899 // move the next 2 lines down into the #if below, and make it static, after Foundation gets off this symbol on other platforms
900 CF_EXPORT pthread_t _CFMainPThread
;
901 pthread_t _CFMainPThread
= kNilPthreadT
;
902 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_IPHONESIMULATOR
904 CF_EXPORT pthread_t
_CF_pthread_main_thread_np(void);
905 pthread_t
_CF_pthread_main_thread_np(void) {
906 return _CFMainPThread
;
908 #define pthread_main_thread_np() _CF_pthread_main_thread_np()
912 #if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
913 static void __CFInitialize(void) __attribute__ ((constructor
));
916 #if DEPLOYMENT_TARGET_WINDOWS
919 void __CFInitialize(void) {
921 if (!__CFInitialized
&& !__CFInitializing
) {
922 __CFInitializing
= 1;
924 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_IPHONESIMULATOR
925 if (!pthread_main_np()) HALT
; // CoreFoundation must be initialized on the main thread
927 // move this next line up into the #if above after Foundation gets off this symbol
928 _CFMainPThread
= pthread_self();
930 #if DEPLOYMENT_TARGET_WINDOWS
931 // Must not call any CF functions
932 __CFTSDWindowsInitialize();
933 #elif DEPLOYMENT_TARGET_LINUX
934 __CFTSDLinuxInitialize();
937 __CFProphylacticAutofsAccess
= true;
939 for (CFIndex idx
= 0; idx
< sizeof(__CFEnv
) / sizeof(__CFEnv
[0]); idx
++) {
940 __CFEnv
[idx
].value
= __CFEnv
[idx
].name
? getenv(__CFEnv
[idx
].name
) : NULL
;
943 #if !defined(kCFUseCollectableAllocator)
944 kCFUseCollectableAllocator
= objc_collectingEnabled();
946 if (kCFUseCollectableAllocator
) {
947 #if !defined(__CFObjCIsCollectable)
948 __CFObjCIsCollectable
= (bool (*)(void *))objc_isAuto
;
951 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
953 __CFStringGetUserDefaultEncoding(&s
, &r
); // force the potential setenv to occur early
954 pthread_atfork(__01121__
, NULL
, __01123__
);
958 memset(__CFRuntimeClassTable
, 0, sizeof(__CFRuntimeClassTable
));
959 memset(__CFRuntimeObjCClassTable
, 0, sizeof(__CFRuntimeObjCClassTable
));
962 /* Here so that two runtime classes get indices 0, 1. */
963 __kCFNotATypeTypeID
= _CFRuntimeRegisterClass(&__CFNotATypeClass
);
964 __kCFTypeTypeID
= _CFRuntimeRegisterClass(&__CFTypeClass
);
966 /* Here so that __kCFAllocatorTypeID gets index 2. */
967 __CFAllocatorInitialize();
969 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
972 char **args
= *_NSGetArgv();
974 for (idx
= 1; idx
< cnt
- 1; idx
++) {
975 if (NULL
== args
[idx
]) continue;
976 if (0 == strcmp(args
[idx
], "-AppleLanguages") && args
[idx
+ 1]) {
977 CFIndex length
= strlen(args
[idx
+ 1]);
978 __CFAppleLanguages
= malloc(length
+ 1);
979 memmove(__CFAppleLanguages
, args
[idx
+ 1], length
+ 1);
987 CFBasicHashGetTypeID();
990 for (CFIndex idx
= 0; idx
< NUM_EXTERN_TABLES
; idx
++) {
991 CFBasicHashCallbacks callbacks
= {NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
992 __NSRetainCounters
[idx
].table
= CFBasicHashCreate(kCFAllocatorSystemDefault
, kCFBasicHashHasCounts
| kCFBasicHashLinearHashing
| kCFBasicHashAggressiveGrowth
, &callbacks
);
993 CFBasicHashSetCapacity(__NSRetainCounters
[idx
].table
, 40);
994 __NSRetainCounters
[idx
].lock
= CFSpinLockInit
;
997 /*** _CFRuntimeCreateInstance() can finally be called generally after this line. ***/
999 __CFRuntimeClassTableCount
= 7;
1000 __CFStringInitialize(); // CFString's TypeID must be 0x7, now and forever
1002 __CFRuntimeClassTableCount
= 16;
1003 __CFNullInitialize(); // See above for hard-coding of this position
1004 CFSetGetTypeID(); // See above for hard-coding of this position
1005 CFDictionaryGetTypeID(); // See above for hard-coding of this position
1006 __CFArrayInitialize(); // See above for hard-coding of this position
1007 __CFDataInitialize(); // See above for hard-coding of this position
1008 __CFBooleanInitialize(); // See above for hard-coding of this position
1009 __CFNumberInitialize(); // See above for hard-coding of this position
1011 __CFBinaryHeapInitialize();
1012 __CFBitVectorInitialize();
1013 __CFCharacterSetInitialize();
1014 __CFStorageInitialize();
1015 __CFErrorInitialize();
1016 __CFTreeInitialize();
1017 __CFURLInitialize();
1019 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
1020 __CFBundleInitialize();
1021 __CFPFactoryInitialize();
1023 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1024 __CFPlugInInitialize();
1025 __CFPlugInInstanceInitialize();
1027 __CFUUIDInitialize();
1028 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
1029 __CFMessagePortInitialize();
1031 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1032 __CFMachPortInitialize();
1034 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
1035 __CFStreamInitialize();
1037 #if DEPLOYMENT_TARGET_WINDOWS
1038 __CFWindowsNamedPipeInitialize();
1041 __CFDateInitialize();
1043 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
1044 __CFRunLoopInitialize();
1045 __CFRunLoopObserverInitialize();
1046 __CFRunLoopSourceInitialize();
1047 __CFRunLoopTimerInitialize();
1049 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1050 __CFTimeZoneInitialize();
1051 __CFCalendarInitialize();
1052 #if DEPLOYMENT_TARGET_LINUX
1053 __CFTimeZoneInitialize();
1054 __CFCalendarInitialize();
1059 CFIndex idx
, cnt
= 0;
1061 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1062 args
= *_NSGetArgv();
1063 cnt
= *_NSGetArgc();
1064 #elif DEPLOYMENT_TARGET_WINDOWS
1065 wchar_t *commandLine
= GetCommandLineW();
1066 // result is actually pointer to wchar_t *, make sure to account for that below
1067 args
= (char **)CommandLineToArgvW(commandLine
, (int *)&cnt
);
1070 CFStringRef
*list
, buffer
[256];
1071 list
= (cnt
<= 256) ? buffer
: (CFStringRef
*)malloc(cnt
* sizeof(CFStringRef
));
1072 for (idx
= 0, count
= 0; idx
< cnt
; idx
++) {
1073 if (NULL
== args
[idx
]) continue;
1074 #if DEPLOYMENT_TARGET_WINDOWS
1075 list
[count
] = CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (const UniChar
*)args
[idx
], wcslen((wchar_t *)args
[idx
]));
1077 list
[count
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, args
[idx
], kCFStringEncodingUTF8
);
1078 if (NULL
== list
[count
]) {
1079 list
[count
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, args
[idx
], kCFStringEncodingISOLatin1
);
1080 // We CANNOT use the string SystemEncoding here;
1081 // Do not argue: it is not initialized yet, but these
1082 // arguments MUST be initialized before it is.
1083 // We should just ignore the argument if the UTF-8
1084 // conversion fails, but out of charity we try once
1085 // more with ISO Latin1, a standard unix encoding.
1088 if (NULL
!= list
[count
]) count
++;
1090 __CFArgStuff
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)list
, count
, &kCFTypeArrayCallBacks
);
1091 if (list
!= buffer
) free(list
);
1092 #if DEPLOYMENT_TARGET_WINDOWS
1097 _CFProcessPath(); // cache this early
1102 if (__CFRuntimeClassTableCount
< 256) __CFRuntimeClassTableCount
= 256;
1105 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
1106 const char *value
= __CFgetenv("NSZombieEnabled");
1107 if (value
&& (*value
== 'Y' || *value
== 'y')) _CFEnableZombies();
1108 value
= __CFgetenv("NSDeallocateZombies");
1109 if (value
&& (*value
== 'Y' || *value
== 'y')) __CFDeallocateZombies
= 0xff;
1112 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED)
1113 CFLog(kCFLogLevelWarning
, CFSTR("Assertions enabled"));
1116 __CFProphylacticAutofsAccess
= false;
1117 __CFInitializing
= 0;
1118 __CFInitialized
= 1;
1123 #if DEPLOYMENT_TARGET_WINDOWS
1125 CF_PRIVATE
void __CFStringCleanup(void);
1126 CF_PRIVATE
void __CFSocketCleanup(void);
1127 CF_PRIVATE
void __CFUniCharCleanup(void);
1128 CF_PRIVATE
void __CFStreamCleanup(void);
1130 static CFBundleRef
RegisterCoreFoundationBundle(void) {
1132 // might be nice to get this from the project file at some point
1133 wchar_t *DLLFileName
= (wchar_t *)L
"CoreFoundation_debug.dll";
1135 wchar_t *DLLFileName
= (wchar_t *)L
"CoreFoundation.dll";
1137 wchar_t path
[MAX_PATH
+1];
1138 path
[0] = path
[1] = 0;
1141 HMODULE ourModule
= GetModuleHandleW(DLLFileName
);
1143 CFAssert(ourModule
, __kCFLogAssertion
, "GetModuleHandle failed");
1145 wResult
= GetModuleFileNameW(ourModule
, path
, MAX_PATH
+1);
1146 CFAssert1(wResult
> 0, __kCFLogAssertion
, "GetModuleFileName failed: %d", GetLastError());
1147 CFAssert1(wResult
< MAX_PATH
+1, __kCFLogAssertion
, "GetModuleFileName result truncated: %s", path
);
1149 // strip off last component, the DLL name
1150 for (idx
= wResult
- 1; idx
; idx
--) {
1151 if ('\\' == path
[idx
]) {
1157 CFStringRef fsPath
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)path
, idx
);
1158 CFURLRef dllURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, fsPath
, kCFURLWindowsPathStyle
, TRUE
);
1159 CFURLRef bundleURL
= CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault
, dllURL
, CFSTR("CoreFoundation.resources"), TRUE
);
1163 // this registers us so subsequent calls to CFBundleGetBundleWithIdentifier will succeed
1164 CFBundleRef bundle
= CFBundleCreate(kCFAllocatorSystemDefault
, bundleURL
);
1165 CFRelease(bundleURL
);
1171 #define DLL_PROCESS_ATTACH 1
1172 #define DLL_THREAD_ATTACH 2
1173 #define DLL_THREAD_DETACH 3
1174 #define DLL_PROCESS_DETACH 0
1176 int DllMain( HINSTANCE hInstance
, DWORD dwReason
, LPVOID pReserved
) {
1177 static CFBundleRef cfBundle
= NULL
;
1178 if (dwReason
== DLL_PROCESS_ATTACH
) {
1180 cfBundle
= RegisterCoreFoundationBundle();
1181 } else if (dwReason
== DLL_PROCESS_DETACH
&& pReserved
== 0) {
1182 // Only cleanup if we are being unloaded dynamically (pReserved == 0) <rdar://problem/7480873>
1183 __CFStreamCleanup();
1184 __CFSocketCleanup();
1185 __CFUniCharCleanup();
1187 #if DEPLOYMENT_TARGET_WINDOWS
1188 // No CF functions should access TSD after this is called
1189 __CFTSDWindowsCleanup();
1193 if (cfBundle
) CFRelease(cfBundle
);
1194 __CFStringCleanup();
1195 } else if (dwReason
== DLL_THREAD_DETACH
) {
1196 __CFFinalizeWindowsThreadData();
1203 #if __CF_BIG_ENDIAN__
1204 #define RC_INCREMENT (1ULL)
1205 #define RC_MASK (0xFFFFFFFFULL)
1206 #define RC_GET(V) ((V) & RC_MASK)
1207 #define RC_DEALLOCATING_BIT (0x400000ULL << 32)
1209 #define RC_INCREMENT (1ULL << 32)
1210 #define RC_MASK (0xFFFFFFFFULL << 32)
1211 #define RC_GET(V) (((V) & RC_MASK) >> 32)
1212 #define RC_DEALLOCATING_BIT (0x400000ULL)
1215 #if !DEPLOYMENT_TARGET_WINDOWS && __LP64__
1216 static bool (*CAS64
)(int64_t, int64_t, volatile int64_t *) = OSAtomicCompareAndSwap64Barrier
;
1218 static bool (*CAS32
)(int32_t, int32_t, volatile int32_t *) = OSAtomicCompareAndSwap32Barrier
;
1221 // For "tryR==true", a return of NULL means "failed".
1222 static CFTypeRef
_CFRetain(CFTypeRef cf
, Boolean tryR
) {
1223 uint32_t cfinfo
= *(uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1224 if (cfinfo
& 0x800000) { // custom ref counting for object
1225 if (tryR
) return NULL
;
1226 CFTypeID typeID
= (cfinfo
>> 8) & 0x03FF; // mask up to 0x0FFF
1227 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1228 uint32_t (*refcount
)(intptr_t, CFTypeRef
) = cfClass
->refcount
;
1229 if (!refcount
|| !(cfClass
->version
& _kCFRuntimeCustomRefCount
) || (((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
] != 0xFF)) {
1230 HALT
; // bogus object
1233 if (((CFRuntimeBase
*)cf
)->_rc
!= 0xFFFFFFFFU
) {
1234 HALT
; // bogus object
1241 Boolean didAuto
= false;
1243 if (0 == ((CFRuntimeBase
*)cf
)->_rc
&& !CF_IS_COLLECTABLE(cf
)) return cf
; // Constant CFTypeRef
1244 #if !DEPLOYMENT_TARGET_WINDOWS
1247 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1248 if (tryR
&& (allBits
& RC_DEALLOCATING_BIT
)) return NULL
;
1249 } while (!CAS64(allBits
, allBits
+ RC_INCREMENT
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
));
1250 // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1251 if (RC_GET(allBits
) == 0 && CF_IS_COLLECTABLE(cf
)) {
1252 auto_zone_retain(objc_collectableZone(), (void*)cf
);
1258 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
1259 } while (!CAS32(lowBits
, lowBits
+ 1, (int32_t *)&((CFRuntimeBase
*)cf
)->_rc
));
1260 // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1261 if (lowBits
== 0 && CF_IS_COLLECTABLE(cf
)) {
1262 auto_zone_retain(objc_collectableZone(), (void*)cf
);
1269 volatile uint32_t *infoLocation
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1270 CFIndex rcLowBits
= __CFBitfieldGetValue(cfinfo
, RC_END
, RC_START
);
1271 if (__builtin_expect(0 == rcLowBits
, 0) && !CF_IS_COLLECTABLE(cf
)) return cf
; // Constant CFTypeRef
1274 cfinfo
= *infoLocation
;
1275 #if !DEPLOYMENT_TARGET_WINDOWS
1276 // if already deallocating, don't allow new retain
1277 if (tryR
&& (cfinfo
& 0x400000)) return NULL
;
1279 uint32_t prospectiveNewInfo
= cfinfo
; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1280 prospectiveNewInfo
+= (1 << RC_START
);
1281 rcLowBits
= __CFBitfieldGetValue(prospectiveNewInfo
, RC_END
, RC_START
);
1282 if (__builtin_expect((rcLowBits
& 0x7f) == 0, 0)) {
1283 /* Roll over another bit to the external ref count
1284 Real ref count = low 7 bits of info[CF_RC_BITS] + external ref count << 6
1285 Bit 8 of low bits indicates that external ref count is in use.
1286 External ref count is shifted by 6 rather than 7 so that we can set the low
1287 bits to to 1100 0000 rather than 1000 0000.
1288 This prevents needing to access the external ref count for successive retains and releases
1289 when the composite retain count is right around a multiple of 1 << 7.
1291 prospectiveNewInfo
= cfinfo
;
1292 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, ((1 << 7) | (1 << 6)));
1293 __CFSpinLock(&__CFRuntimeExternRefCountTableLock
);
1294 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1295 if (__builtin_expect(success
, 1)) {
1296 __CFDoExternRefOperation(350, (id
)cf
);
1298 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock
);
1300 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1301 // XXX_PCB: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1302 if (success
&& __CFBitfieldGetValue(cfinfo
, RC_END
, RC_START
) == 0 && CF_IS_COLLECTABLE(cf
)) {
1303 auto_zone_retain(objc_collectableZone(), (void*)cf
);
1307 } while (__builtin_expect(!success
, 0));
1309 if (!didAuto
&& __builtin_expect(__CFOASafe
, 0)) {
1310 __CFRecordAllocationEvent(__kCFRetainEvent
, (void *)cf
, 0, CFGetRetainCount(cf
), NULL
);
1315 // Never called under GC, only called via ARR weak subsystem; a return of NULL is failure
1316 CFTypeRef
_CFTryRetain(CFTypeRef cf
) {
1317 if (NULL
== cf
) return NULL
;
1318 #if OBJC_HAVE_TAGGED_POINTERS
1319 if (_objc_isTaggedPointer(cf
)) return cf
; // success
1321 return _CFRetain(cf
, true);
1324 Boolean
_CFIsDeallocating(CFTypeRef cf
) {
1325 if (NULL
== cf
) return false;
1326 #if OBJC_HAVE_TAGGED_POINTERS
1327 if (_objc_isTaggedPointer(cf
)) return false;
1329 uint32_t cfinfo
= *(uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1330 if (cfinfo
& 0x800000) { // custom ref counting for object
1331 return true; // lie for now; this weak references to these objects cannot be formed
1333 return (cfinfo
& 0x400000) ? true : false;
1336 static void _CFRelease(CFTypeRef cf
) {
1338 uint32_t cfinfo
= *(uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1339 CFTypeID typeID
= (cfinfo
>> 8) & 0x03FF; // mask up to 0x0FFF
1340 if (cfinfo
& 0x800000) { // custom ref counting for object
1341 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1342 uint32_t (*refcount
)(intptr_t, CFTypeRef
) = cfClass
->refcount
;
1343 if (!refcount
|| !(cfClass
->version
& _kCFRuntimeCustomRefCount
) || (((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
] != 0xFF)) {
1344 HALT
; // bogus object
1347 if (((CFRuntimeBase
*)cf
)->_rc
!= 0xFFFFFFFFU
) {
1348 HALT
; // bogus object
1355 CFIndex start_rc
= __builtin_expect(__CFOASafe
, 0) ? CFGetRetainCount(cf
) : 0;
1356 Boolean isAllocator
= (__kCFAllocatorTypeID_CONST
== typeID
);
1357 Boolean didAuto
= false;
1359 #if !DEPLOYMENT_TARGET_WINDOWS
1364 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1365 lowBits
= RC_GET(allBits
);
1367 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(objc_collectableZone(), (void*)cf
);
1368 return; // Constant CFTypeRef
1371 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1372 if ((cfClass
->version
& _kCFRuntimeResourcefulObject
) && cfClass
->reclaim
!= NULL
) {
1373 cfClass
->reclaim(cf
);
1375 if (!CF_IS_COLLECTABLE(cf
)) {
1376 uint64_t newAllBits
= allBits
| RC_DEALLOCATING_BIT
;
1377 if (!CAS64(allBits
, newAllBits
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
)) {
1380 allBits
= newAllBits
;
1381 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1385 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1386 lowBits
= RC_GET(allBits
);
1387 if (isAllocator
|| ((1 == lowBits
) && CAS64(allBits
, allBits
- RC_INCREMENT
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
))) {
1390 Boolean success
= false;
1391 do { // drop the deallocating bit; racey, but this resurrection stuff isn't thread-safe anyway
1392 allBits
= *(uint64_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1393 uint64_t newAllBits
= allBits
& ~RC_DEALLOCATING_BIT
;
1394 success
= CAS64(allBits
, newAllBits
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
);
1396 goto again
; // still need to have the effect of a CFRelease
1399 } while (!CAS64(allBits
, allBits
- RC_INCREMENT
, (int64_t *)&((CFRuntimeBase
*)cf
)->_cfinfo
));
1400 if (lowBits
== 1 && CF_IS_COLLECTABLE(cf
)) {
1401 // GC: release the collector's hold over the object, which will call the finalize function later on.
1402 auto_zone_release(objc_collectableZone(), (void*)cf
);
1408 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
1410 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(objc_collectableZone(), (void*)cf
);
1411 return; // Constant CFTypeRef
1414 // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION
1415 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1416 if ((cfClass
->version
& _kCFRuntimeResourcefulObject
) && cfClass
->reclaim
!= NULL
) {
1417 cfClass
->reclaim(cf
);
1419 if (!CF_IS_COLLECTABLE(cf
)) {
1420 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1424 if (isAllocator
|| CAS32(1, 0, (int32_t *)&((CFRuntimeBase
*)cf
)->_rc
)) {
1429 } while (!CAS32(lowBits
, lowBits
- 1, (int32_t *)&((CFRuntimeBase
*)cf
)->_rc
));
1430 if (lowBits
== 1 && CF_IS_COLLECTABLE(cf
)) {
1431 // GC: release the collector's hold over the object, which will call the finalize function later on.
1432 auto_zone_release(objc_collectableZone(), (void*)cf
);
1437 #if !DEPLOYMENT_TARGET_WINDOWS
1439 volatile uint32_t *infoLocation
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1440 CFIndex rcLowBits
= __CFBitfieldGetValue(cfinfo
, RC_END
, RC_START
);
1441 if (__builtin_expect(0 == rcLowBits
, 0)) {
1442 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(objc_collectableZone(), (void*)cf
);
1443 return; // Constant CFTypeRef
1446 Boolean whack
= false;
1448 cfinfo
= *infoLocation
;
1449 rcLowBits
= __CFBitfieldGetValue(cfinfo
, RC_END
, RC_START
);
1450 if (__builtin_expect(1 == rcLowBits
, 0)) {
1451 // we think cf should be deallocated
1452 uint32_t prospectiveNewInfo
= cfinfo
| (0x400000);
1453 if (CF_IS_COLLECTABLE(cf
)) {
1454 prospectiveNewInfo
-= (1 << RC_START
);
1456 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1457 if (success
) whack
= true;
1460 uint32_t prospectiveNewInfo
= cfinfo
; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1461 if (__builtin_expect((1 << 7) == rcLowBits
, 0)) {
1462 // Time to remove a bit from the external ref count
1463 __CFSpinLock(&__CFRuntimeExternRefCountTableLock
);
1464 CFIndex rcHighBitsCnt
= __CFDoExternRefOperation(500, (id
)cf
);
1465 if (1 == rcHighBitsCnt
) {
1466 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, (1 << 6) - 1);
1468 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, ((1 << 6) | (1 << 7)) - 1);
1470 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1471 if (__builtin_expect(success
, 1)) {
1472 __CFDoExternRefOperation(450, (id
)cf
);
1474 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock
);
1476 prospectiveNewInfo
-= (1 << RC_START
);
1477 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1480 } while (__builtin_expect(!success
, 0));
1483 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1484 if ((cfClass
->version
& _kCFRuntimeResourcefulObject
) && cfClass
->reclaim
!= NULL
) {
1485 cfClass
->reclaim(cf
);
1487 if (CF_IS_COLLECTABLE(cf
)) {
1488 // GC: release the collector's hold over the object, which will call the finalize function later on.
1489 auto_zone_release(objc_collectableZone(), (void*)cf
);
1495 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1499 rcLowBits
= __CFBitfieldGetValue(*infoLocation
, RC_END
, RC_START
);
1500 if (1 == rcLowBits
) {
1503 do { // drop the deallocating bit; racey, but this resurrection stuff isn't thread-safe anyway
1504 cfinfo
= *infoLocation
;
1505 uint32_t prospectiveNewInfo
= (cfinfo
& ~(0x400000));
1506 success
= CAS32(*(int32_t *)& cfinfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1513 volatile uint32_t *infoLocation
= (uint32_t *)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1514 CFIndex rcLowBits
= __CFBitfieldGetValue(*infoLocation
, RC_END
, RC_START
);
1515 if (__builtin_expect(0 == rcLowBits
, 0)) {
1516 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(objc_collectableZone(), (void*)cf
);
1517 return; // Constant CFTypeRef
1521 uint32_t initialCheckInfo
= *infoLocation
;
1522 rcLowBits
= __CFBitfieldGetValue(initialCheckInfo
, RC_END
, RC_START
);
1523 if (__builtin_expect(1 == rcLowBits
, 0)) {
1524 // we think cf should be deallocated
1525 // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION
1526 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1527 if ((cfClass
->version
& _kCFRuntimeResourcefulObject
) && cfClass
->reclaim
!= NULL
) {
1528 cfClass
->reclaim(cf
);
1530 if (CF_IS_COLLECTABLE(cf
)) {
1531 uint32_t prospectiveNewInfo
= initialCheckInfo
- (1 << RC_START
);
1532 success
= CAS32(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1533 // GC: release the collector's hold over the object, which will call the finalize function later on.
1535 auto_zone_release(objc_collectableZone(), (void*)cf
);
1542 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1546 // We recheck rcLowBits to see if the object has been retained again during
1547 // the finalization process. This allows for the finalizer to resurrect,
1548 // but the main point is to allow finalizers to be able to manage the
1549 // removal of objects from uniquing caches, which may race with other threads
1550 // which are allocating (looking up and finding) objects from those caches,
1551 // which (that thread) would be the thing doing the extra retain in that case.
1552 rcLowBits
= __CFBitfieldGetValue(*infoLocation
, RC_END
, RC_START
);
1553 success
= (1 == rcLowBits
);
1554 if (__builtin_expect(success
, 1)) {
1561 uint32_t prospectiveNewInfo
= initialCheckInfo
; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1562 if (__builtin_expect((1 << 7) == rcLowBits
, 0)) {
1563 // Time to remove a bit from the external ref count
1564 __CFSpinLock(&__CFRuntimeExternRefCountTableLock
);
1565 CFIndex rcHighBitsCnt
= __CFDoExternRefOperation(500, (id
)cf
);
1566 if (1 == rcHighBitsCnt
) {
1567 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, (1 << 6) - 1);
1569 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, ((1 << 6) | (1 << 7)) - 1);
1571 success
= CAS32(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1572 if (__builtin_expect(success
, 1)) {
1573 __CFDoExternRefOperation(450, (id
)cf
);
1575 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock
);
1577 prospectiveNewInfo
-= (1 << RC_START
);
1578 success
= CAS32(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1581 } while (__builtin_expect(!success
, 0));
1584 if (!didAuto
&& __builtin_expect(__CFOASafe
, 0)) {
1585 __CFRecordAllocationEvent(__kCFReleaseEvent
, (void *)cf
, 0, start_rc
- 1, NULL
);
1590 if (!didAuto
&& __builtin_expect(__CFOASafe
, 0)) {
1591 // do not use CFGetRetainCount() because cf has been freed if it was an allocator
1592 __CFRecordAllocationEvent(__kCFReleaseEvent
, (void *)cf
, 0, 0, NULL
);
1594 // cannot zombify allocators, which get deallocated by __CFAllocatorDeallocate (finalize)
1596 __CFAllocatorDeallocate((void *)cf
);
1598 CFAllocatorRef allocator
= kCFAllocatorSystemDefault
;
1599 Boolean usesSystemDefaultAllocator
= true;
1601 if (!__CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 7, 7)) {
1602 allocator
= CFGetAllocator(cf
);
1603 usesSystemDefaultAllocator
= _CFAllocatorIsSystemDefault(allocator
);
1607 CFAllocatorDeallocate(allocator
, (uint8_t *)cf
- (usesSystemDefaultAllocator
? 0 : sizeof(CFAllocatorRef
)));
1610 if (kCFAllocatorSystemDefault
!= allocator
) {
1611 CFRelease(allocator
);
1616 #undef __kCFAllocatorTypeID_CONST
1617 #undef __CFGenericAssertIsCF