2 * Copyright (c) 2009 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-2009, 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>
43 #include <objc/runtime.h>
45 #include <CoreFoundation/CFStringDefaultEncoding.h>
46 #define objc_isAuto (0)
48 #include <objc/runtime.h>
51 #if DEPLOYMENT_TARGET_WINDOWS
52 #define _objc_getFreedObjectClass() 0
54 extern Class
_objc_getFreedObjectClass(void);
57 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
58 extern void __CFRecordAllocationEvent(int eventnum
, void *ptr
, int64_t size
, uint64_t data
, const char *classname
);
60 #define __CFRecordAllocationEvent(a, b, c, d, e) ((void)0)
64 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
65 extern void instrumentObjcMessageSends(BOOL flag
);
68 #if DEPLOYMENT_TARGET_WINDOWS
73 // retain/release recording constants -- must match values
74 // used by OA for now; probably will change in the future
75 __kCFRetainEvent
= 28,
76 __kCFReleaseEvent
= 29
79 #if DEPLOYMENT_TARGET_WINDOWS
82 #include <malloc/malloc.h>
85 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
87 bool __CFOASafe
= false;
89 void (*__CFObjectAllocRecordAllocationFunction
)(int, void *, int64_t , uint64_t, const char *) = NULL
;
90 void (*__CFObjectAllocSetLastAllocEventNameFunction
)(void *, const char *) = NULL
;
92 void __CFOAInitialize(void) {
93 static void (*dyfunc
)(void) = (void *)~0;
94 if (NULL
== __CFgetenv("OAKeepAllocationStatistics")) return;
95 if ((void *)~0 == dyfunc
) {
96 dyfunc
= dlsym(RTLD_DEFAULT
, "_OAInitialize");
100 __CFObjectAllocRecordAllocationFunction
= dlsym(RTLD_DEFAULT
, "_OARecordAllocationEvent");
101 __CFObjectAllocSetLastAllocEventNameFunction
= dlsym(RTLD_DEFAULT
, "_OASetLastAllocationEventName");
106 void __CFRecordAllocationEvent(int eventnum
, void *ptr
, int64_t size
, uint64_t data
, const char *classname
) {
107 if (!__CFOASafe
|| !__CFObjectAllocRecordAllocationFunction
) return;
108 __CFObjectAllocRecordAllocationFunction(eventnum
, ptr
, size
, data
, classname
);
111 void __CFSetLastAllocationEventName(void *ptr
, const char *classname
) {
112 if (!__CFOASafe
|| !__CFObjectAllocSetLastAllocEventNameFunction
) return;
113 __CFObjectAllocSetLastAllocEventNameFunction(ptr
, classname
);
118 extern void __HALT(void);
120 static CFTypeID __kCFNotATypeTypeID
= _kCFRuntimeNotATypeID
;
122 #if !defined (__cplusplus)
123 static const CFRuntimeClass __CFNotATypeClass
= {
135 static CFTypeID __kCFTypeTypeID
= _kCFRuntimeNotATypeID
;
137 static const CFRuntimeClass __CFTypeClass
= {
149 void SIG1(CFTypeRef
){__HALT();};;
150 CFTypeRef
SIG2(CFAllocatorRef
,CFTypeRef
){__HALT();return NULL
;};
151 Boolean
SIG3(CFTypeRef
,CFTypeRef
){__HALT();return FALSE
;};
152 CFHashCode
SIG4(CFTypeRef
){__HALT(); return 0;};
153 CFStringRef
SIG5(CFTypeRef
,CFDictionaryRef
){__HALT();return NULL
;};
154 CFStringRef
SIG6(CFTypeRef
){__HALT();return NULL
;};
156 static const CFRuntimeClass __CFNotATypeClass
= {
168 static CFTypeID __kCFTypeTypeID
= _kCFRuntimeNotATypeID
;
170 static const CFRuntimeClass __CFTypeClass
= {
183 // the lock does not protect most reading of these; we just leak the old table to allow read-only accesses to continue to work
184 static CFSpinLock_t __CFBigRuntimeFunnel
= CFSpinLockInit
;
185 static CFRuntimeClass
** __CFRuntimeClassTable
= NULL
;
186 int32_t __CFRuntimeClassTableSize
= 0;
187 static int32_t __CFRuntimeClassTableCount
= 0;
189 uintptr_t *__CFRuntimeObjCClassTable
= NULL
;
191 __private_extern__
void * (*__CFSendObjCMsg
)(const void *, SEL
, ...) = NULL
;
193 bool (*__CFObjCIsCollectable
)(void *) = NULL
;
195 // Compiler uses this symbol name; must match compiler built-in decl, so we use 'int'
197 int __CFConstantStringClassReference
[24] = {0};
199 int __CFConstantStringClassReference
[12] = {0};
203 Boolean
_CFIsObjC(CFTypeID typeID
, void *obj
) {
204 __CFSpinLock(&__CFBigRuntimeFunnel
);
205 Boolean b
= ((typeID
>= (CFTypeID
)__CFRuntimeClassTableSize
) || (((CFRuntimeBase
*)obj
)->_cfisa
!= (uintptr_t)__CFRuntimeObjCClassTable
[typeID
] && ((CFRuntimeBase
*)obj
)->_cfisa
> (uintptr_t)0xFFF));
206 __CFSpinUnlock(&__CFBigRuntimeFunnel
);
210 CFTypeID
_CFRuntimeRegisterClass(const CFRuntimeClass
* const cls
) {
211 // version field must be 0
212 // className must be pure ASCII string, non-null
213 __CFSpinLock(&__CFBigRuntimeFunnel
);
214 if (__CFMaxRuntimeTypes
<= __CFRuntimeClassTableCount
) {
215 CFLog(kCFLogLevelWarning
, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls
->className
);
216 __CFSpinUnlock(&__CFBigRuntimeFunnel
);
217 return _kCFRuntimeNotATypeID
;
219 if (__CFRuntimeClassTableSize
<= __CFRuntimeClassTableCount
) {
220 int32_t old_size
= __CFRuntimeClassTableSize
;
221 int32_t new_size
= __CFRuntimeClassTableSize
* 4;
223 void *new_table1
= calloc(new_size
, sizeof(CFRuntimeClass
*));
224 memmove(new_table1
, __CFRuntimeClassTable
, old_size
* sizeof(CFRuntimeClass
*));
225 __CFRuntimeClassTable
= (CFRuntimeClass
**)new_table1
;
227 void *new_table2
= calloc(new_size
, sizeof(uintptr_t));
228 memmove(new_table2
, __CFRuntimeObjCClassTable
, old_size
* sizeof(uintptr_t));
229 for (CFIndex idx
= old_size
; idx
< new_size
; idx
++) {
230 ((uintptr_t *)new_table2
)[idx
] = __CFRuntimeObjCClassTable
[0];
232 __CFRuntimeObjCClassTable
= (uintptr_t *)new_table2
;
234 __CFRuntimeClassTableSize
= new_size
;
235 // The old value of __CFRuntimeClassTable is intentionally leaked
236 // for thread-safety reasons:
237 // other threads might have loaded the value of that, in functions here
238 // in this file executing in other threads, and may attempt to use it after
239 // this thread gets done reallocating here, so freeing is unsafe. We
240 // don't want to pay the expense of locking around all uses of these variables.
241 // The old value of __CFRuntimeObjCClassTable is intentionally leaked
242 // for thread-safety reasons:
243 // other threads might have loaded the value of that, since it is
244 // accessible via CFBridgingPriv.h, and may attempt to use it after
245 // this thread gets done reallocating here, so freeing is unsafe.
247 __CFRuntimeClassTable
[__CFRuntimeClassTableCount
++] = (CFRuntimeClass
*)cls
;
248 CFTypeID typeID
= __CFRuntimeClassTableCount
- 1;
249 __CFSpinUnlock(&__CFBigRuntimeFunnel
);
253 void _CFRuntimeBridgeClasses(CFTypeID cf_typeID
, const char *objc_classname
) {
254 __CFSpinLock(&__CFBigRuntimeFunnel
);
255 __CFRuntimeObjCClassTable
[cf_typeID
] = (uintptr_t)objc_getFutureClass(objc_classname
);
256 __CFSpinUnlock(&__CFBigRuntimeFunnel
);
259 const CFRuntimeClass
* _CFRuntimeGetClassWithTypeID(CFTypeID typeID
) {
260 return __CFRuntimeClassTable
[typeID
]; // hopelessly unthreadsafe
263 void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID
) {
264 __CFSpinLock(&__CFBigRuntimeFunnel
);
265 __CFRuntimeClassTable
[typeID
] = NULL
;
266 __CFSpinUnlock(&__CFBigRuntimeFunnel
);
270 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
272 /* CFZombieLevel levels:
273 * bit 0: scribble deallocated CF object memory
274 * bit 1: do not scribble on CFRuntimeBase header (when bit 0)
275 * bit 4: do not free CF objects
276 * bit 7: use 3rd-order byte as scribble byte for dealloc (otherwise 0xFC)
279 static uint32_t __CFZombieLevel
= 0x0;
280 __private_extern__
uint8_t __CFZombieEnabled
= 0;
281 __private_extern__
uint8_t __CFDeallocateZombies
= 0;
283 static void *_original_objc_dealloc
= 0;
286 void _CFEnableZombies(void) {
287 __CFZombieEnabled
= 0xFF;
292 // XXX_PCB: use the class version field as a bitmask, to allow classes to opt-in for GC scanning.
294 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
295 CF_INLINE CFOptionFlags
CF_GET_COLLECTABLE_MEMORY_TYPE(const CFRuntimeClass
*cls
)
297 return ((cls
->version
& _kCFRuntimeScannedObject
) ? __kCFAllocatorGCScannedMemory
: 0) | __kCFAllocatorGCObjectMemory
;
300 #define CF_GET_COLLECTABLE_MEMORY_TYPE(x) (0)
303 CFTypeRef
_CFRuntimeCreateInstance(CFAllocatorRef allocator
, CFTypeID typeID
, CFIndex extraBytes
, unsigned char *category
) {
304 CFAssert1(typeID
!= _kCFRuntimeNotATypeID
, __kCFLogAssertion
, "%s(): Uninitialized type id", __PRETTY_FUNCTION__
);
305 CFRuntimeClass
*cls
= __CFRuntimeClassTable
[typeID
];
309 allocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : allocator
;
310 if (kCFAllocatorNull
== allocator
) {
313 Boolean usesSystemDefaultAllocator
= (allocator
== kCFAllocatorSystemDefault
);
314 CFIndex size
= sizeof(CFRuntimeBase
) + extraBytes
+ (usesSystemDefaultAllocator
? 0 : sizeof(CFAllocatorRef
));
315 size
= (size
+ 0xF) & ~0xF; // CF objects are multiples of 16 in size
316 // CFType version 0 objects are unscanned by default since they don't have write-barriers and hard retain their innards
317 // CFType version 1 objects are scanned and use hand coded write-barriers to store collectable storage within
318 CFRuntimeBase
*memory
= (CFRuntimeBase
*)CFAllocatorAllocate(allocator
, size
, CF_GET_COLLECTABLE_MEMORY_TYPE(cls
));
319 if (NULL
== memory
) {
320 CFStringRef msg
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("Attempt to allocate %ld bytes for %s failed"), size
, category
? (char *)category
: (char *)cls
->className
);
322 CFLog(kCFLogLevelCritical
, CFSTR("%@"), msg
);
328 if (!kCFUseCollectableAllocator
|| !CF_IS_COLLECTABLE_ALLOCATOR(allocator
) || !(CF_GET_COLLECTABLE_MEMORY_TYPE(cls
) & __kCFAllocatorGCScannedMemory
)) {
329 memset(memory
, 0, size
);
331 if (__CFOASafe
&& category
) {
332 __CFSetLastAllocationEventName(memory
, (char *)category
);
333 } else if (__CFOASafe
) {
334 __CFSetLastAllocationEventName(memory
, (char *)cls
->className
);
336 if (!usesSystemDefaultAllocator
) {
337 // add space to hold allocator ref for non-standard allocators.
338 // (this screws up 8 byte alignment but seems to work)
339 *(CFAllocatorRef
*)((char *)memory
) = (CFAllocatorRef
)CFRetain(allocator
);
340 memory
= (CFRuntimeBase
*)((char *)memory
+ sizeof(CFAllocatorRef
));
342 memory
->_cfisa
= __CFISAForTypeID(typeID
);
344 *(uint32_t *)(memory
->_cfinfo
) = (uint32_t)((0 << 24) + ((typeID
& 0xFFFF) << 8) + (usesSystemDefaultAllocator
? 0x80 : 0x00));
347 *(uint32_t *)(memory
->_cfinfo
) = (uint32_t)((1 << 24) + ((typeID
& 0xFFFF) << 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 (NULL
== __CFRuntimeClassTable
[typeID
]) {
360 CFRuntimeBase
*memory
= (CFRuntimeBase
*)ptr
;
361 memory
->_cfisa
= __CFISAForTypeID(typeID
);
362 *(uint32_t *)(memory
->_cfinfo
) = (uint32_t)((0 << 24) + ((typeID
& 0xFFFF) << 8) + 0x80);
366 if (NULL
!= __CFRuntimeClassTable
[typeID
]->init
) {
367 (__CFRuntimeClassTable
[typeID
]->init
)(memory
);
371 void _CFRuntimeSetInstanceTypeID(CFTypeRef cf
, CFTypeID typeID
) {
372 *(uint16_t *)(((CFRuntimeBase
*)cf
)->_cfinfo
+ 1) = (uint16_t)(typeID
& 0xFFFF);
375 __private_extern__ Boolean
__CFRuntimeIsFreedObject(id anObject
) {
376 if (!anObject
) return false;
377 static Class freedClass
= Nil
;
378 if (!freedClass
) freedClass
= _objc_getFreedObjectClass();
379 Class cls
= object_getClass(anObject
);
380 if (cls
== freedClass
) return true;
381 // in 64-bit, a future class has nil isa, and calling class_getName() on
382 // such will crash so we do this test; zombie classes are not future classes
383 if (object_getClass((id
)cls
) == nil
) return false;
384 const char *cname
= class_getName(cls
);
385 if (cname
&& 0 == strncmp(cname
, "_NSZombie_", 10)) return true;
391 __kCFObjectRetainedEvent
= 12,
392 __kCFObjectReleasedEvent
= 13
395 #if DEPLOYMENT_TARGET_MACOSX
396 #define NUM_EXTERN_TABLES 8
397 #define EXTERN_TABLE_IDX(O) (((uintptr_t)(O) >> 8) & 0x7)
398 #elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
399 #define NUM_EXTERN_TABLES 1
400 #define EXTERN_TABLE_IDX(O) 0
405 // we disguise pointers so that programs like 'leaks' forget about these references
406 #define DISGUISE(O) (~(uintptr_t)(O))
410 CFBasicHashRef table
;
411 uint8_t padding
[64 - sizeof(CFBasicHashRef
) - sizeof(CFSpinLock_t
)];
412 } __NSRetainCounters
[NUM_EXTERN_TABLES
];
414 CF_EXPORT
uintptr_t __CFDoExternRefOperation(uintptr_t op
, id obj
) {
415 if (nil
== obj
) HALT
;
416 uintptr_t idx
= EXTERN_TABLE_IDX(obj
);
417 uintptr_t disguised
= DISGUISE(obj
);
418 #if DEPLOYMENT_TARGET_WINDOWS
419 // assume threaded on windows for now
422 int thr
= pthread_is_threaded_np();
424 CFSpinLock_t
*lock
= &__NSRetainCounters
[idx
].lock
;
425 CFBasicHashRef table
= __NSRetainCounters
[idx
].table
;
428 case 300: // increment
429 case 350: // increment, no event
430 if (thr
) __CFSpinLock(lock
);
431 CFBasicHashAddValue(table
, disguised
, disguised
);
432 if (thr
) __CFSpinUnlock(lock
);
433 if (__CFOASafe
&& op
!= 350) __CFRecordAllocationEvent(__kCFObjectRetainedEvent
, obj
, 0, 0, NULL
);
434 return (uintptr_t)obj
;
435 case 400: // decrement
436 if (__CFOASafe
) __CFRecordAllocationEvent(__kCFObjectReleasedEvent
, obj
, 0, 0, NULL
);
437 case 450: // decrement, no event
438 if (thr
) __CFSpinLock(lock
);
439 count
= (uintptr_t)CFBasicHashRemoveValue(table
, disguised
);
440 if (thr
) __CFSpinUnlock(lock
);
443 if (thr
) __CFSpinLock(lock
);
444 count
= (uintptr_t)CFBasicHashGetCountOfKey(table
, disguised
);
445 if (thr
) __CFSpinUnlock(lock
);
452 CFTypeID
__CFGenericTypeID(const void *cf
) {
453 return (*(uint32_t *)(((CFRuntimeBase
*)cf
)->_cfinfo
) >> 8) & 0xFFFF;
456 CF_INLINE CFTypeID
__CFGenericTypeID_inline(const void *cf
) {
457 return (*(uint32_t *)(((CFRuntimeBase
*)cf
)->_cfinfo
) >> 8) & 0xFFFF;
460 CFTypeID
CFTypeGetTypeID(void) {
461 return __kCFTypeTypeID
;
464 __private_extern__
void __CFGenericValidateType_(CFTypeRef cf
, CFTypeID type
, const char *func
) {
465 if (cf
&& CF_IS_OBJC(type
, cf
)) return;
466 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
); \
467 CFAssert3(__CFGenericTypeID_inline(cf
) == type
, __kCFLogAssertion
, "%s(): pointer %p is not a %s", func
, cf
, __CFRuntimeClassTable
[type
]->className
); \
470 #define __CFGenericAssertIsCF(cf) \
471 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);
474 #define CFTYPE_IS_OBJC(obj) (false)
475 #define CFTYPE_OBJC_FUNCDISPATCH0(rettype, obj, sel) do {} while (0)
476 #define CFTYPE_OBJC_FUNCDISPATCH1(rettype, obj, sel, a1) do {} while (0)
479 CFTypeID
CFGetTypeID(CFTypeRef cf
) {
481 if (NULL
== cf
) HALT
;
483 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeID
, cf
, "_cfTypeID");
484 __CFGenericAssertIsCF(cf
);
485 return __CFGenericTypeID_inline(cf
);
488 CFStringRef
CFCopyTypeIDDescription(CFTypeID type
) {
489 CFAssert2((NULL
!= __CFRuntimeClassTable
[type
]) && __kCFNotATypeTypeID
!= type
&& __kCFTypeTypeID
!= type
, __kCFLogAssertion
, "%s(): type %d is not a CF type ID", __PRETTY_FUNCTION__
, type
);
490 return CFStringCreateWithCString(kCFAllocatorSystemDefault
, __CFRuntimeClassTable
[type
]->className
, kCFStringEncodingASCII
);
493 // Bit 31 (highest bit) in second word of cf instance indicates external ref count
495 CF_EXPORT
void _CFRelease(CFTypeRef cf
);
496 CF_EXPORT CFTypeRef
_CFRetain(CFTypeRef cf
);
498 CFTypeRef
CFRetain(CFTypeRef cf
) {
499 if (NULL
== cf
) HALT
;
500 if (CF_IS_COLLECTABLE(cf
)) {
501 if (CFTYPE_IS_OBJC(cf
)) {
502 // always honor CFRetain's with a GC-visible retain.
503 auto_zone_retain(auto_zone(), (void*)cf
);
506 // special case CF objects for performance.
507 return _CFRetain(cf
);
510 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeRef
, cf
, "retain");
511 if (cf
) __CFGenericAssertIsCF(cf
);
512 return _CFRetain(cf
);
515 __private_extern__
void __CFAllocatorDeallocate(CFTypeRef cf
);
517 void CFRelease(CFTypeRef cf
) {
518 if (NULL
== cf
) HALT
;
519 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
520 if (CF_IS_COLLECTABLE(cf
)) {
521 if (CFTYPE_IS_OBJC(cf
)) {
522 // release the GC-visible reference.
523 auto_zone_release(auto_zone(), (void*)cf
);
525 // special-case CF objects for better performance.
532 void **addrs
[2] = {&&start
, &&end
};
534 if (addrs
[0] <= __builtin_return_address(0) && __builtin_return_address(0) <= addrs
[1]) {
535 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]);
539 CFTYPE_OBJC_FUNCDISPATCH0(void, cf
, "release");
540 if (cf
) __CFGenericAssertIsCF(cf
);
548 __private_extern__
const void *__CFStringCollectionCopy(CFAllocatorRef allocator
, const void *ptr
) {
549 if (NULL
== ptr
) HALT
;
550 CFStringRef theString
= (CFStringRef
)ptr
;
551 CFStringRef result
= CFStringCreateCopy(allocator
, theString
);
552 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
553 result
= (CFStringRef
)CFMakeCollectable(result
);
555 return (const void *)result
;
558 extern void CFCollection_non_gc_storage_error(void);
560 __private_extern__
const void *__CFTypeCollectionRetain(CFAllocatorRef allocator
, const void *ptr
) {
561 if (NULL
== ptr
) HALT
;
562 CFTypeRef cf
= (CFTypeRef
)ptr
;
563 // only collections allocated in the GC zone can opt-out of reference counting.
564 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
565 if (CFTYPE_IS_OBJC(cf
)) return cf
; // do nothing for OBJC objects.
566 if (auto_zone_is_valid_pointer(auto_zone(), ptr
)) {
567 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)];
568 if (cfClass
->version
& _kCFRuntimeResourcefulObject
) {
569 // GC: If this a CF object in the GC heap that is marked resourceful, then
570 // it must be retained keep it alive in a CF collection.
571 // We're basically inlining CFRetain() here, to avoid extra heap membership tests.
575 ; // don't retain normal CF objects
578 // support constant CFTypeRef objects.
580 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
582 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
];
584 if (lowBits
== 0) return cf
;
585 // complain about non-GC objects in GC containers.
586 CFLog(kCFLogLevelWarning
, CFSTR("storing a non-GC object %p in a GC collection, break on CFCollection_non_gc_storage_error to debug."), cf
);
587 CFCollection_non_gc_storage_error();
588 // XXX should halt, except Patrick is using this somewhere.
596 __private_extern__
void __CFTypeCollectionRelease(CFAllocatorRef allocator
, const void *ptr
) {
597 if (NULL
== ptr
) HALT
;
598 CFTypeRef cf
= (CFTypeRef
)ptr
;
599 // only collections allocated in the GC zone can opt-out of reference counting.
600 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
601 if (CFTYPE_IS_OBJC(cf
)) return; // do nothing for OBJC objects.
602 if (auto_zone_is_valid_pointer(auto_zone(), cf
)) {
603 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
604 // GC: If this a CF object in the GC heap that is marked uncollectable, then
605 // must balance the retain done in __CFTypeCollectionRetain().
606 // We're basically inlining CFRelease() here, to avoid extra heap membership tests.
607 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)];
608 if (cfClass
->version
& _kCFRuntimeResourcefulObject
) {
609 // reclaim is called by _CFRelease(), which must be called to keep the
610 // CF and GC retain counts in sync.
613 // avoid releasing normal CF objects. Like other collections, for example
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;
631 static CFSpinLock_t __CFRuntimeExternRefCountTableLock
= CFSpinLockInit
;
632 static CFMutableBagRef __CFRuntimeExternRefCountTable
= NULL
;
635 static uint64_t __CFGetFullRetainCount(CFTypeRef cf
) {
636 if (NULL
== cf
) HALT
;
638 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
640 return (uint64_t)0x0fffffffffffffffULL
;
644 uint32_t lowBits
= ((CFRuntimeBase
*)cf
)->_cfinfo
[CF_RC_BITS
];
646 return (uint64_t)0x0fffffffffffffffULL
;
648 uint64_t highBits
= 0;
649 if ((lowBits
& 0x80) != 0) {
650 highBits
= __CFDoExternRefOperation(500, (id
)cf
);
652 uint64_t compositeRC
= (lowBits
& 0x7f) + (highBits
<< 6);
657 CFTypeRef
_CFRetainGC(CFTypeRef cf
) {
659 if (kCFUseCollectableAllocator
&& !CF_IS_COLLECTABLE(cf
)) {
660 fprintf(stderr
, "non-auto object %p passed to _CFRetainGC.\n", cf
);
664 return kCFUseCollectableAllocator
? cf
: CFRetain(cf
);
667 void _CFReleaseGC(CFTypeRef cf
) {
669 if (kCFUseCollectableAllocator
&& !CF_IS_COLLECTABLE(cf
)) {
670 fprintf(stderr
, "non-auto object %p passed to _CFReleaseGC.\n", cf
);
674 if (!kCFUseCollectableAllocator
) CFRelease(cf
);
677 CFIndex
CFGetRetainCount(CFTypeRef cf
) {
678 if (NULL
== cf
) HALT
;
679 if (CF_IS_COLLECTABLE(cf
)) {
680 if (CFTYPE_IS_OBJC(cf
)) return auto_zone_retain_count(auto_zone(), cf
);
682 CFTYPE_OBJC_FUNCDISPATCH0(CFIndex
, cf
, "retainCount");
683 __CFGenericAssertIsCF(cf
);
685 uint64_t rc
= __CFGetFullRetainCount(cf
);
686 return (rc
< (uint64_t)LONG_MAX
) ? (CFIndex
)rc
: (CFIndex
)LONG_MAX
;
689 CFTypeRef
CFMakeCollectable(CFTypeRef cf
) {
690 if (NULL
== cf
) return NULL
;
691 if (CF_IS_COLLECTABLE(cf
)) {
692 objc_assertRegisteredThreadWithCollector();
694 CFAllocatorRef allocator
= CFGetAllocator(cf
);
695 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
696 CFLog(kCFLogLevelWarning
, CFSTR("object %p with non-GC allocator %p passed to CFMakeCollectable."), cf
, allocator
);
700 if (!CFTYPE_IS_OBJC(cf
)) {
701 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)];
702 if (cfClass
->version
& (_kCFRuntimeResourcefulObject
)) {
703 // don't allow the collector to manage uncollectable objects.
704 CFLog(kCFLogLevelWarning
, CFSTR("uncollectable object %p passed to CFMakeCollectable."), cf
);
708 if (CFGetRetainCount(cf
) == 0) {
709 CFLog(kCFLogLevelWarning
, CFSTR("object %p with 0 retain-count passed to CFMakeCollectable."), cf
);
717 CFTypeRef
CFMakeUncollectable(CFTypeRef cf
) {
718 if (NULL
== cf
) return NULL
;
719 if (CF_IS_COLLECTABLE(cf
)) {
725 Boolean
CFEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
726 if (NULL
== cf1
) HALT
;
727 if (NULL
== cf2
) HALT
;
728 if (cf1
== cf2
) return true;
729 CFTYPE_OBJC_FUNCDISPATCH1(Boolean
, cf1
, "isEqual:", cf2
);
730 CFTYPE_OBJC_FUNCDISPATCH1(Boolean
, cf2
, "isEqual:", cf1
);
731 __CFGenericAssertIsCF(cf1
);
732 __CFGenericAssertIsCF(cf2
);
733 if (__CFGenericTypeID_inline(cf1
) != __CFGenericTypeID_inline(cf2
)) return false;
734 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf1
)]->equal
) {
735 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf1
)]->equal(cf1
, cf2
);
740 CFHashCode
CFHash(CFTypeRef cf
) {
741 if (NULL
== cf
) HALT
;
742 CFTYPE_OBJC_FUNCDISPATCH0(CFHashCode
, cf
, "hash");
743 __CFGenericAssertIsCF(cf
);
744 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->hash
) {
745 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->hash(cf
);
747 return (CFHashCode
)cf
;
750 // definition: produces a normally non-NULL debugging description of the object
751 CFStringRef
CFCopyDescription(CFTypeRef cf
) {
752 if (NULL
== cf
) HALT
;
753 if (CFTYPE_IS_OBJC(cf
)) {
755 CFStringRef (*func
)(void *, SEL
) = (CFStringRef (*)(void *, SEL
))objc_msgSend
;
756 if (!s
) s
= sel_registerName("_copyDescription");
757 CFStringRef result
= func((void *)cf
, s
);
760 // CFTYPE_OBJC_FUNCDISPATCH0(CFStringRef, cf, "_copyDescription"); // XXX returns 0 refcounted item under GC
761 __CFGenericAssertIsCF(cf
);
762 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyDebugDesc
) {
764 result
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyDebugDesc(cf
);
765 if (NULL
!= result
) return result
;
767 return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<%s %p [%p]>"), __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->className
, cf
, CFGetAllocator(cf
));
770 // Definition: if type produces a formatting description, return that string, otherwise NULL
771 __private_extern__ CFStringRef
__CFCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
772 if (NULL
== cf
) HALT
;
773 if (CFTYPE_IS_OBJC(cf
)) {
774 static SEL s
= NULL
, r
= NULL
;
775 CFStringRef (*func
)(void *, SEL
, CFDictionaryRef
) = (CFStringRef (*)(void *, SEL
, CFDictionaryRef
))objc_msgSend
;
776 BOOL (*rfunc
)(void *, SEL
, SEL
) = (BOOL (*)(void *, SEL
, SEL
))objc_msgSend
;
777 if (!s
) s
= sel_registerName("_copyFormattingDescription:");
778 if (!r
) r
= sel_registerName("respondsToSelector:");
779 if (s
&& rfunc((void *)cf
, r
, s
)) return func((void *)cf
, s
, formatOptions
);
782 __CFGenericAssertIsCF(cf
);
783 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyFormattingDesc
) {
784 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyFormattingDesc(cf
, formatOptions
);
789 extern CFAllocatorRef
__CFAllocatorGetAllocator(CFTypeRef
);
791 CFAllocatorRef
CFGetAllocator(CFTypeRef cf
) {
792 if (NULL
== cf
) return kCFAllocatorSystemDefault
;
793 // CF: need to get allocator from objc objects in better way...how?
794 // -> bridging of CFAllocators and malloc_zone_t will help this
795 if (CFTYPE_IS_OBJC(cf
)) return __CFGetDefaultAllocator();
796 if (__kCFAllocatorTypeID_CONST
== __CFGenericTypeID_inline(cf
)) {
797 return __CFAllocatorGetAllocator(cf
);
799 return __CFGetAllocator(cf
);
802 extern void __CFBaseInitialize(void);
803 extern void __CFNullInitialize(void);
804 extern void __CFAllocatorInitialize(void);
805 extern void __CFStringInitialize(void);
806 extern void __CFArrayInitialize(void);
807 extern void __CFBooleanInitialize(void);
808 extern void __CFCharacterSetInitialize(void);
809 extern void __CFDataInitialize(void);
810 extern void __CFNumberInitialize(void);
811 extern void __CFStorageInitialize(void);
812 extern void __CFErrorInitialize(void);
813 extern void __CFTreeInitialize(void);
814 extern void __CFURLInitialize(void);
815 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
816 extern void __CFMachPortInitialize(void);
818 extern void __CFMessagePortInitialize(void);
819 extern void __CFRunLoopInitialize(void);
820 extern void __CFRunLoopObserverInitialize(void);
821 extern void __CFRunLoopSourceInitialize(void);
822 extern void __CFRunLoopTimerInitialize(void);
823 extern void __CFBundleInitialize(void);
824 extern void __CFPlugInInitialize(void);
825 extern void __CFPlugInInstanceInitialize(void);
826 extern void __CFUUIDInitialize(void);
827 extern void __CFBinaryHeapInitialize(void);
828 extern void __CFBitVectorInitialize(void);
829 #if DEPLOYMENT_TARGET_WINDOWS
830 extern void __CFWindowsMessageQueueInitialize(void);
831 extern void __CFWindowsNamedPipeInitialize(void);
832 extern void __CFBaseCleanup(void);
834 extern void __CFStreamInitialize(void);
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 {NULL
, NULL
}, // the last one is for optional "COMMAND_MODE" "legacy", do not use this slot, insert before
907 __private_extern__
const char *__CFgetenv(const char *n
) {
908 for (CFIndex idx
= 0; idx
< sizeof(__CFEnv
) / sizeof(__CFEnv
[0]); idx
++) {
909 if (__CFEnv
[idx
].name
&& 0 == strcmp(n
, __CFEnv
[idx
].name
)) return __CFEnv
[idx
].value
;
914 #if DEPLOYMENT_TARGET_WINDOWS
915 #define kNilPthreadT { nil, nil }
917 #define kNilPthreadT (pthread_t)0
921 CF_EXPORT pthread_t _CFMainPThread
;
922 pthread_t _CFMainPThread
= kNilPthreadT
;
924 CF_EXPORT
bool kCFUseCollectableAllocator
= false;
926 __private_extern__ Boolean __CFProphylacticAutofsAccess
= false;
928 #if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
929 static void __CFInitialize(void) __attribute__ ((constructor
));
932 #if DEPLOYMENT_TARGET_WINDOWS
935 void __CFInitialize(void) {
936 static int __done
= 0;
941 if (!pthread_main_np()) HALT
; // CoreFoundation must be initialized on the main thread
943 _CFMainPThread
= pthread_self();
945 __CFProphylacticAutofsAccess
= true;
947 for (CFIndex idx
= 0; idx
< sizeof(__CFEnv
) / sizeof(__CFEnv
[0]); idx
++) {
948 __CFEnv
[idx
].value
= __CFEnv
[idx
].name
? getenv(__CFEnv
[idx
].name
) : NULL
;
951 kCFUseCollectableAllocator
= objc_collectingEnabled();
952 if (kCFUseCollectableAllocator
) {
953 __CFObjCIsCollectable
= (bool (*)(void *))objc_isAuto
;
955 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
957 __CFStringGetUserDefaultEncoding(&s
, &r
); // force the potential setenv to occur early
958 pthread_atfork(__01121__
, NULL
, __01123__
);
959 const char *value2
= __CFgetenv("NSObjCMessageLoggingEnabled");
960 if (value2
&& (*value2
== 'Y' || *value2
== 'y')) instrumentObjcMessageSends(1);
961 #elif DEPLOYMENT_TARGET_WINDOWS
965 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
966 const char *value
= __CFgetenv("NSZombieEnabled");
967 if (value
&& (*value
== 'Y' || *value
== 'y')) __CFZombieEnabled
= 0xff;
968 value
= __CFgetenv("NSDeallocateZombies");
969 if (value
&& (*value
== 'Y' || *value
== 'y')) __CFDeallocateZombies
= 0xff;
971 _original_objc_dealloc
= (void *)_dealloc
;
974 value
= __CFgetenv("CFZombieLevel");
976 __CFZombieLevel
= (uint32_t)strtoul_l(value
, NULL
, 0, NULL
);
978 if (0x0 == __CFZombieLevel
) __CFZombieLevel
= 0x0000FC00; // default
982 __CFRuntimeClassTableSize
= 1024;
983 __CFRuntimeClassTable
= (CFRuntimeClass
**)calloc(__CFRuntimeClassTableSize
, sizeof(CFRuntimeClass
*));
984 __CFRuntimeObjCClassTable
= (uintptr_t *)calloc(__CFRuntimeClassTableSize
, sizeof(uintptr_t));
985 __CFBaseInitialize();
987 _CFRuntimeBridgeClasses(0, "__NSCFType");
988 for (CFIndex idx
= 1; idx
< __CFRuntimeClassTableSize
; idx
++) {
989 __CFRuntimeObjCClassTable
[idx
] = __CFRuntimeObjCClassTable
[0];
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 // Creating this lazily in CFRetain causes recursive call to CFRetain
1021 __CFRuntimeExternRefCountTable
= CFBagCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
);
1024 for (CFIndex idx
= 0; idx
< NUM_EXTERN_TABLES
; idx
++) {
1025 __NSRetainCounters
[idx
].table
= CFBasicHashCreate(kCFAllocatorSystemDefault
, kCFBasicHashHasCounts
| kCFBasicHashLinearHashing
| kCFBasicHashAggressiveGrowth
, &CFBasicHashNullCallbacks
);
1026 CFBasicHashSetCapacity(__NSRetainCounters
[idx
].table
, 40);
1027 __NSRetainCounters
[idx
].lock
= CFSpinLockInit
;
1030 /*** _CFRuntimeCreateInstance() can finally be called generally after this line. ***/
1032 __CFRuntimeClassTableCount
= 7;
1033 __CFStringInitialize(); // CFString's TypeID must be 0x7, now and forever
1034 __CFRuntimeClassTableCount
= 16;
1035 CFSetGetTypeID(); // See above for hard-coding of this position
1036 CFDictionaryGetTypeID(); // See above for hard-coding of this position
1037 __CFArrayInitialize(); // See above for hard-coding of this position
1038 __CFDataInitialize(); // See above for hard-coding of this position
1039 __CFNullInitialize(); // See above for hard-coding of this position
1040 __CFBooleanInitialize(); // See above for hard-coding of this position
1041 __CFNumberInitialize(); // See above for hard-coding of this position
1043 __CFBinaryHeapInitialize();
1044 __CFBitVectorInitialize();
1045 __CFCharacterSetInitialize();
1046 __CFStorageInitialize();
1047 __CFErrorInitialize();
1048 __CFTreeInitialize();
1049 __CFURLInitialize();
1050 __CFBundleInitialize();
1051 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1052 __CFPlugInInitialize();
1053 __CFPlugInInstanceInitialize();
1055 __CFUUIDInitialize();
1056 __CFMessagePortInitialize();
1057 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1058 __CFMachPortInitialize();
1060 __CFStreamInitialize();
1061 __CFRunLoopInitialize();
1062 __CFRunLoopObserverInitialize();
1063 __CFRunLoopSourceInitialize();
1064 __CFRunLoopTimerInitialize();
1070 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1071 args
= *_NSGetArgv();
1072 cnt
= *_NSGetArgc();
1073 #elif DEPLOYMENT_TARGET_WINDOWS
1074 wchar_t *commandLine
= GetCommandLineW();
1075 wchar_t **wideArgs
= CommandLineToArgvW(commandLine
, (int *)&cnt
);
1076 args
= (char **)malloc(sizeof(char *) * cnt
);
1077 for (int y
=0; y
< cnt
; y
++) {
1078 int bufSize
= lstrlenW(wideArgs
[y
]) + 20;
1079 char *arg
= (char *)malloc(sizeof(char) * bufSize
);
1080 int res
= WideCharToMultiByte(CP_ACP
, 1024 /*WC_NO_BEST_FIT_CHARS*/, wideArgs
[y
], -1, arg
, bufSize
, NULL
, NULL
);
1082 printf("CF - Error converting command line arg string to ascii: %x\n", (unsigned int)wideArgs
[y
]);
1087 CFStringRef
*list
, buffer
[256];
1088 list
= (cnt
<= 256) ? buffer
: (CFStringRef
*)malloc(cnt
* sizeof(CFStringRef
));
1089 for (idx
= 0, count
= 0; idx
< cnt
; idx
++) {
1090 if (NULL
== args
[idx
]) continue;
1091 list
[count
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, args
[idx
], kCFStringEncodingUTF8
);
1092 if (NULL
== list
[count
]) {
1093 list
[count
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, args
[idx
], kCFStringEncodingISOLatin1
);
1094 // We CANNOT use the string SystemEncoding here;
1095 // Do not argue: it is not initialized yet, but these
1096 // arguments MUST be initialized before it is.
1097 // We should just ignore the argument if the UTF-8
1098 // conversion fails, but out of charity we try once
1099 // more with ISO Latin1, a standard unix encoding.
1101 if (NULL
!= list
[count
]) count
++;
1103 __CFArgStuff
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)list
, count
, &kCFTypeArrayCallBacks
);
1106 _CFProcessPath(); // cache this early
1109 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1113 if (__CFRuntimeClassTableCount
< 256) __CFRuntimeClassTableCount
= 256;
1114 __CFSendObjCMsg
= (void *(*)(const void *, SEL
, ...))objc_msgSend
;
1116 #if DEPLOYMENT_TARGET_MACOSX
1117 #elif DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_EMBEDDED
1122 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1123 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard
)) {
1124 setenv("COMMAND_MODE", "legacy", 1);
1125 __CFEnv
[sizeof(__CFEnv
) / sizeof(__CFEnv
[0]) - 1].name
= "COMMAND_MODE";
1126 __CFEnv
[sizeof(__CFEnv
) / sizeof(__CFEnv
[0]) - 1].value
= "legacy";
1128 #elif DEPLOYMENT_TARGET_WINDOWS
1133 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED)
1134 CFLog(kCFLogLevelWarning
, CFSTR("Assertions enabled"));
1137 __CFProphylacticAutofsAccess
= false;
1142 #if DEPLOYMENT_TARGET_WINDOWS
1144 static CFBundleRef
RegisterCoreFoundationBundle(void) {
1146 // might be nice to get this from the project file at some point
1147 wchar_t *DLLFileName
= (wchar_t *)L
"CoreFoundation_debug.dll";
1149 wchar_t *DLLFileName
= (wchar_t *)L
"CoreFoundation.dll";
1151 wchar_t path
[MAX_PATH
+1];
1152 path
[0] = path
[1] = 0;
1155 HMODULE ourModule
= GetModuleHandleW(DLLFileName
);
1157 CFAssert(ourModule
, __kCFLogAssertion
, "GetModuleHandle failed");
1159 wResult
= GetModuleFileNameW(ourModule
, path
, MAX_PATH
+1);
1160 CFAssert1(wResult
> 0, __kCFLogAssertion
, "GetModuleFileName failed: %d", GetLastError());
1161 CFAssert1(wResult
< MAX_PATH
+1, __kCFLogAssertion
, "GetModuleFileName result truncated: %s", path
);
1163 // strip off last component, the DLL name
1164 for (idx
= wResult
- 1; idx
; idx
--) {
1165 if ('\\' == path
[idx
]) {
1171 CFStringRef fsPath
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, (UniChar
*)path
, idx
);
1172 CFURLRef dllURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, fsPath
, kCFURLWindowsPathStyle
, TRUE
);
1173 CFURLRef bundleURL
= CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault
, dllURL
, CFSTR("CoreFoundation.resources"), TRUE
);
1177 // this registers us so subsequent calls to CFBundleGetBundleWithIdentifier will succeed
1178 CFBundleRef bundle
= CFBundleCreate(kCFAllocatorSystemDefault
, bundleURL
);
1179 CFRelease(bundleURL
);
1185 #define DLL_PROCESS_ATTACH 1
1186 #define DLL_THREAD_ATTACH 2
1187 #define DLL_THREAD_DETACH 3
1188 #define DLL_PROCESS_DETACH 0
1190 int DllMain( HINSTANCE hInstance
, DWORD dwReason
, LPVOID pReserved
) {
1191 static CFBundleRef cfBundle
= NULL
;
1192 if (dwReason
== DLL_PROCESS_ATTACH
) {
1194 cfBundle
= RegisterCoreFoundationBundle();
1195 } else if (dwReason
== DLL_PROCESS_DETACH
) {
1196 __CFStreamCleanup();
1197 __CFSocketCleanup();
1198 __CFUniCharCleanup();
1201 if (cfBundle
) CFRelease(cfBundle
);
1202 __CFStringCleanup();
1203 } else if (dwReason
== DLL_THREAD_DETACH
) {
1204 __CFFinalizeThreadData(NULL
);
1211 CF_EXPORT CFTypeRef
_CFRetain(CFTypeRef cf
) {
1212 if (NULL
== cf
) return NULL
;
1213 Boolean didAuto
= false;
1215 if (0 == ((CFRuntimeBase
*)cf
)->_rc
&& !CF_IS_COLLECTABLE(cf
)) return cf
; // Constant CFTypeRef
1218 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
1219 } while (!OSAtomicCompareAndSwap32Barrier(lowBits
, lowBits
+ 1, (int32_t *)&((CFRuntimeBase
*)cf
)->_rc
));
1220 // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1221 if (lowBits
== 0 && CF_IS_COLLECTABLE(cf
)) {
1222 auto_zone_retain(auto_zone(), (void*)cf
);
1228 volatile UInt32
*infoLocation
= (UInt32
*)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1229 CFIndex rcLowBits
= __CFBitfieldGetValue(*infoLocation
, RC_END
, RC_START
);
1230 if (__builtin_expect(0 == rcLowBits
, 0) && !CF_IS_COLLECTABLE(cf
)) return cf
; // Constant CFTypeRef
1233 UInt32 initialCheckInfo
= *infoLocation
;
1234 UInt32 prospectiveNewInfo
= initialCheckInfo
; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1235 prospectiveNewInfo
+= (1 << RC_START
);
1236 rcLowBits
= __CFBitfieldGetValue(prospectiveNewInfo
, RC_END
, RC_START
);
1237 if (__builtin_expect((rcLowBits
& 0x7f) == 0, 0)) {
1238 /* Roll over another bit to the external ref count
1239 Real ref count = low 7 bits of info[CF_RC_BITS] + external ref count << 6
1240 Bit 8 of low bits indicates that external ref count is in use.
1241 External ref count is shifted by 6 rather than 7 so that we can set the low
1242 bits to to 1100 0000 rather than 1000 0000.
1243 This prevents needing to access the external ref count for successive retains and releases
1244 when the composite retain count is right around a multiple of 1 << 7.
1246 prospectiveNewInfo
= initialCheckInfo
;
1247 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, ((1 << 7) | (1 << 6)));
1248 __CFSpinLock(&__CFRuntimeExternRefCountTableLock
);
1249 success
= OSAtomicCompareAndSwap32Barrier(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1250 if (__builtin_expect(success
, 1)) {
1251 __CFDoExternRefOperation(350, (id
)cf
);
1253 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock
);
1255 success
= OSAtomicCompareAndSwap32Barrier(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1256 // XXX_PCB: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1257 if (success
&& __CFBitfieldGetValue(initialCheckInfo
, RC_END
, RC_START
) == 0 && CF_IS_COLLECTABLE(cf
)) {
1258 auto_zone_retain(auto_zone(), (void*)cf
);
1262 } while (__builtin_expect(!success
, 0));
1264 if (!didAuto
&& __builtin_expect(__CFOASafe
, 0)) {
1265 __CFRecordAllocationEvent(__kCFRetainEvent
, (void *)cf
, 0, 0, NULL
);
1270 CF_EXPORT
void _CFRelease(CFTypeRef cf
) {
1271 CFTypeID typeID
= __CFGenericTypeID_inline(cf
);
1272 Boolean isAllocator
= (__kCFAllocatorTypeID_CONST
== typeID
);
1273 Boolean didAuto
= false;
1277 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
1279 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(auto_zone(), (void*)cf
);
1280 return; // Constant CFTypeRef
1283 // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION
1284 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1285 if (cfClass
->version
& _kCFRuntimeResourcefulObject
&& cfClass
->reclaim
!= NULL
) {
1286 cfClass
->reclaim(cf
);
1288 if (!CF_IS_COLLECTABLE(cf
)) {
1289 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1293 // We recheck lowBits to see if the object has been retained again during
1294 // the finalization process. This allows for the finalizer to resurrect,
1295 // but the main point is to allow finalizers to be able to manage the
1296 // removal of objects from uniquing caches, which may race with other threads
1297 // which are allocating (looking up and finding) objects from those caches,
1298 // which (that thread) would be the thing doing the extra retain in that case.
1299 if (isAllocator
|| OSAtomicCompareAndSwap32Barrier(1, 0, (int32_t *)&((CFRuntimeBase
*)cf
)->_rc
)) {
1304 } while (!OSAtomicCompareAndSwap32Barrier(lowBits
, lowBits
- 1, (int32_t *)&((CFRuntimeBase
*)cf
)->_rc
));
1305 if (lowBits
== 1 && CF_IS_COLLECTABLE(cf
)) {
1306 // GC: release the collector's hold over the object, which will call the finalize function later on.
1307 auto_zone_release(auto_zone(), (void*)cf
);
1311 volatile UInt32
*infoLocation
= (UInt32
*)&(((CFRuntimeBase
*)cf
)->_cfinfo
);
1312 CFIndex rcLowBits
= __CFBitfieldGetValue(*infoLocation
, RC_END
, RC_START
);
1313 if (__builtin_expect(0 == rcLowBits
, 0)) {
1314 if (CF_IS_COLLECTABLE(cf
)) auto_zone_release(auto_zone(), (void*)cf
);
1315 return; // Constant CFTypeRef
1319 UInt32 initialCheckInfo
= *infoLocation
;
1320 rcLowBits
= __CFBitfieldGetValue(initialCheckInfo
, RC_END
, RC_START
);
1321 if (__builtin_expect(1 == rcLowBits
, 0)) {
1322 // we think cf should be deallocated
1323 // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION
1324 CFRuntimeClass
*cfClass
= __CFRuntimeClassTable
[typeID
];
1325 if (cfClass
->version
& _kCFRuntimeResourcefulObject
&& cfClass
->reclaim
!= NULL
) {
1326 cfClass
->reclaim(cf
);
1328 if (CF_IS_COLLECTABLE(cf
)) {
1329 UInt32 prospectiveNewInfo
= initialCheckInfo
- (1 << RC_START
);
1330 success
= OSAtomicCompareAndSwap32Barrier(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1331 // GC: release the collector's hold over the object, which will call the finalize function later on.
1333 auto_zone_release(auto_zone(), (void*)cf
);
1340 void (*func
)(CFTypeRef
) = __CFRuntimeClassTable
[typeID
]->finalize
;
1344 // We recheck rcLowBits to see if the object has been retained again during
1345 // the finalization process. This allows for the finalizer to resurrect,
1346 // but the main point is to allow finalizers to be able to manage the
1347 // removal of objects from uniquing caches, which may race with other threads
1348 // which are allocating (looking up and finding) objects from those caches,
1349 // which (that thread) would be the thing doing the extra retain in that case.
1350 rcLowBits
= __CFBitfieldGetValue(*infoLocation
, RC_END
, RC_START
);
1351 success
= (1 == rcLowBits
);
1352 if (__builtin_expect(success
, 1)) {
1359 UInt32 prospectiveNewInfo
= initialCheckInfo
; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1360 if (__builtin_expect((1 << 7) == rcLowBits
, 0)) {
1361 // Time to remove a bit from the external ref count
1362 __CFSpinLock(&__CFRuntimeExternRefCountTableLock
);
1363 CFIndex rcHighBitsCnt
= __CFDoExternRefOperation(500, (id
)cf
);
1364 if (1 == rcHighBitsCnt
) {
1365 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, (1 << 6) - 1);
1367 __CFBitfieldSetValue(prospectiveNewInfo
, RC_END
, RC_START
, ((1 << 6) | (1 << 7)) - 1);
1369 success
= OSAtomicCompareAndSwap32Barrier(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1370 if (__builtin_expect(success
, 1)) {
1371 __CFDoExternRefOperation(450, (id
)cf
);
1373 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock
);
1375 prospectiveNewInfo
-= (1 << RC_START
);
1376 success
= OSAtomicCompareAndSwap32Barrier(*(int32_t *)&initialCheckInfo
, *(int32_t *)&prospectiveNewInfo
, (int32_t *)infoLocation
);
1379 } while (__builtin_expect(!success
, 0));
1382 if (!didAuto
&& __builtin_expect(__CFOASafe
, 0)) {
1383 __CFRecordAllocationEvent(__kCFReleaseEvent
, (void *)cf
, 0, 0, NULL
);
1388 if (!didAuto
&& __builtin_expect(__CFOASafe
, 0)) {
1389 // do not use CFGetRetainCount() because cf has been freed if it was an allocator
1390 __CFRecordAllocationEvent(__kCFReleaseEvent
, (void *)cf
, 0, 0, NULL
);
1392 // cannot zombify allocators, which get deallocated by __CFAllocatorDeallocate (finalize)
1394 __CFAllocatorDeallocate((void *)cf
);
1396 CFAllocatorRef allocator
= kCFAllocatorSystemDefault
;
1397 Boolean usesSystemDefaultAllocator
= true;
1399 if (!__CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_cfinfo
[CF_INFO_BITS
], 7, 7)) {
1400 allocator
= CFGetAllocator(cf
);
1401 usesSystemDefaultAllocator
= (allocator
== kCFAllocatorSystemDefault
);
1404 if (__CFZombieEnabled
&& !kCFUseCollectableAllocator
) {
1405 Class cls
= object_getClass((id
)cf
);
1406 const char *name
= NULL
;
1407 __CFSpinLock(&__CFBigRuntimeFunnel
);
1408 for (CFIndex idx
= 0; !name
&& idx
< __CFRuntimeClassTableCount
; idx
++) {
1409 if ((uintptr_t)cls
== __CFRuntimeObjCClassTable
[idx
]) {
1410 CFRuntimeClass
*c
= __CFRuntimeClassTable
[idx
];
1411 if (c
) name
= c
->className
;
1414 __CFSpinUnlock(&__CFBigRuntimeFunnel
);
1415 // in 64-bit, a future class has nil isa, and calling class_getName()
1416 // on such will crash so we do this test
1417 if (!name
&& object_getClass((id
)cls
)) {
1418 name
= class_getName(cls
);
1420 if (!name
) name
= "$class-unknown$";
1422 asprintf(&cname
, "_NSZombie_%s", name
);
1423 Class zclass
= (Class
)objc_lookUpClass(cname
);
1425 zclass
= objc_duplicateClass((Class
)objc_lookUpClass("_NSZombie_"), cname
, 0);
1429 #if DEPLOYMENT_TARGET_MACOSX
1430 if (object_getClass((id
)cls
)) {
1431 objc_destructInstance((id
)cf
);
1434 if (__CFDeallocateZombies
) {
1436 object_setClass((id
)cf
, zclass
);
1438 // Set 'isa' pointer only if using standard deallocator
1439 // However, _internal_object_dispose is not exported from libobjc
1440 if (_dealloc
== _original_objc_dealloc
) {
1441 object_setClass((id
)cf
, zclass
);
1444 CFAllocatorDeallocate(allocator
, (uint8_t *)cf
- (usesSystemDefaultAllocator
? 0 : sizeof(CFAllocatorRef
)));
1446 object_setClass((id
)cf
, zclass
);
1450 extern uintptr_t __CFFindPointer(uintptr_t ptr
, uintptr_t start
);
1451 uintptr_t res
= __CFFindPointer((uintptr_t)cf
, 0);
1453 if (res
< (uintptr_t)&cf
- 4 * 4096 || (uintptr_t)&cf
+ 4096 < res
) {
1454 printf("*** NSZombie warning: object %p deallocated, but reference still found at %p (%p %p)\n", cf
, res
);
1456 res
= __CFFindPointer((uintptr_t)cf
, res
+ 1);
1461 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1462 if (kCFUseCollectableAllocator
|| !(__CFZombieLevel
& (1 << 4))) {
1463 Class cls
= object_getClass((id
)cf
);
1464 if (object_getClass((id
)cls
)) {
1465 objc_removeAssociatedObjects((id
)cf
);
1469 if ((__CFZombieLevel
& (1 << 0)) && !kCFUseCollectableAllocator
) {
1470 uint8_t *ptr
= (uint8_t *)cf
- (usesSystemDefaultAllocator
? 0 : sizeof(CFAllocatorRef
));
1471 size_t size
= malloc_size(ptr
);
1472 uint8_t byte
= 0xFC;
1473 if (__CFZombieLevel
& (1 << 1)) {
1474 ptr
= (uint8_t *)cf
+ sizeof(CFRuntimeBase
);
1475 size
= size
- sizeof(CFRuntimeBase
) - (usesSystemDefaultAllocator
? 0 : sizeof(CFAllocatorRef
));
1477 if (__CFZombieLevel
& (1 << 7)) {
1478 byte
= (__CFZombieLevel
>> 8) & 0xFF;
1480 memset(ptr
, byte
, size
);
1482 if (kCFUseCollectableAllocator
|| !(__CFZombieLevel
& (1 << 4))) {
1483 CFAllocatorDeallocate(allocator
, (uint8_t *)cf
- (usesSystemDefaultAllocator
? 0 : sizeof(CFAllocatorRef
)));
1487 if (kCFAllocatorSystemDefault
!= allocator
) {
1488 CFRelease(allocator
);
1493 #undef __kCFAllocatorTypeID_CONST
1494 #undef __CFGenericAssertIsCF