2 * Copyright (c) 2005 Apple Computer, 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@
24 Copyright 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
28 #define ENABLE_ZOMBIES 1
30 #include "CFRuntime.h"
31 #include "CFInternal.h"
38 #include <crt_externs.h>
39 #include <objc/objc-auto.h>
40 #include <objc/objc-runtime.h>
45 extern void __CFRecordAllocationEvent(int eventnum
, void *ptr
, int size
, int data
, const char *classname
);
47 #define __CFRecordAllocationEvent(a, b, c, d, e)
51 extern BOOL
objc_isAuto(id object
);
52 extern void* objc_assign_ivar_address_CF(void *value
, void *base
, void **slot
);
53 extern void* objc_assign_strongCast_CF(void* value
, void **slot
);
57 // retain/release recording constants -- must match values
58 // used by OA for now; probably will change in the future
59 __kCFRetainEvent
= 28,
60 __kCFReleaseEvent
= 29
63 /* On Win32 we should use _msize instead of malloc_size
64 * (Aleksey Dukhnyakov)
66 #if defined(__WIN32__)
68 CF_INLINE
size_t malloc_size(void *memblock
) {
69 return _msize(memblock
);
72 #include <malloc/malloc.h>
77 bool __CFOASafe
= false;
79 void __CFOAInitialize(void) {
80 static void (*dyfunc
)(void) = (void *)0xFFFFFFFF;
81 if (NULL
== getenv("OAKeepAllocationStatistics")) return;
82 if ((void *)0xFFFFFFFF == dyfunc
) {
83 dyfunc
= dlsym(RTLD_DEFAULT
, "_OAInitialize");
91 void __CFRecordAllocationEvent(int eventnum
, void *ptr
, int size
, int data
, const char *classname
) {
92 static void (*dyfunc
)(int, void *, int, int, const char *) = (void *)0xFFFFFFFF;
93 if (!__CFOASafe
) return;
94 if ((void *)0xFFFFFFFF == dyfunc
) {
95 dyfunc
= dlsym(RTLD_DEFAULT
, "_OARecordAllocationEvent");
98 dyfunc(eventnum
, ptr
, size
, data
, classname
);
102 void __CFSetLastAllocationEventName(void *ptr
, const char *classname
) {
103 static void (*dyfunc
)(void *, const char *) = (void *)0xFFFFFFFF;
104 if (!__CFOASafe
) return;
105 if ((void *)0xFFFFFFFF == dyfunc
) {
106 dyfunc
= dlsym(RTLD_DEFAULT
, "_OASetLastAllocationEventName");
108 if (NULL
!= dyfunc
) {
109 dyfunc(ptr
, classname
);
114 extern void __HALT(void);
116 static CFTypeID __kCFNotATypeTypeID
= _kCFRuntimeNotATypeID
;
118 static const CFRuntimeClass __CFNotATypeClass
= {
130 static CFTypeID __kCFTypeTypeID
= _kCFRuntimeNotATypeID
;
132 static const CFRuntimeClass __CFTypeClass
= {
144 /* bits 15-8 in the CFRuntimeBase _info are type */
145 /* bits 7-0 in the CFRuntimeBase are reserved for CF's use */
147 static CFRuntimeClass
* __CFRuntimeClassTable
[__CFMaxRuntimeTypes
] = {NULL
};
148 static int32_t __CFRuntimeClassTableCount
= 0;
150 #if defined(__MACH__)
152 #if !defined(__ppc__)
153 __private_extern__
void * (*__CFSendObjCMsg
)(const void *, SEL
, ...) = NULL
;
156 __private_extern__ malloc_zone_t
*__CFCollectableZone
= NULL
;
158 static bool objc_isCollectable_nope(void* obj
) { return false; }
159 bool (*__CFObjCIsCollectable
)(void *) = NULL
;
161 static const void* objc_AssignIvar_none(const void *value
, void *base
, const void **slot
) { return (*slot
= value
); }
162 const void* (*__CFObjCAssignIvar
)(const void *value
, const void *base
, const void **slot
) = objc_AssignIvar_none
;
164 static const void* objc_StrongAssign_none(const void *value
, const void **slot
) { return (*slot
= value
); }
165 const void* (*__CFObjCStrongAssign
)(const void *value
, const void **slot
) = objc_StrongAssign_none
;
167 void* (*__CFObjCMemmoveCollectable
)(void *dst
, const void *, unsigned) = memmove
;
169 // GC: to be moved to objc if necessary.
170 static void objc_WriteBarrierRange_none(void *ptr
, unsigned size
) {}
171 static void objc_WriteBarrierRange_auto(void *ptr
, unsigned size
) { auto_zone_write_barrier_range(__CFCollectableZone
, ptr
, size
); }
172 void (*__CFObjCWriteBarrierRange
)(void *, unsigned) = objc_WriteBarrierRange_none
;
174 // Temporarily disabled __private_extern__
175 #warning Ali, be sure to reexamine this
176 struct objc_class
*__CFRuntimeObjCClassTable
[__CFMaxRuntimeTypes
] = {NULL
};
180 // Compiler uses this symbol name
181 int __CFConstantStringClassReference
[10] = {0};
183 #if defined(__MACH__)
184 static struct objc_class __CFNSTypeClass
= {{0, 0}, NULL
, {0, 0, 0, 0, 0, 0, 0}};
187 //static CFSpinLock_t __CFRuntimeLock = 0;
189 CFTypeID
_CFRuntimeRegisterClass(const CFRuntimeClass
* const cls
) {
190 // version field must be 0
191 // className must be pure ASCII string, non-null
192 if (__CFMaxRuntimeTypes
<= __CFRuntimeClassTableCount
) {
193 CFLog(0, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls
->className
);
194 return _kCFRuntimeNotATypeID
;
196 __CFRuntimeClassTable
[__CFRuntimeClassTableCount
++] = (CFRuntimeClass
*)cls
;
197 return __CFRuntimeClassTableCount
- 1;
200 void _CFRuntimeInitializeClassForBridging(CFTypeID typeID
) {
201 __CFRuntimeObjCClassTable
[typeID
] = (struct objc_class
*)calloc(sizeof(struct objc_class
), 1);
204 Boolean
_CFRuntimeSetupBridging(CFTypeID typeID
, struct objc_class
*mainClass
, struct objc_class
*subClass
) {
205 void *isa
= __CFISAForTypeID(typeID
);
206 memmove(isa
, subClass
, sizeof(struct objc_class
));
207 class_poseAs(isa
, mainClass
);
211 const CFRuntimeClass
* _CFRuntimeGetClassWithTypeID(CFTypeID typeID
) {
212 return __CFRuntimeClassTable
[typeID
];
215 void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID
) {
216 __CFRuntimeClassTable
[typeID
] = NULL
;
220 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
222 /* CFZombieLevel levels:
223 * bit 0: scribble deallocated CF object memory
224 * bit 1: do not scribble on CFRuntimeBase header (when bit 0)
225 * bit 4: do not free CF objects
226 * bit 7: use 3rd-order byte as scribble byte for dealloc (otherwise 0xFC)
227 * bit 16: scribble allocated CF object memory
228 * bit 23: use 1st-order byte as scribble byte for alloc (otherwise 0xCF)
231 static uint32_t __CFZombieLevel
= 0x0;
233 static void __CFZombifyAllocatedMemory(void *cf
) {
234 if (__CFZombieLevel
& (1 << 16)) {
236 size_t size
= malloc_size(cf
);
238 if (__CFZombieLevel
& (1 << 23)) {
239 byte
= (__CFZombieLevel
>> 24) & 0xFF;
241 memset(ptr
, byte
, size
);
245 static void __CFZombifyDeallocatedMemory(void *cf
) {
246 if (__CFZombieLevel
& (1 << 0)) {
248 size_t size
= malloc_size(cf
);
250 if (__CFZombieLevel
& (1 << 1)) {
251 ptr
+= sizeof(CFRuntimeBase
);
252 size
-= sizeof(CFRuntimeBase
);
254 if (__CFZombieLevel
& (1 << 7)) {
255 byte
= (__CFZombieLevel
>> 8) & 0xFF;
257 memset(ptr
, byte
, size
);
263 // XXX_PCB: use the class version field as a bitmask, to allow classes to opt-in for GC scanning.
265 CF_INLINE CFOptionFlags
CF_GET_COLLECTABLE_MEMORY_TYPE(const CFRuntimeClass
*cls
)
267 return (cls
->version
& _kCFRuntimeScannedObject
) ? AUTO_OBJECT_SCANNED
: AUTO_OBJECT_UNSCANNED
;
270 CFTypeRef
_CFRuntimeCreateInstance(CFAllocatorRef allocator
, CFTypeID typeID
, uint32_t extraBytes
, unsigned char *category
) {
271 CFRuntimeBase
*memory
;
272 Boolean usesSystemDefaultAllocator
;
275 CFAssert1(typeID
!= _kCFRuntimeNotATypeID
, __kCFLogAssertion
, "%s(): Uninitialized type id", __PRETTY_FUNCTION__
);
277 if (NULL
== __CFRuntimeClassTable
[typeID
]) {
280 allocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : allocator
;
281 usesSystemDefaultAllocator
= (allocator
== kCFAllocatorSystemDefault
);
282 extraBytes
= (extraBytes
+ (sizeof(void *) - 1)) & ~(sizeof(void *) - 1);
283 size
= sizeof(CFRuntimeBase
) + extraBytes
+ (usesSystemDefaultAllocator
? 0 : sizeof(CFAllocatorRef
));
284 // CFType version 0 objects are unscanned by default since they don't have write-barriers and hard retain their innards
285 // CFType version 1 objects are scanned and use hand coded write-barriers to store collectable storage within
286 memory
= CFAllocatorAllocate(allocator
, size
, CF_GET_COLLECTABLE_MEMORY_TYPE(__CFRuntimeClassTable
[typeID
]));
287 if (NULL
== memory
) {
290 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
291 __CFZombifyAllocatedMemory((void *)memory
);
293 if (__CFOASafe
&& category
) {
294 __CFSetLastAllocationEventName(memory
, category
);
295 } else if (__CFOASafe
) {
296 __CFSetLastAllocationEventName(memory
, __CFRuntimeClassTable
[typeID
]->className
);
298 if (!usesSystemDefaultAllocator
) {
299 // add space to hold allocator ref for non-standard allocators.
300 // (this screws up 8 byte alignment but seems to work)
301 *(CFAllocatorRef
*)((char *)memory
) = CFRetain(allocator
);
302 memory
= (CFRuntimeBase
*)((char *)memory
+ sizeof(CFAllocatorRef
));
304 memory
->_isa
= __CFISAForTypeID(typeID
);
307 __CFBitfieldSetValue(memory
->_info
, 15, 8, typeID
);
308 if (usesSystemDefaultAllocator
) {
309 __CFBitfieldSetValue(memory
->_info
, 7, 7, 1);
311 if (NULL
!= __CFRuntimeClassTable
[typeID
]->init
) {
312 (__CFRuntimeClassTable
[typeID
]->init
)(memory
);
317 void _CFRuntimeSetInstanceTypeID(CFTypeRef cf
, CFTypeID typeID
) {
318 __CFBitfieldSetValue(((CFRuntimeBase
*)cf
)->_info
, 15, 8, typeID
);
321 CFTypeID
__CFGenericTypeID(const void *cf
) {
322 return __CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_info
, 15, 8);
325 CF_INLINE CFTypeID
__CFGenericTypeID_inline(const void *cf
) {
326 return __CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_info
, 15, 8);
329 CFTypeID
CFTypeGetTypeID(void) {
330 return __kCFTypeTypeID
;
333 __private_extern__
void __CFGenericValidateType_(CFTypeRef cf
, CFTypeID type
, const char *func
) {
334 if (cf
&& CF_IS_OBJC(type
, cf
)) return;
335 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
); \
336 CFAssert3(__CFGenericTypeID_inline(cf
) == type
, __kCFLogAssertion
, "%s(): pointer 0x%x is not a %s", func
, cf
, __CFRuntimeClassTable
[type
]->className
); \
339 #define __CFGenericAssertIsCF(cf) \
340 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);
342 #if !defined(__MACH__)
344 #define CFTYPE_IS_OBJC(obj) (false)
345 #define CFTYPE_OBJC_FUNCDISPATCH0(rettype, obj, sel) do {} while (0)
346 #define CFTYPE_OBJC_FUNCDISPATCH1(rettype, obj, sel, a1) do {} while (0)
350 #if defined(__MACH__)
352 CF_INLINE
int CFTYPE_IS_OBJC(const void *obj
) {
353 CFTypeID typeID
= __CFGenericTypeID_inline(obj
);
354 return CF_IS_OBJC(typeID
, obj
);
357 #define CFTYPE_OBJC_FUNCDISPATCH0(rettype, obj, sel) \
358 if (CFTYPE_IS_OBJC(obj)) \
359 {rettype (*func)(void *, SEL) = (void *)__CFSendObjCMsg; \
360 static SEL s = NULL; if (!s) s = sel_registerName(sel); \
361 return func((void *)obj, s);}
362 #define CFTYPE_OBJC_FUNCDISPATCH1(rettype, obj, sel, a1) \
363 if (CFTYPE_IS_OBJC(obj)) \
364 {rettype (*func)(void *, SEL, ...) = (void *)__CFSendObjCMsg; \
365 static SEL s = NULL; if (!s) s = sel_registerName(sel); \
366 return func((void *)obj, s, (a1));}
370 CFTypeID
CFGetTypeID(CFTypeRef cf
) {
372 if (NULL
== cf
) HALT
;
374 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeID
, cf
, "_cfTypeID");
375 __CFGenericAssertIsCF(cf
);
376 return __CFGenericTypeID_inline(cf
);
379 CFStringRef
CFCopyTypeIDDescription(CFTypeID type
) {
380 CFAssert2((NULL
!= __CFRuntimeClassTable
[type
]) && __kCFNotATypeTypeID
!= type
&& __kCFTypeTypeID
!= type
, __kCFLogAssertion
, "%s(): type %d is not a CF type ID", __PRETTY_FUNCTION__
, type
);
381 return CFStringCreateWithCString(kCFAllocatorDefault
, __CFRuntimeClassTable
[type
]->className
, kCFStringEncodingASCII
);
384 static CFSpinLock_t __CFGlobalRetainLock
= 0;
385 static CFMutableDictionaryRef __CFRuntimeExternRefCountTable
= NULL
;
387 #define DISGUISE(object) ((void *)(((unsigned)object) + 1))
388 #define UNDISGUISE(disguised) ((id)(((unsigned)disguised) - 1))
390 extern void _CFDictionaryIncrementValue(CFMutableDictionaryRef dict
, const void *key
);
391 extern int _CFDictionaryDecrementValue(CFMutableDictionaryRef dict
, const void *key
);
393 // Bit 31 (highest bit) in second word of cf instance indicates external ref count
395 extern void _CFRelease(CFTypeRef cf
);
396 extern CFTypeRef
_CFRetain(CFTypeRef cf
);
397 extern CFHashCode
_CFHash(CFTypeRef cf
);
399 CFTypeRef
CFRetain(CFTypeRef cf
) {
400 // always honor CFRetain's with a hard reference
401 if (CF_IS_COLLECTABLE(cf
)) {
402 auto_zone_retain(__CFCollectableZone
, (void*)cf
);
405 // XXX_PCB some Objc objects aren't really reference counted, perhaps they should be able to make that distinction?
406 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeRef
, cf
, "retain");
407 __CFGenericAssertIsCF(cf
);
408 return _CFRetain(cf
);
411 __private_extern__
void __CFAllocatorDeallocate(CFTypeRef cf
);
413 void CFRelease(CFTypeRef cf
) {
414 // make sure we get rid of the hard reference if called
415 if (CF_IS_COLLECTABLE(cf
)) {
416 auto_zone_release(__CFCollectableZone
, (void*)cf
);
419 // XXX_PCB some objects aren't really reference counted.
420 CFTYPE_OBJC_FUNCDISPATCH0(void, cf
, "release");
421 __CFGenericAssertIsCF(cf
);
425 static uint64_t __CFGetFullRetainCount(CFTypeRef cf
) {
426 uint32_t lowBits
= 0;
427 uint64_t highBits
= 0, compositeRC
;
428 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
430 return (uint64_t)0x00ffffffffffffffULL
;
432 if ((lowBits
& 0x08000) != 0) {
433 highBits
= (uint64_t)(uintptr_t)CFDictionaryGetValue(__CFRuntimeExternRefCountTable
, DISGUISE(cf
));
435 compositeRC
= (lowBits
& 0x7fff) + (highBits
<< 15);
439 CFTypeRef
_CFRetainGC(CFTypeRef cf
)
442 if (CF_USING_COLLECTABLE_MEMORY
&& !CF_IS_COLLECTABLE(cf
)) {
443 fprintf(stderr
, "non-auto object %p passed to _CFRetainGC.\n", cf
);
447 return CF_USING_COLLECTABLE_MEMORY
? cf
: CFRetain(cf
);
450 void _CFReleaseGC(CFTypeRef cf
)
453 if (CF_USING_COLLECTABLE_MEMORY
&& !CF_IS_COLLECTABLE(cf
)) {
454 fprintf(stderr
, "non-auto object %p passed to _CFReleaseGC.\n", cf
);
458 if (!CF_USING_COLLECTABLE_MEMORY
) CFRelease(cf
);
461 CFIndex
CFGetRetainCount(CFTypeRef cf
) {
465 if (NULL
== cf
) HALT
;
467 if (CF_IS_COLLECTABLE(cf
)) {
468 return auto_zone_retain_count(__CFCollectableZone
, cf
);
470 CFTYPE_OBJC_FUNCDISPATCH0(CFIndex
, cf
, "retainCount");
471 __CFGenericAssertIsCF(cf
);
472 rc
= __CFGetFullRetainCount(cf
);
473 result
= (rc
< (uint64_t)0x7FFFFFFF) ? (CFIndex
)rc
: (CFIndex
)0x7FFFFFFF;
477 CFTypeRef
CFMakeCollectable(CFTypeRef cf
)
479 if (!cf
) return NULL
;
480 if (CF_USING_COLLECTABLE_MEMORY
) {
482 CFAllocatorRef allocator
= CFGetAllocator(cf
);
483 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
484 CFLog(0, CFSTR("object %p with non-GC allocator %p passed to CFMakeCollected."), cf
, allocator
);
488 if (CFGetRetainCount(cf
) == 0) {
489 CFLog(0, CFSTR("object %p with 0 retain-count passed to CFMakeCollected."), cf
);
497 Boolean
CFEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
499 if (NULL
== cf1
) HALT
;
500 if (NULL
== cf2
) HALT
;
502 if (cf1
== cf2
) return true;
503 CFTYPE_OBJC_FUNCDISPATCH1(Boolean
, cf1
, "isEqual:", cf2
);
504 CFTYPE_OBJC_FUNCDISPATCH1(Boolean
, cf2
, "isEqual:", cf1
);
505 __CFGenericAssertIsCF(cf1
);
506 __CFGenericAssertIsCF(cf2
);
507 if (__CFGenericTypeID_inline(cf1
) != __CFGenericTypeID_inline(cf2
)) return false;
508 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf1
)]->equal
) {
509 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf1
)]->equal(cf1
, cf2
);
514 CFHashCode
CFHash(CFTypeRef cf
) {
515 CFTYPE_OBJC_FUNCDISPATCH0(CFHashCode
, cf
, "hash");
516 __CFGenericAssertIsCF(cf
);
520 // definition: produces a normally non-NULL debugging description of the object
521 CFStringRef
CFCopyDescription(CFTypeRef cf
) {
523 if (NULL
== cf
) HALT
;
525 if (CFTYPE_IS_OBJC(cf
)) {
527 CFStringRef (*func
)(void *, SEL
, ...) = (void *)__CFSendObjCMsg
;
528 if (!s
) s
= sel_registerName("_copyDescription");
529 CFStringRef result
= func((void *)cf
, s
);
530 if (result
&& CF_USING_COLLECTABLE_MEMORY
) CFRetain(result
); // needs hard retain
533 // CFTYPE_OBJC_FUNCDISPATCH0(CFStringRef, cf, "_copyDescription"); // XXX returns 0 refcounted item under GC
534 __CFGenericAssertIsCF(cf
);
535 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyDebugDesc
) {
537 result
= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyDebugDesc(cf
);
538 if (NULL
!= result
) return result
;
540 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<%s %p [%p]>"), __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->className
, cf
, CFGetAllocator(cf
));
543 // Definition: if type produces a formatting description, return that string, otherwise NULL
544 __private_extern__ CFStringRef
__CFCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
546 if (NULL
== cf
) HALT
;
548 #if defined(__MACH__)
549 if (CFTYPE_IS_OBJC(cf
)) {
550 static SEL s
= NULL
, r
= NULL
;
551 CFStringRef (*func
)(void *, SEL
, ...) = (void *)__CFSendObjCMsg
;
552 if (!s
) s
= sel_registerName("_copyFormattingDescription:");
553 if (!r
) r
= sel_registerName("respondsToSelector:");
554 if (s
&& func((void *)cf
, r
, s
)) return func((void *)cf
, s
, formatOptions
);
558 __CFGenericAssertIsCF(cf
);
559 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyFormattingDesc
) {
560 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->copyFormattingDesc(cf
, formatOptions
);
565 extern CFAllocatorRef
__CFAllocatorGetAllocator(CFTypeRef
);
567 CFAllocatorRef
CFGetAllocator(CFTypeRef cf
) {
569 if (NULL
== cf
) HALT
;
571 // CF: need to get allocator from objc objects in better way...how?
572 // -> bridging of CFAllocators and malloc_zone_t will help this
573 if (CFTYPE_IS_OBJC(cf
)) return __CFGetDefaultAllocator();
574 if (__kCFAllocatorTypeID_CONST
== __CFGenericTypeID_inline(cf
)) {
575 return __CFAllocatorGetAllocator(cf
);
577 return __CFGetAllocator(cf
);
580 extern void __CFBaseInitialize(void);
581 extern void __CFNullInitialize(void);
582 extern void __CFAllocatorInitialize(void);
583 extern void __CFStringInitialize(void);
584 extern void __CFArrayInitialize(void);
585 extern void __CFBagInitialize(void);
586 extern void __CFBooleanInitialize(void);
587 extern void __CFCharacterSetInitialize(void);
588 extern void __CFDataInitialize(void);
589 extern void __CFDateInitialize(void);
590 extern void __CFDictionaryInitialize(void);
591 extern void __CFNumberInitialize(void);
592 extern void __CFSetInitialize(void);
593 extern void __CFStorageInitialize(void);
594 extern void __CFTimeZoneInitialize(void);
595 extern void __CFTreeInitialize(void);
596 extern void __CFURLInitialize(void);
597 extern void __CFXMLNodeInitialize(void);
598 extern void __CFXMLParserInitialize(void);
599 extern void __CFLocaleInitialize(void);
600 extern void __CFCalendarInitialize(void);
601 extern void __CFNumberFormatterInitialize(void);
602 extern void __CFDateFormatterInitialize(void);
603 #if defined(__MACH__)
604 extern void __CFMessagePortInitialize(void);
605 extern void __CFMachPortInitialize(void);
607 #if defined(__MACH__) || defined(__WIN32__)
608 extern void __CFRunLoopInitialize(void);
609 extern void __CFRunLoopObserverInitialize(void);
610 extern void __CFRunLoopSourceInitialize(void);
611 extern void __CFRunLoopTimerInitialize(void);
612 extern void __CFSocketInitialize(void);
614 extern void __CFBundleInitialize(void);
615 extern void __CFPlugInInitialize(void);
616 extern void __CFPlugInInstanceInitialize(void);
617 extern void __CFUUIDInitialize(void);
618 extern void __CFBinaryHeapInitialize(void);
619 extern void __CFBitVectorInitialize(void);
620 #if defined(__WIN32__)
621 extern void __CFWindowsMessageQueueInitialize(void);
622 extern void __CFBaseCleanup(void);
624 extern void __CFStreamInitialize(void);
625 #if defined(__MACH__)
626 extern void __CFPreferencesDomainInitialize(void);
627 extern void __CFUserNotificationInitialize(void);
631 #define DO_SYSCALL_TRACE_HELPERS 1
633 #if defined(DO_SYSCALL_TRACE_HELPERS) && defined(__MACH__)
634 extern void ptrace(int, int, int, int);
635 #define SYSCALL_TRACE(N) do ptrace(N, 0, 0, 0); while (0)
637 #define SYSCALL_TRACE(N) do {} while (0)
640 #if defined(__MACH__) && defined(PROFILE)
641 static void _CF_mcleanup(void) {
646 const void *__CFArgStuff
= NULL
;
647 __private_extern__
void *__CFAppleLanguages
= NULL
;
648 __private_extern__
void *__CFSessionID
= NULL
;
650 #if defined(__LINUX__) || defined(__FREEBSD__)
651 static void __CFInitialize(void) __attribute__ ((constructor
));
654 #if defined(__WIN32__)
657 void __CFInitialize(void) {
658 static int __done
= 0;
659 if (sizeof(int) != sizeof(long) || 4 != sizeof(long)) __HALT();
663 SYSCALL_TRACE(0xC000);
665 kCFUseCollectableAllocator
= objc_collecting_enabled();
666 if (kCFUseCollectableAllocator
) {
667 __CFCollectableZone
= auto_zone();
668 __CFObjCIsCollectable
= objc_isAuto
;
669 __CFObjCAssignIvar
= objc_assign_ivar_address_CF
;
670 __CFObjCStrongAssign
= objc_assign_strongCast_CF
;
671 __CFObjCMemmoveCollectable
= objc_memmove_collectable
;
672 __CFObjCWriteBarrierRange
= objc_WriteBarrierRange_auto
;
675 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
677 const char *value
= getenv("CFZombieLevel");
679 __CFZombieLevel
= strtoul(value
, NULL
, 0);
681 if (0x0 == __CFZombieLevel
) __CFZombieLevel
= 0xCF00FC00; // default
684 #if defined(__MACH__) && defined(PROFILE)
686 const char *v
= getenv("DYLD_IMAGE_SUFFIX");
687 const char *p
= getenv("CFPROF_ENABLE");
688 // ckane: People were upset that I added this feature to allow for the profiling of
689 // libraries using unprofiled apps/executables, so ensure they cannot get this accidentally.
690 if (v
&& p
&& 0 == strcmp("_profile", v
) && 0 == strcmp(crypt(p
+ 2, p
) + 2, "eQJhkVvMm.w")) {
691 // Unfortunately, no way to know if this has already been done,
692 // or I would not do it. Not much information will be lost.
693 atexit(_CF_mcleanup
);
699 __CFBaseInitialize();
701 #if defined(__MACH__)
704 for (idx
= 0; idx
< __CFMaxRuntimeTypes
; idx
++) {
705 __CFRuntimeObjCClassTable
[idx
] = &__CFNSTypeClass
;
710 /* Here so that two runtime classes get indices 0, 1. */
711 __kCFNotATypeTypeID
= _CFRuntimeRegisterClass(&__CFNotATypeClass
);
712 __kCFTypeTypeID
= _CFRuntimeRegisterClass(&__CFTypeClass
);
714 /* Here so that __kCFAllocatorTypeID gets index 2. */
715 __CFAllocatorInitialize();
717 /* Basic collections need to be up before CFString. */
718 __CFDictionaryInitialize();
719 __CFArrayInitialize();
720 __CFDataInitialize();
723 #if defined(__MACH__)
726 char **args
= *_NSGetArgv();
728 for (idx
= 1; idx
< cnt
- 1; idx
++) {
729 if (0 == strcmp(args
[idx
], "-AppleLanguages")) {
730 CFIndex length
= strlen(args
[idx
+ 1]);
731 __CFAppleLanguages
= malloc(length
+ 1);
732 memmove(__CFAppleLanguages
, args
[idx
+ 1], length
+ 1);
740 // Creating this lazily in CFRetain causes recursive call to CFRetain
741 __CFRuntimeExternRefCountTable
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, NULL
);
743 /*** _CFRuntimeCreateInstance() can finally be called generally after this line. ***/
745 __CFStringInitialize(); // CFString's TypeID must be 0x7, now and forever
746 __CFNullInitialize(); // See above for hard-coding of this position
747 __CFBooleanInitialize(); // See above for hard-coding of this position
748 __CFNumberInitialize(); // See above for hard-coding of this position
749 __CFDateInitialize(); // See above for hard-coding of this position
750 __CFTimeZoneInitialize(); // See above for hard-coding of this position
752 __CFBinaryHeapInitialize();
753 __CFBitVectorInitialize();
755 __CFCharacterSetInitialize();
756 __CFStorageInitialize();
757 __CFTreeInitialize();
759 __CFXMLNodeInitialize();
760 __CFXMLParserInitialize();
761 __CFBundleInitialize();
762 __CFPlugInInitialize();
763 __CFPlugInInstanceInitialize();
764 __CFUUIDInitialize();
765 #if defined(__MACH__)
766 __CFMessagePortInitialize();
767 __CFMachPortInitialize();
769 #if defined(__MACH__) || defined(__WIN32__)
770 __CFRunLoopInitialize();
771 __CFRunLoopObserverInitialize();
772 __CFRunLoopSourceInitialize();
773 __CFRunLoopTimerInitialize();
774 __CFSocketInitialize();
776 __CFStreamInitialize();
777 #if defined(__MACH__)
778 __CFPreferencesDomainInitialize();
782 SYSCALL_TRACE(0xC001);
784 #if defined(__MACH__)
787 char **args
= *_NSGetArgv();
790 CFStringRef
*list
, buffer
[256];
791 list
= (cnt
<= 256) ? buffer
: malloc(cnt
* sizeof(CFStringRef
));
792 for (idx
= 0, count
= 0; idx
< cnt
&& args
[idx
]; idx
++) {
793 list
[count
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, args
[idx
], kCFStringEncodingUTF8
);
794 if (NULL
== list
[count
]) {
795 list
[count
] = CFStringCreateWithCString(kCFAllocatorSystemDefault
, args
[idx
], kCFStringEncodingISOLatin1
);
796 // We CANNOT use the string SystemEncoding here;
797 // Do not argue: it is not initialized yet, but these
798 // arguments MUST be initialized before it is.
799 // We should just ignore the argument if the UTF-8
800 // conversion fails, but out of charity we try once
801 // more with ISO Latin1, a standard unix encoding.
803 if (NULL
!= list
[count
]) count
++;
805 __CFArgStuff
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)list
, count
, &kCFTypeArrayCallBacks
);
808 __CFSessionID
= getenv("SECURITYSESSIONID");
810 _CFProcessPath(); // cache this early
812 #if defined(__MACH__)
814 SYSCALL_TRACE(0xC003);
817 if (__CFRuntimeClassTableCount
< 100) __CFRuntimeClassTableCount
= 100;
819 #if defined(DEBUG) && !defined(__WIN32__)
820 // Don't log on MacOS 8 as this will create a log file unnecessarily
821 CFLog (0, CFSTR("Assertions enabled"));
823 SYSCALL_TRACE(0xC0FF);
827 #if defined(__WIN32__)
829 /* We have to call __CFInitialize when library is attached to the process.
832 WINBOOL WINAPI
DllMain( HINSTANCE hInstance
, DWORD dwReason
, LPVOID pReserved
) {
833 if (dwReason
== DLL_PROCESS_ATTACH
) {
835 } else if (dwReason
== DLL_PROCESS_DETACH
) {
838 __CFUniCharCleanup();
841 } else if (dwReason
== DLL_THREAD_DETACH
) {
842 __CFFinalizeThreadData(NULL
);
850 // Functions that avoid ObC dispatch and CF type validation, for use by NSNotifyingCFArray, etc.
851 // Hopefully all of this will just go away. 3321464. M.P. To Do - 7/9/03
853 Boolean
_CFEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
855 if (NULL
== cf1
) HALT
;
856 if (NULL
== cf2
) HALT
;
858 if (cf1
== cf2
) return true;
859 __CFGenericAssertIsCF(cf1
);
860 __CFGenericAssertIsCF(cf2
);
861 if (__CFGenericTypeID_inline(cf1
) != __CFGenericTypeID_inline(cf2
)) return false;
862 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf1
)]->equal
) {
863 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf1
)]->equal(cf1
, cf2
);
868 CFIndex
_CFGetRetainCount(CFTypeRef cf
) {
871 rc
= __CFGetFullRetainCount(cf
);
872 result
= (rc
< (uint64_t)0x7FFFFFFF) ? (CFIndex
)rc
: (CFIndex
)0x7FFFFFFF;
876 CFHashCode
_CFHash(CFTypeRef cf
) {
878 if (NULL
== cf
) HALT
;
880 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->hash
) {
881 return __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->hash(cf
);
883 return (CFHashCode
)cf
;
886 CF_EXPORT CFTypeRef
_CFRetain(CFTypeRef cf
) {
889 if (NULL
== cf
) HALT
;
891 __CFSpinLock(&__CFGlobalRetainLock
);
892 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
893 if (__builtin_expect(0 == lowBits
, 0)) { // Constant CFTypeRef
894 __CFSpinUnlock(&__CFGlobalRetainLock
);
898 if (__builtin_expect((lowBits
& 0x07fff) == 0, 0)) {
899 // Roll over another bit to the external ref count
900 _CFDictionaryIncrementValue(__CFRuntimeExternRefCountTable
, DISGUISE(cf
));
901 lowBits
= 0x8000; // Bit 16 indicates external ref count
903 ((CFRuntimeBase
*)cf
)->_rc
= lowBits
;
904 __CFSpinUnlock(&__CFGlobalRetainLock
);
905 if (__builtin_expect(__CFOASafe
, 0)) {
906 uint64_t compositeRC
;
907 compositeRC
= (lowBits
& 0x7fff) + ((uint64_t)(uintptr_t)CFDictionaryGetValue(__CFRuntimeExternRefCountTable
, DISGUISE(cf
)) << 15);
908 if (compositeRC
> (uint64_t)0x7fffffff) compositeRC
= (uint64_t)0x7fffffff;
909 __CFRecordAllocationEvent(__kCFRetainEvent
, (void *)cf
, 0, compositeRC
, NULL
);
914 CF_EXPORT
void _CFRelease(CFTypeRef cf
) {
917 if (NULL
== cf
) HALT
;
919 __CFSpinLock(&__CFGlobalRetainLock
);
920 lowBits
= ((CFRuntimeBase
*)cf
)->_rc
;
921 if (__builtin_expect(0 == lowBits
, 0)) { // Constant CFTypeRef
922 __CFSpinUnlock(&__CFGlobalRetainLock
);
925 if (__builtin_expect(1 == lowBits
, 0)) {
926 __CFSpinUnlock(&__CFGlobalRetainLock
);
927 if (__builtin_expect(__CFOASafe
, 0)) __CFRecordAllocationEvent(__kCFReleaseEvent
, (void *)cf
, 0, 0, NULL
);
928 if (__builtin_expect(__kCFAllocatorTypeID_CONST
== __CFGenericTypeID_inline(cf
), 0)) {
929 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
930 __CFZombifyDeallocatedMemory((void *)cf
);
931 if (!(__CFZombieLevel
& (1 << 4))) {
932 __CFAllocatorDeallocate((void *)cf
);
935 __CFAllocatorDeallocate((void *)cf
);
938 CFAllocatorRef allocator
;
939 // ((CFRuntimeBase *)cf)->_rc = 0;
940 if (NULL
!= __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->finalize
) {
941 __CFRuntimeClassTable
[__CFGenericTypeID_inline(cf
)]->finalize(cf
);
943 if (__builtin_expect(__CFBitfieldGetValue(((const CFRuntimeBase
*)cf
)->_info
, 7, 7), 1)) {
944 allocator
= kCFAllocatorSystemDefault
;
946 allocator
= CFGetAllocator(cf
);
947 (intptr_t)cf
-= sizeof(CFAllocatorRef
);
949 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
950 __CFZombifyDeallocatedMemory((void *)cf
);
951 if (!(__CFZombieLevel
& (1 << 4))) {
952 CFAllocatorDeallocate(allocator
, (void *)cf
);
955 CFAllocatorDeallocate(allocator
, (void *)cf
);
957 if (kCFAllocatorSystemDefault
!= allocator
) {
958 CFRelease(allocator
);
962 if (__builtin_expect(0x8000 == lowBits
, 0)) {
963 // Time to remove a bit from the external ref count
964 if (0 == _CFDictionaryDecrementValue(__CFRuntimeExternRefCountTable
, DISGUISE(cf
))) {
972 ((CFRuntimeBase
*)cf
)->_rc
= lowBits
;
973 __CFSpinUnlock(&__CFGlobalRetainLock
);
974 if (__builtin_expect(__CFOASafe
, 0)) {
975 uint64_t compositeRC
;
976 compositeRC
= (lowBits
& 0x7fff) + ((uint64_t)(uintptr_t)CFDictionaryGetValue(__CFRuntimeExternRefCountTable
, DISGUISE(cf
)) << 15);
977 if (compositeRC
> (uint64_t)0x7fffffff) compositeRC
= (uint64_t)0x7fffffff;
978 __CFRecordAllocationEvent(__kCFReleaseEvent
, (void *)cf
, 0, compositeRC
, NULL
);
983 #undef DO_SYSCALL_TRACE_HELPERS
985 #undef __kCFAllocatorTypeID_CONST
986 #undef __CFGenericAssertIsCF