2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Christopher Kane
30 #include "CFRuntime.h"
31 #include "CFInternal.h"
36 #include <mach-o/dyld.h>
37 #include <crt_externs.h>
39 #define __is_threaded (1)
42 extern size_t malloc_size(const void *ptr
);
43 extern int __setonlyClocaleconv(int val
);
46 extern void __CFRecordAllocationEvent(int eventnum
, void *ptr
, int size
, int data
, const char *classname
);
48 #define __CFRecordAllocationEvent(a, b, c, d, e)
52 // retain/release recording constants -- must match values
53 // used by OA for now; probably will change in the future
54 __kCFRetainEvent
= 28,
55 __kCFReleaseEvent
= 29
58 /* On Win32 we should use _msize instead of malloc_size
59 * (Aleksey Dukhnyakov)
61 #if defined(__WIN32__)
63 CF_INLINE
size_t malloc_size(void *memblock
) {
64 return _msize(memblock
);
70 bool __CFOASafe
= false;
72 void __CFOAInitialize(void) {
73 static void (*dyfunc
)(void) = (void *)0xFFFFFFFF;
74 if (NULL
== getenv("OAKeepAllocationStatistics")) return;
75 if ((void *)0xFFFFFFFF == dyfunc
) {
77 if (NSIsSymbolNameDefined("__OAInitialize"))
78 dyfunc
= (void *)NSAddressOfSymbol(NSLookupAndBindSymbol("__OAInitialize"));
86 void __CFRecordAllocationEvent(int eventnum
, void *ptr
, int size
, int data
, const char *classname
) {
87 static void (*dyfunc
)(int, void *, int, int, const char *) = (void *)0xFFFFFFFF;
88 if (!__CFOASafe
) return;
89 if ((void *)0xFFFFFFFF == dyfunc
) {
91 if (NSIsSymbolNameDefined("__OARecordAllocationEvent"))
92 dyfunc
= (void *)NSAddressOfSymbol(NSLookupAndBindSymbol("__OARecordAllocationEvent"));
95 dyfunc(eventnum
, ptr
, size
, data
, classname
);
99 void __CFSetLastAllocationEventName(void *ptr
, const char *classname
) {
100 static void (*dyfunc
)(void *, const char *) = (void *)0xFFFFFFFF;
101 if (!__CFOASafe
) return;
102 if ((void *)0xFFFFFFFF == dyfunc
) {
104 if (NSIsSymbolNameDefined("__OASetLastAllocationEventName"))
105 dyfunc
= (void *)NSAddressOfSymbol(NSLookupAndBindSymbol("__OASetLastAllocationEventName"));
107 if (NULL
!= dyfunc
) {
108 dyfunc(ptr
, classname
);
113 extern void __HALT(void);
115 static CFTypeID __kCFNotATypeTypeID
= _kCFRuntimeNotATypeID
;
117 static const CFRuntimeClass __CFNotATypeClass
= {
129 static CFTypeID __kCFTypeTypeID
= _kCFRuntimeNotATypeID
;
131 static const CFRuntimeClass __CFTypeClass
= {
143 /* bits 15-8 in the CFRuntimeBase _info are type */
144 /* bits 7-0 in the CFRuntimeBase are reserved for CF's use */
146 static CFRuntimeClass
* __CFRuntimeClassTable
[__CFMaxRuntimeTypes
] = {NULL
};
147 static int32_t __CFRuntimeClassTableCount
= 0;
149 #if defined(__MACH__)
151 __private_extern__
SEL (*__CFGetObjCSelector
)(const char *) = NULL
;
152 __private_extern__
void * (*__CFSendObjCMsg
)(const void *, SEL
, ...) = NULL
;
154 __private_extern__
struct objc_class
*__CFRuntimeObjCClassTable
[__CFMaxRuntimeTypes
] = {NULL
};
158 // Compiler uses this symbol name
159 int __CFConstantStringClassReference
[10] = {0};
161 #if defined(__MACH__)
162 static struct objc_class __CFNSTypeClass
= {{0, 0}, NULL
, {0, 0, 0, 0, 0, 0, 0}};
164 static void *__CFNSTypeClass
[10] = {NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
167 //static CFSpinLock_t __CFRuntimeLock = 0;
169 CFTypeID
_CFRuntimeRegisterClass(const CFRuntimeClass
* const cls
) {
170 // version field must be 0
171 // className must be pure ASCII string, non-null
172 if (__CFMaxRuntimeTypes
<= __CFRuntimeClassTableCount
) {
173 CFLog(0, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls
->className
);
174 return _kCFRuntimeNotATypeID
;
176 __CFRuntimeClassTable
[__CFRuntimeClassTableCount
++] = (CFRuntimeClass
*)cls
;
177 return __CFRuntimeClassTableCount
- 1;
180 const CFRuntimeClass
* _CFRuntimeGetClassWithTypeID(CFTypeID typeID
) {
181 return __CFRuntimeClassTable
[typeID
];
184 void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID
) {
185 __CFRuntimeClassTable
[typeID
] = NULL
;
191 /* CFZombieLevel levels:
192 * bit 0: scribble deallocated CF object memory
193 * bit 1: do not scribble on CFRuntimeBase header (when bit 0)
194 * bit 4: do not free CF objects
195 * bit 7: use 3rd-order byte as scribble byte for dealloc (otherwise 0xFC)
196 * bit 16: scribble allocated CF object memory
197 * bit 23: use 1st-order byte as scribble byte for alloc (otherwise 0xCF)
200 static uint32_t __CFZombieLevel
= 0x0;
202 static void __CFZombifyAllocatedMemory(void *cf
) {
203 if (__CFZombieLevel
& (1 << 16)) {
205 size_t size
= malloc_size(cf
);
207 if (__CFZombieLevel
& (1 << 23)) {
208 byte
= (__CFZombieLevel
>> 24) & 0xFF;
210 memset(ptr
, byte
, size
);
214 static void __CFZombifyDeallocatedMemory(void *cf
) {
215 if (__CFZombieLevel
& (1 << 0)) {
217 size_t size
= malloc_size(cf
);
219 if (__CFZombieLevel
& (1 << 1)) {
220 ptr
+= sizeof(CFRuntimeBase
);
221 size
-= sizeof(CFRuntimeBase
);
223 if (__CFZombieLevel
& (1 << 7)) {
224 byte
= (__CFZombieLevel
>> 8) & 0xFF;
226 memset(ptr
, byte
, size
);
232 CFTypeRef
_CFRuntimeCreateInstance(CFAllocatorRef allocator
, CFTypeID typeID
, uint32_t extraBytes
, unsigned char *category
) {
233 CFRuntimeBase
*memory
;
234 Boolean usesSystemDefaultAllocator
;
237 if (NULL
== __CFRuntimeClassTable
[typeID
]) {
240 allocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : allocator
;
241 usesSystemDefaultAllocator
= (allocator
== kCFAllocatorSystemDefault
);
242 extraBytes
= (extraBytes
+ (sizeof(void *) - 1)) & ~(sizeof(void *) - 1);
243 size
= sizeof(CFRuntimeBase
) + extraBytes
+ (usesSystemDefaultAllocator
? 0 : sizeof(CFAllocatorRef
));
244 memory
= CFAllocatorAllocate(allocator
, size
, 0);
245 if (NULL
== memory
) {
249 __CFZombifyAllocatedMemory((void *)memory
);
251 if (__CFOASafe
&& category
) {
252 __CFSetLastAllocationEventName(memory
, category
);
253 } else if (__CFOASafe
) {
254 __CFSetLastAllocationEventName(memory
, __CFRuntimeClassTable
[typeID
]->className
);
256 if (!usesSystemDefaultAllocator
) {
257 *(CFAllocatorRef
*)((char *)memory
) = CFRetain(allocator
);
258 memory
= (CFRuntimeBase
*)((char *)memory
+ sizeof(CFAllocatorRef
));
260 memory
->_isa
= __CFISAForTypeID(typeID
);
263 __CFBitfieldSetValue(memory
->_info
, 15, 8, typeID
);
264 if (usesSystemDefaultAllocator
) {
265 __CFBitfieldSetValue(memory
->_info
, 7, 7, 1);
267 if (NULL
!= __CFRuntimeClassTable
[typeID
]->init
) {
268 (__CFRuntimeClassTable
[typeID
]->init
)(memory
);
273 void _CFRuntimeSetInstanceTypeID(CFTypeRef cf
, CFTypeID typeID
) {
274 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_info
, 15, 8, typeID
);
277 CFTypeID
__CFGenericTypeID(const void *cf
) {
278 return __CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_info
, 15, 8);
281 CF_INLINE CFTypeID
__CFGenericTypeID_inline(const void *cf
) {
282 return __CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_info
, 15, 8);
285 CFTypeID
CFTypeGetTypeID(void) {
286 return __kCFTypeTypeID
;
289 __private_extern__
void __CFGenericValidateType_(CFTypeRef cf
, CFTypeID type
, const char *func
) {
290 if (cf
&& CF_IS_OBJC(type
, cf
)) return;
291 CFAssert2((cf
!= NULL
) && (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]) && (__kCFNotATypeTypeID
!= __CFGenericTypeID_inline(cf
)) && (__kCFTypeTypeID
!= __CFGenericTypeID_inline(cf
)), __kCFLogAssertion
, "%s(): pointer 0x%x is not a CF object", func
, cf
); \
292 CFAssert3(__CFGenericTypeID_inline(cf
) == type
, __kCFLogAssertion
, "%s(): pointer 0x%x is not a %s", func
, cf
, __CFRuntimeClassTable
[type
]->className
); \
295 #define __CFGenericAssertIsCF(cf) \
296 CFAssert2(cf != NULL && (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]) && (__kCFNotATypeTypeID != __CFGenericTypeID_inline(cf)) && (__kCFTypeTypeID != __CFGenericTypeID_inline(cf)), __kCFLogAssertion, "%s(): pointer 0x%x is not a CF object", __PRETTY_FUNCTION__, cf);
298 #if !defined(__MACH__)
300 #define CFTYPE_IS_OBJC(obj) (false)
301 #define CFTYPE_OBJC_FUNCDISPATCH0(rettype, obj, sel) do {} while (0)
302 #define CFTYPE_OBJC_FUNCDISPATCH1(rettype, obj, sel, a1) do {} while (0)
306 #if defined(__MACH__)
308 CF_INLINE
int CFTYPE_IS_OBJC(const void *obj
) {
309 CFTypeID typeID
= __CFGenericTypeID_inline(obj
);
310 return CF_IS_OBJC(typeID
, obj
) && __CFSendObjCMsg
;
313 #define CFTYPE_OBJC_FUNCDISPATCH0(rettype, obj, sel) \
314 if (CFTYPE_IS_OBJC(obj)) \
315 {rettype (*func)(void *, SEL) = (void *)__CFSendObjCMsg; \
316 static SEL s = NULL; if (!s) s = __CFGetObjCSelector(sel); \
317 return func((void *)obj, s);}
318 #define CFTYPE_OBJC_FUNCDISPATCH1(rettype, obj, sel, a1) \
319 if (CFTYPE_IS_OBJC(obj)) \
320 {rettype (*func)(void *, SEL, ...) = (void *)__CFSendObjCMsg; \
321 static SEL s = NULL; if (!s) s = __CFGetObjCSelector(sel); \
322 return func((void *)obj, s, (a1));}
326 CFTypeID
CFGetTypeID(CFTypeRef cf
) {
328 if (NULL
== cf
) HALT
;
330 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeID
, cf
, "_cfTypeID");
331 __CFGenericAssertIsCF(cf
);
332 return __CFGenericTypeID_inline(cf
);
335 CFStringRef
CFCopyTypeIDDescription(CFTypeID type
) {
336 CFAssert2((NULL
!= __CFRuntimeClassTable
[type
]) && __kCFNotATypeTypeID
!= type
&& __kCFTypeTypeID
!= type
, __kCFLogAssertion
, "%s(): type %d is not a CF type ID", __PRETTY_FUNCTION__
, type
);
337 return CFStringCreateWithCString(kCFAllocatorDefault
, __CFRuntimeClassTable
[type
]->className
, kCFStringEncodingASCII
);
340 static CFSpinLock_t __CFGlobalRetainLock
= 0;
341 static CFMutableDictionaryRef __CFRuntimeExternRefCountTable
= NULL
;
343 #define DISGUISE(object) ((void *)(((unsigned)object) + 1))
344 #define UNDISGUISE(disguised) ((id)(((unsigned)disguised) - 1))
346 extern void _CFDictionaryIncrementValue(CFMutableDictionaryRef dict
, const void *key
);
347 extern int _CFDictionaryDecrementValue(CFMutableDictionaryRef dict
, const void *key
);
349 // Bit 31 (highest bit) in second word of cf instance indicates external ref count
351 CFTypeRef
CFRetain(CFTypeRef cf
) {
353 bool is_threaded
= __is_threaded
;
355 if (NULL
== cf
) HALT
;
357 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeRef
, cf
, "retain");
358 __CFGenericAssertIsCF(cf
);
359 if (is_threaded
) __CFSpinLock(&__CFGlobalRetainLock
);
360 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
361 if (0 == lowBits
) { // Constant CFTypeRef
362 if (is_threaded
) __CFSpinUnlock(&__CFGlobalRetainLock
);
366 if ((lowBits
& 0x07fff) == 0) {
367 // Roll over another bit to the external ref count
368 _CFDictionaryIncrementValue(__CFRuntimeExternRefCountTable
, DISGUISE(cf
));
369 lowBits
= 0x8000; // Bit 16 indicates external ref count
371 ((CFRuntimeBase
*)cf
)->_rc
= lowBits
;
372 if (is_threaded
) __CFSpinUnlock(&__CFGlobalRetainLock
);
374 uint64_t compositeRC
;
375 compositeRC
= (lowBits
& 0x7fff) + ((uint64_t)(uintptr_t)CFDictionaryGetValue(__CFRuntimeExternRefCountTable
, DISGUISE(cf
)) << 15);
376 if (compositeRC
> (uint64_t)0x7fffffff) compositeRC
= (uint64_t)0x7fffffff;
377 __CFRecordAllocationEvent(__kCFRetainEvent
, (void *)cf
, 0, compositeRC
, NULL
);
382 __private_extern__
void __CFAllocatorDeallocate(CFTypeRef cf
);
384 void CFRelease(CFTypeRef cf
) {
386 bool is_threaded
= __is_threaded
;
388 if (NULL
== cf
) HALT
;
390 CFTYPE_OBJC_FUNCDISPATCH0(void, cf
, "release");
391 __CFGenericAssertIsCF(cf
);
392 if (is_threaded
) __CFSpinLock(&__CFGlobalRetainLock
);
393 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
394 if (0 == lowBits
) { // Constant CFTypeRef
395 if (is_threaded
) __CFSpinUnlock(&__CFGlobalRetainLock
);
399 if (is_threaded
) __CFSpinUnlock(&__CFGlobalRetainLock
);
400 if (__CFOASafe
) __CFRecordAllocationEvent(__kCFReleaseEvent
, (void *)cf
, 0, 0, NULL
);
401 if (__kCFAllocatorTypeID_CONST
== __CFGenericTypeID_inline(cf
)) {
403 __CFZombifyDeallocatedMemory((void *)cf
);
404 if (!(__CFZombieLevel
& (1 << 4))) {
405 __CFAllocatorDeallocate((void *)cf
);
408 __CFAllocatorDeallocate((void *)cf
);
411 CFAllocatorRef allocator
;
412 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->finalize
) {
413 __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->finalize(cf
);
415 if (__CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_info
, 7, 7)) {
416 allocator
= kCFAllocatorSystemDefault
;
418 allocator
= CFGetAllocator(cf
);
419 (intptr_t)cf
-= sizeof(CFAllocatorRef
);
422 __CFZombifyDeallocatedMemory((void *)cf
);
423 if (!(__CFZombieLevel
& (1 << 4))) {
424 CFAllocatorDeallocate(allocator
, (void *)cf
);
427 CFAllocatorDeallocate(allocator
, (void *)cf
);
429 if (kCFAllocatorSystemDefault
!= allocator
) {
430 CFRelease(allocator
);
434 if (0x8000 == lowBits
) {
435 // Time to remove a bit from the external ref count
436 if (0 == _CFDictionaryDecrementValue(__CFRuntimeExternRefCountTable
, DISGUISE(cf
))) {
444 ((CFRuntimeBase
*)cf
)->_rc
= lowBits
;
445 if (is_threaded
) __CFSpinUnlock(&__CFGlobalRetainLock
);
447 uint64_t compositeRC
;
448 compositeRC
= (lowBits
& 0x7fff) + ((uint64_t)(uintptr_t)CFDictionaryGetValue(__CFRuntimeExternRefCountTable
, DISGUISE(cf
)) << 15);
449 if (compositeRC
> (uint64_t)0x7fffffff) compositeRC
= (uint64_t)0x7fffffff;
450 __CFRecordAllocationEvent(__kCFReleaseEvent
, (void *)cf
, 0, compositeRC
, NULL
);
455 static uint64_t __CFGetFullRetainCount(CFTypeRef cf
) {
456 uint32_t lowBits
= 0;
457 uint64_t highBits
= 0, compositeRC
;
458 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
460 return (uint64_t)0x00FFFFFFFFFFFFFFULL
;
462 if ((lowBits
& 0x08000) != 0) {
463 highBits
= (uint64_t)(uintptr_t)CFDictionaryGetValue(__CFRuntimeExternRefCountTable
, DISGUISE(cf
));
465 compositeRC
= (lowBits
& 0x7fff) + (highBits
<< 15);
469 CFIndex
CFGetRetainCount(CFTypeRef cf
) {
473 if (NULL
== cf
) HALT
;
475 CFTYPE_OBJC_FUNCDISPATCH0(CFIndex
, cf
, "retainCount");
476 __CFGenericAssertIsCF(cf
);
477 rc
= __CFGetFullRetainCount(cf
);
478 result
= (rc
< (uint64_t)0x7FFFFFFF) ? (CFIndex
)rc
: (CFIndex
)0x7FFFFFFF;
482 Boolean
CFEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
484 if (NULL
== cf1
) HALT
;
485 if (NULL
== cf2
) HALT
;
487 if (cf1
== cf2
) return true;
488 CFTYPE_OBJC_FUNCDISPATCH1(Boolean
, cf1
, "isEqual:", cf2
);
489 CFTYPE_OBJC_FUNCDISPATCH1(Boolean
, cf2
, "isEqual:", cf1
);
490 __CFGenericAssertIsCF(cf1
);
491 __CFGenericAssertIsCF(cf2
);
492 if (__CFGenericTypeID_inline(cf1
) != __CFGenericTypeID_inline(cf2
)) return false;
493 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf1
)]->equal
) {
494 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf1
)]->equal(cf1
, cf2
);
499 CFHashCode
CFHash(CFTypeRef cf
) {
501 if (NULL
== cf
) HALT
;
503 CFTYPE_OBJC_FUNCDISPATCH0(CFHashCode
, cf
, "hash");
504 __CFGenericAssertIsCF(cf
);
505 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->hash
) {
506 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->hash(cf
);
508 return (CFHashCode
)cf
;
511 // definition: produces a normally non-NULL debugging description of the object
512 CFStringRef
CFCopyDescription(CFTypeRef cf
) {
514 if (NULL
== cf
) HALT
;
516 CFTYPE_OBJC_FUNCDISPATCH0(CFStringRef
, cf
, "_copyDescription");
517 __CFGenericAssertIsCF(cf
);
518 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyDebugDesc
) {
520 result
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyDebugDesc(cf
);
521 if (NULL
!= result
) return result
;
523 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<%s %p [%p]>"), __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->className
, cf
, CFGetAllocator(cf
));
526 // Definition: if type produces a formatting description, return that string, otherwise NULL
527 __private_extern__ CFStringRef
__CFCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
529 if (NULL
== cf
) HALT
;
531 #if defined(__MACH__)
532 if (CFTYPE_IS_OBJC(cf
)) {
533 static SEL s
= NULL
, r
= NULL
;
534 CFStringRef (*func
)(void *, SEL
, ...) = (void *)__CFSendObjCMsg
;
535 if (!s
) s
= __CFGetObjCSelector("_copyFormattingDescription:");
536 if (!r
) r
= __CFGetObjCSelector("respondsToSelector:");
537 if (s
&& func((void *)cf
, r
, s
)) return func((void *)cf
, s
, formatOptions
);
541 __CFGenericAssertIsCF(cf
);
542 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyFormattingDesc
) {
543 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyFormattingDesc(cf
, formatOptions
);
548 extern CFAllocatorRef
__CFAllocatorGetAllocator(CFTypeRef
);
550 CFAllocatorRef
CFGetAllocator(CFTypeRef cf
) {
552 if (NULL
== cf
) HALT
;
554 // CF: need to get allocator from objc objects in better way...how?
555 // -> bridging of CFAllocators and malloc_zone_t will help this
556 if (CFTYPE_IS_OBJC(cf
)) return __CFGetDefaultAllocator();
557 if (__kCFAllocatorTypeID_CONST
== __CFGenericTypeID_inline(cf
)) {
558 return __CFAllocatorGetAllocator(cf
);
560 return __CFGetAllocator(cf
);
563 extern void __CFBaseInitialize(void);
564 extern void __CFNullInitialize(void);
565 extern void __CFAllocatorInitialize(void);
566 extern void __CFStringInitialize(void);
567 extern void __CFArrayInitialize(void);
568 extern void __CFBagInitialize(void);
569 extern void __CFBooleanInitialize(void);
570 extern void __CFCharacterSetInitialize(void);
571 extern void __CFDataInitialize(void);
572 extern void __CFDateInitialize(void);
573 extern void __CFDictionaryInitialize(void);
574 extern void __CFNumberInitialize(void);
575 extern void __CFSetInitialize(void);
576 extern void __CFStorageInitialize(void);
577 extern void __CFTimeZoneInitialize(void);
578 extern void __CFTreeInitialize(void);
579 extern void __CFURLInitialize(void);
580 extern void __CFXMLNodeInitialize(void);
581 extern void __CFXMLParserInitialize(void);
582 #if defined(__MACH__)
583 extern void __CFMessagePortInitialize(void);
584 extern void __CFMachPortInitialize(void);
586 #if defined(__MACH__) || defined(__WIN32__)
587 extern void __CFRunLoopInitialize(void);
588 extern void __CFRunLoopObserverInitialize(void);
589 extern void __CFRunLoopSourceInitialize(void);
590 extern void __CFRunLoopTimerInitialize(void);
591 extern void __CFSocketInitialize(void);
593 extern void __CFBundleInitialize(void);
594 extern void __CFPlugInInitialize(void);
595 extern void __CFPlugInInstanceInitialize(void);
596 extern void __CFUUIDInitialize(void);
597 extern void __CFBinaryHeapInitialize(void);
598 extern void __CFBitVectorInitialize(void);
601 #define DO_SYSCALL_TRACE_HELPERS 1
603 #if defined(DO_SYSCALL_TRACE_HELPERS) && defined(__MACH__)
604 extern void ptrace(int, int, int, int);
605 #define SYSCALL_TRACE(N) do ptrace(N, 0, 0, 0); while (0)
607 #define SYSCALL_TRACE(N) do {} while (0)
610 #if defined(__MACH__) && defined(PROFILE)
611 static void _CF_mcleanup(void) {
616 extern CFTypeID
CFTimeZoneGetTypeID(void);
617 extern CFTypeID
CFNumberGetTypeID(void);
618 extern CFTypeID
CFBooleanGetTypeID(void);
620 const void *__CFArgStuff
= NULL
;
621 __private_extern__
void *__CFAppleLanguages
= NULL
;
622 __private_extern__
void *__CFSessionID
= NULL
;
624 #if defined(__LINUX__) || defined(__FREEBSD__)
625 static void __CFInitialize(void) __attribute__ ((constructor
));
628 #if defined(__WIN32__)
631 void __CFInitialize(void) {
632 static int __done
= 0;
633 if (sizeof(int) != sizeof(long) || 4 != sizeof(long)) __HALT();
638 SYSCALL_TRACE(0xC000);
640 __setonlyClocaleconv(1);
643 const char *value
= getenv("CFZombieLevel");
645 __CFZombieLevel
= strtoul(value
, NULL
, 0);
647 if (0x0 == __CFZombieLevel
) __CFZombieLevel
= 0xCF00FC00; // default
650 #if defined(__MACH__) && defined(PROFILE)
652 const char *v
= getenv("DYLD_IMAGE_SUFFIX");
653 const char *p
= getenv("CFPROF_ENABLE");
654 // ckane: People were upset that I added this feature to allow for the profiling of
655 // libraries using unprofiled apps/executables, so ensure they cannot get this accidentally.
656 if (v
&& p
&& 0 == strcmp("_profile", v
) && 0 == strcmp(crypt(p
+ 2, p
) + 2, "eQJhkVvMm.w")) {
657 // Unfortunately, no way to know if this has already been done,
658 // or I would not do it. Not much information will be lost.
659 atexit(_CF_mcleanup
);
665 __CFBaseInitialize();
667 #if defined(__MACH__)
668 for (idx
= 0; idx
< __CFMaxRuntimeTypes
; idx
++) {
669 __CFRuntimeObjCClassTable
[idx
] = &__CFNSTypeClass
;
673 /* Here so that two runtime classes get indices 0, 1. */
674 __kCFNotATypeTypeID
= _CFRuntimeRegisterClass(&__CFNotATypeClass
);
675 __kCFTypeTypeID
= _CFRuntimeRegisterClass(&__CFTypeClass
);
677 /* Here so that __kCFAllocatorTypeID gets index 2. */
678 __CFAllocatorInitialize();
680 /* Basic collections need to be up before CFString. */
681 __CFDictionaryInitialize();
682 __CFArrayInitialize();
683 __CFDataInitialize();
686 #if defined(__MACH__)
688 char **args
= *_NSGetArgv();
690 for (idx
= 1; idx
< cnt
- 1; idx
++) {
691 if (0 == strcmp(args
[idx
], "-AppleLanguages")) {
692 CFIndex length
= strlen(args
[idx
+ 1]);
693 __CFAppleLanguages
= malloc(length
+ 1);
694 memmove(__CFAppleLanguages
, args
[idx
+ 1], length
+ 1);
701 #if defined(__MACH__)
702 // Pre-initialize for possible future toll-free bridging
703 // These have to be initialized before the *Initialize functions below are called
704 __CFRuntimeObjCClassTable
[CFDictionaryGetTypeID()] = (struct objc_class
*)calloc(sizeof(struct objc_class
), 1);
705 __CFRuntimeObjCClassTable
[CFArrayGetTypeID()] = (struct objc_class
*)calloc(sizeof(struct objc_class
), 1);
706 __CFRuntimeObjCClassTable
[CFDataGetTypeID()] = (struct objc_class
*)calloc(sizeof(struct objc_class
), 1);
707 __CFRuntimeObjCClassTable
[CFSetGetTypeID()] = (struct objc_class
*)calloc(sizeof(struct objc_class
), 1);
708 __CFRuntimeObjCClassTable
[0x7] = (struct objc_class
*)&__CFConstantStringClassReference
;
709 __CFRuntimeObjCClassTable
[0x8] = (struct objc_class
*)calloc(sizeof(struct objc_class
), 1);
710 __CFRuntimeObjCClassTable
[0x9] = (struct objc_class
*)calloc(sizeof(struct objc_class
), 1);
711 __CFRuntimeObjCClassTable
[0xa] = (struct objc_class
*)calloc(sizeof(struct objc_class
), 1);
712 __CFRuntimeObjCClassTable
[0xb] = (struct objc_class
*)calloc(sizeof(struct objc_class
), 1);
713 __CFRuntimeObjCClassTable
[0xc] = (struct objc_class
*)calloc(sizeof(struct objc_class
), 1);
716 // Creating this lazily in CFRetain causes recursive call to CFRetain
717 __CFRuntimeExternRefCountTable
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, NULL
);
719 /*** _CFRuntimeCreateInstance() can finally be called generally after this line. ***/
721 __CFStringInitialize(); // CFString's TypeID must be 0x7, now and forever
722 __CFNullInitialize(); // See above for hard-coding of this position
723 __CFBooleanInitialize(); // See above for hard-coding of this position
724 __CFNumberInitialize(); // See above for hard-coding of this position
725 __CFDateInitialize(); // See above for hard-coding of this position
726 __CFTimeZoneInitialize(); // See above for hard-coding of this position
728 __CFBinaryHeapInitialize();
729 __CFBitVectorInitialize();
731 __CFCharacterSetInitialize();
732 __CFStorageInitialize();
733 __CFTreeInitialize();
735 __CFXMLNodeInitialize();
736 __CFXMLParserInitialize();
737 __CFBundleInitialize();
738 __CFPlugInInitialize();
739 __CFPlugInInstanceInitialize();
740 __CFUUIDInitialize();
741 #if defined(__MACH__)
742 __CFMessagePortInitialize();
743 __CFMachPortInitialize();
745 #if defined(__MACH__) || defined(__WIN32__)
746 __CFRunLoopInitialize();
747 __CFRunLoopObserverInitialize();
748 __CFRunLoopSourceInitialize();
749 __CFRunLoopTimerInitialize();
750 __CFSocketInitialize();
753 #if defined(__MACH__)
754 // Pre-initialize for possible future toll-free bridging, continued
755 __CFRuntimeObjCClassTable
[CFRunLoopTimerGetTypeID()] = (struct objc_class
*)calloc(sizeof(struct objc_class
), 1);
756 __CFRuntimeObjCClassTable
[CFMachPortGetTypeID()] = (struct objc_class
*)calloc(sizeof(struct objc_class
), 1);
757 __CFRuntimeObjCClassTable
[CFURLGetTypeID()] = (struct objc_class
*)calloc(sizeof(struct objc_class
), 1);
758 __CFRuntimeObjCClassTable
[CFCharacterSetGetTypeID()] = (struct objc_class
*)calloc(sizeof(struct objc_class
), 1);
761 SYSCALL_TRACE(0xC001);
763 #if defined(__MACH__)
765 char **args
= *_NSGetArgv();
768 CFStringRef
*list
, buffer
[256];
769 list
= (cnt
<= 256) ? buffer
: malloc(cnt
* sizeof(CFStringRef
));
770 for (idx
= 0, count
= 0; idx
< cnt
&& args
[idx
]; idx
++) {
771 list
[count
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, args
[idx
], kCFStringEncodingUTF8
);
772 if (NULL
== list
[count
]) {
773 list
[count
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, args
[idx
], kCFStringEncodingISOLatin1
);
774 // We CANNOT use the string SystemEncoding here;
775 // Do not argue: it is not initialized yet, but these
776 // arguments MUST be initialized before it is.
777 // We should just ignore the argument if the UTF-8
778 // conversion fails, but out of charity we try once
779 // more with ISO Latin1, a standard unix encoding.
781 if (NULL
!= list
[count
]) count
++;
783 __CFArgStuff
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)list
, count
, &kCFTypeArrayCallBacks
);
786 __CFSessionID
= getenv("SECURITYSESSIONID");
788 _CFProcessPath(); // cache this early
790 #if defined(__MACH__)
792 SYSCALL_TRACE(0xC003);
795 #if defined(DEBUG) && !defined(__WIN32__)
796 // Don't log on MacOS 8 as this will create a log file unnecessarily
797 CFLog (0, CFSTR("Assertions enabled"));
799 SYSCALL_TRACE(0xC0FF);
803 #if defined(__WIN32__)
805 /* We have to call __CFInitialize when library is attached to the process.
808 WINBOOL WINAPI
DllMain( HINSTANCE hInstance
, DWORD dwReason
, LPVOID pReserved
) {
809 if (dwReason
== DLL_PROCESS_ATTACH
) {
811 } else if (dwReason
== DLL_PROCESS_DETACH
) {
819 // Functions that avoid ObC dispatch and CF type validation, for use by NSNotifyingCFArray, etc.
820 // Hopefully all of this will just go away. 3321464. M.P. To Do - 7/9/03
822 Boolean
_CFEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
824 if (NULL
== cf1
) HALT
;
825 if (NULL
== cf2
) HALT
;
827 if (cf1
== cf2
) return true;
828 __CFGenericAssertIsCF(cf1
);
829 __CFGenericAssertIsCF(cf2
);
830 if (__CFGenericTypeID(cf1
) != __CFGenericTypeID(cf2
)) return false;
831 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID(cf1
)]->equal
) {
832 return __CFRuntimeClassTable
[__CFGenericTypeID(cf1
)]->equal(cf1
, cf2
);
837 CFIndex
_CFGetRetainCount(CFTypeRef cf
) {
840 rc
= __CFGetFullRetainCount(cf
);
841 result
= (rc
< (uint64_t)0x7FFFFFFF) ? (CFIndex
)rc
: (CFIndex
)0x7FFFFFFF;
845 CFHashCode
_CFHash(CFTypeRef cf
) {
846 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->hash
) {
847 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->hash(cf
);
849 return (CFHashCode
)cf
;
852 CF_EXPORT CFTypeRef
_CFRetain(CFTypeRef cf
) {
854 bool is_threaded
= __is_threaded
;
856 if (NULL
== cf
) HALT
;
858 if (is_threaded
) __CFSpinLock(&__CFGlobalRetainLock
);
859 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
860 if (0 == lowBits
) { // Constant CFTypeRef
861 if (is_threaded
) __CFSpinUnlock(&__CFGlobalRetainLock
);
865 if ((lowBits
& 0x07fff) == 0) {
866 // Roll over another bit to the external ref count
867 _CFDictionaryIncrementValue(__CFRuntimeExternRefCountTable
, DISGUISE(cf
));
868 lowBits
= 0x8000; // Bit 16 indicates external ref count
870 ((CFRuntimeBase
*)cf
)->_rc
= lowBits
;
871 if (is_threaded
) __CFSpinUnlock(&__CFGlobalRetainLock
);
873 uint64_t compositeRC
;
874 compositeRC
= (lowBits
& 0x7fff) + ((uint64_t)(uintptr_t)CFDictionaryGetValue(__CFRuntimeExternRefCountTable
, DISGUISE(cf
)) << 15);
875 if (compositeRC
> (uint64_t)0x7fffffff) compositeRC
= (uint64_t)0x7fffffff;
876 __CFRecordAllocationEvent(__kCFRetainEvent
, (void *)cf
, 0, compositeRC
, NULL
);
881 CF_EXPORT
void _CFRelease(CFTypeRef cf
) {
883 bool is_threaded
= __is_threaded
;
885 if (NULL
== cf
) HALT
;
887 if (is_threaded
) __CFSpinLock(&__CFGlobalRetainLock
);
888 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
889 if (0 == lowBits
) { // Constant CFTypeRef
890 if (is_threaded
) __CFSpinUnlock(&__CFGlobalRetainLock
);
894 if (is_threaded
) __CFSpinUnlock(&__CFGlobalRetainLock
);
895 if (__CFOASafe
) __CFRecordAllocationEvent(__kCFReleaseEvent
, (void *)cf
, 0, 0, NULL
);
896 if (__kCFAllocatorTypeID_CONST
== __CFGenericTypeID(cf
)) {
898 __CFZombifyDeallocatedMemory((void *)cf
);
899 if (!(__CFZombieLevel
& (1 << 4))) {
900 __CFAllocatorDeallocate((void *)cf
);
903 __CFAllocatorDeallocate((void *)cf
);
906 CFAllocatorRef allocator
;
907 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID(cf
)]->finalize
) {
908 __CFRuntimeClassTable
[__CFGenericTypeID(cf
)]->finalize(cf
);
910 if (__CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_info
, 7, 7)) {
911 allocator
= kCFAllocatorSystemDefault
;
913 allocator
= CFGetAllocator(cf
);
914 (intptr_t)cf
-= sizeof(CFAllocatorRef
);
917 __CFZombifyDeallocatedMemory((void *)cf
);
918 if (!(__CFZombieLevel
& (1 << 4))) {
919 CFAllocatorDeallocate(allocator
, (void *)cf
);
922 CFAllocatorDeallocate(allocator
, (void *)cf
);
924 if (kCFAllocatorSystemDefault
!= allocator
) {
925 CFRelease(allocator
);
929 if (0x8000 == lowBits
) {
930 // Time to remove a bit from the external ref count
931 if (0 == _CFDictionaryDecrementValue(__CFRuntimeExternRefCountTable
, DISGUISE(cf
))) {
939 ((CFRuntimeBase
*)cf
)->_rc
= lowBits
;
940 if (is_threaded
) __CFSpinUnlock(&__CFGlobalRetainLock
);
942 uint64_t compositeRC
;
943 compositeRC
= (lowBits
& 0x7fff) + ((uint64_t)(uintptr_t)CFDictionaryGetValue(__CFRuntimeExternRefCountTable
, DISGUISE(cf
)) << 15);
944 if (compositeRC
> (uint64_t)0x7fffffff) compositeRC
= (uint64_t)0x7fffffff;
945 __CFRecordAllocationEvent(__kCFReleaseEvent
, (void *)cf
, 0, compositeRC
, NULL
);
950 #undef DO_SYSCALL_TRACE_HELPERS
952 #undef __kCFAllocatorTypeID_CONST
953 #undef __CFGenericAssertIsCF