]> git.saurik.com Git - apple/cf.git/blame - Base.subproj/CFRuntime.c
CF-368.11.tar.gz
[apple/cf.git] / Base.subproj / CFRuntime.c
CommitLineData
9ce05555 1/*
d8925383 2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
9ce05555
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
9ce05555
A
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/* CFRuntime.c
24 Copyright 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
26*/
27
d8925383
A
28#define ENABLE_ZOMBIES 1
29
9ce05555
A
30#include "CFRuntime.h"
31#include "CFInternal.h"
32#include <string.h>
33#include <stdlib.h>
d8925383 34#include <stdio.h>
9ce05555 35#if defined(__MACH__)
d8925383 36#include <dlfcn.h>
9ce05555 37#include <monitor.h>
9ce05555 38#include <crt_externs.h>
d8925383
A
39#include <objc/objc-auto.h>
40#include <objc/objc-runtime.h>
9ce05555 41#else
9ce05555
A
42#endif
43
9ce05555
A
44#if defined(__MACH__)
45extern void __CFRecordAllocationEvent(int eventnum, void *ptr, int size, int data, const char *classname);
46#else
47#define __CFRecordAllocationEvent(a, b, c, d, e)
48#endif
49
d8925383
A
50#if defined(__MACH__)
51extern BOOL objc_isAuto(id object);
52extern void* objc_assign_ivar_address_CF(void *value, void *base, void **slot);
53extern void* objc_assign_strongCast_CF(void* value, void **slot);
54#endif
55
9ce05555
A
56enum {
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
61};
62
63/* On Win32 we should use _msize instead of malloc_size
64 * (Aleksey Dukhnyakov)
65 */
66#if defined(__WIN32__)
67#include <malloc.h>
68CF_INLINE size_t malloc_size(void *memblock) {
69 return _msize(memblock);
70}
d8925383
A
71#else
72#include <malloc/malloc.h>
9ce05555
A
73#endif
74
75#if defined(__MACH__)
76
77bool __CFOASafe = false;
78
79void __CFOAInitialize(void) {
80 static void (*dyfunc)(void) = (void *)0xFFFFFFFF;
81 if (NULL == getenv("OAKeepAllocationStatistics")) return;
82 if ((void *)0xFFFFFFFF == dyfunc) {
d8925383 83 dyfunc = dlsym(RTLD_DEFAULT, "_OAInitialize");
9ce05555
A
84 }
85 if (NULL != dyfunc) {
d8925383
A
86 dyfunc();
87 __CFOASafe = true;
9ce05555
A
88 }
89}
90
91void __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) {
d8925383 95 dyfunc = dlsym(RTLD_DEFAULT, "_OARecordAllocationEvent");
9ce05555
A
96 }
97 if (NULL != dyfunc) {
d8925383 98 dyfunc(eventnum, ptr, size, data, classname);
9ce05555
A
99 }
100}
101
102void __CFSetLastAllocationEventName(void *ptr, const char *classname) {
103 static void (*dyfunc)(void *, const char *) = (void *)0xFFFFFFFF;
104 if (!__CFOASafe) return;
105 if ((void *)0xFFFFFFFF == dyfunc) {
d8925383 106 dyfunc = dlsym(RTLD_DEFAULT, "_OASetLastAllocationEventName");
9ce05555
A
107 }
108 if (NULL != dyfunc) {
d8925383 109 dyfunc(ptr, classname);
9ce05555
A
110 }
111}
112#endif
113
114extern void __HALT(void);
115
116static CFTypeID __kCFNotATypeTypeID = _kCFRuntimeNotATypeID;
117
118static const CFRuntimeClass __CFNotATypeClass = {
119 0,
120 "Not A Type",
121 (void *)__HALT,
122 (void *)__HALT,
123 (void *)__HALT,
124 (void *)__HALT,
125 (void *)__HALT,
126 (void *)__HALT,
127 (void *)__HALT
128};
129
130static CFTypeID __kCFTypeTypeID = _kCFRuntimeNotATypeID;
131
132static const CFRuntimeClass __CFTypeClass = {
133 0,
134 "CFType",
135 (void *)__HALT,
136 (void *)__HALT,
137 (void *)__HALT,
138 (void *)__HALT,
139 (void *)__HALT,
140 (void *)__HALT,
141 (void *)__HALT
142};
143
144/* bits 15-8 in the CFRuntimeBase _info are type */
145/* bits 7-0 in the CFRuntimeBase are reserved for CF's use */
146
147static CFRuntimeClass * __CFRuntimeClassTable[__CFMaxRuntimeTypes] = {NULL};
148static int32_t __CFRuntimeClassTableCount = 0;
149
150#if defined(__MACH__)
151
d8925383 152#if !defined(__ppc__)
9ce05555 153__private_extern__ void * (*__CFSendObjCMsg)(const void *, SEL, ...) = NULL;
d8925383
A
154#endif
155
156__private_extern__ malloc_zone_t *__CFCollectableZone = NULL;
157
158static bool objc_isCollectable_nope(void* obj) { return false; }
159bool (*__CFObjCIsCollectable)(void *) = NULL;
9ce05555 160
d8925383
A
161static const void* objc_AssignIvar_none(const void *value, void *base, const void **slot) { return (*slot = value); }
162const void* (*__CFObjCAssignIvar)(const void *value, const void *base, const void **slot) = objc_AssignIvar_none;
163
164static const void* objc_StrongAssign_none(const void *value, const void **slot) { return (*slot = value); }
165const void* (*__CFObjCStrongAssign)(const void *value, const void **slot) = objc_StrongAssign_none;
166
167void* (*__CFObjCMemmoveCollectable)(void *dst, const void *, unsigned) = memmove;
168
169// GC: to be moved to objc if necessary.
170static void objc_WriteBarrierRange_none(void *ptr, unsigned size) {}
171static void objc_WriteBarrierRange_auto(void *ptr, unsigned size) { auto_zone_write_barrier_range(__CFCollectableZone, ptr, size); }
172void (*__CFObjCWriteBarrierRange)(void *, unsigned) = objc_WriteBarrierRange_none;
173
174// Temporarily disabled __private_extern__
175#warning Ali, be sure to reexamine this
176struct objc_class *__CFRuntimeObjCClassTable[__CFMaxRuntimeTypes] = {NULL};
9ce05555
A
177
178#endif
179
180// Compiler uses this symbol name
181int __CFConstantStringClassReference[10] = {0};
182
183#if defined(__MACH__)
184static struct objc_class __CFNSTypeClass = {{0, 0}, NULL, {0, 0, 0, 0, 0, 0, 0}};
9ce05555
A
185#endif
186
187//static CFSpinLock_t __CFRuntimeLock = 0;
188
189CFTypeID _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;
195 }
196 __CFRuntimeClassTable[__CFRuntimeClassTableCount++] = (CFRuntimeClass *)cls;
197 return __CFRuntimeClassTableCount - 1;
198}
199
d8925383
A
200void _CFRuntimeInitializeClassForBridging(CFTypeID typeID) {
201 __CFRuntimeObjCClassTable[typeID] = (struct objc_class *)calloc(sizeof(struct objc_class), 1);
202}
203
204Boolean _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);
208 return true;
209}
210
9ce05555
A
211const CFRuntimeClass * _CFRuntimeGetClassWithTypeID(CFTypeID typeID) {
212 return __CFRuntimeClassTable[typeID];
213}
214
215void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID) {
216 __CFRuntimeClassTable[typeID] = NULL;
217}
218
219
d8925383 220#if defined(DEBUG) || defined(ENABLE_ZOMBIES)
9ce05555
A
221
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)
229 */
230
231static uint32_t __CFZombieLevel = 0x0;
232
233static void __CFZombifyAllocatedMemory(void *cf) {
234 if (__CFZombieLevel & (1 << 16)) {
235 void *ptr = cf;
236 size_t size = malloc_size(cf);
237 uint8_t byte = 0xCF;
238 if (__CFZombieLevel & (1 << 23)) {
239 byte = (__CFZombieLevel >> 24) & 0xFF;
240 }
241 memset(ptr, byte, size);
242 }
243}
244
245static void __CFZombifyDeallocatedMemory(void *cf) {
246 if (__CFZombieLevel & (1 << 0)) {
247 void *ptr = cf;
248 size_t size = malloc_size(cf);
249 uint8_t byte = 0xFC;
250 if (__CFZombieLevel & (1 << 1)) {
251 ptr += sizeof(CFRuntimeBase);
252 size -= sizeof(CFRuntimeBase);
253 }
254 if (__CFZombieLevel & (1 << 7)) {
255 byte = (__CFZombieLevel >> 8) & 0xFF;
256 }
257 memset(ptr, byte, size);
258 }
259}
260
261#endif /* DEBUG */
262
d8925383
A
263// XXX_PCB: use the class version field as a bitmask, to allow classes to opt-in for GC scanning.
264
265CF_INLINE CFOptionFlags CF_GET_COLLECTABLE_MEMORY_TYPE(const CFRuntimeClass *cls)
266{
267 return (cls->version & _kCFRuntimeScannedObject) ? AUTO_OBJECT_SCANNED : AUTO_OBJECT_UNSCANNED;
268}
269
9ce05555
A
270CFTypeRef _CFRuntimeCreateInstance(CFAllocatorRef allocator, CFTypeID typeID, uint32_t extraBytes, unsigned char *category) {
271 CFRuntimeBase *memory;
272 Boolean usesSystemDefaultAllocator;
273 int32_t size;
274
d8925383
A
275 CFAssert1(typeID != _kCFRuntimeNotATypeID, __kCFLogAssertion, "%s(): Uninitialized type id", __PRETTY_FUNCTION__);
276
9ce05555
A
277 if (NULL == __CFRuntimeClassTable[typeID]) {
278 return NULL;
279 }
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));
d8925383
A
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]));
9ce05555
A
287 if (NULL == memory) {
288 return NULL;
289 }
d8925383 290#if defined(DEBUG) || defined(ENABLE_ZOMBIES)
9ce05555
A
291 __CFZombifyAllocatedMemory((void *)memory);
292#endif
293 if (__CFOASafe && category) {
d8925383 294 __CFSetLastAllocationEventName(memory, category);
9ce05555 295 } else if (__CFOASafe) {
d8925383 296 __CFSetLastAllocationEventName(memory, __CFRuntimeClassTable[typeID]->className);
9ce05555
A
297 }
298 if (!usesSystemDefaultAllocator) {
d8925383
A
299 // add space to hold allocator ref for non-standard allocators.
300 // (this screws up 8 byte alignment but seems to work)
9ce05555
A
301 *(CFAllocatorRef *)((char *)memory) = CFRetain(allocator);
302 memory = (CFRuntimeBase *)((char *)memory + sizeof(CFAllocatorRef));
303 }
304 memory->_isa = __CFISAForTypeID(typeID);
305 memory->_rc = 1;
306 memory->_info = 0;
307 __CFBitfieldSetValue(memory->_info, 15, 8, typeID);
308 if (usesSystemDefaultAllocator) {
309 __CFBitfieldSetValue(memory->_info, 7, 7, 1);
310 }
311 if (NULL != __CFRuntimeClassTable[typeID]->init) {
312 (__CFRuntimeClassTable[typeID]->init)(memory);
313 }
314 return memory;
315}
316
317void _CFRuntimeSetInstanceTypeID(CFTypeRef cf, CFTypeID typeID) {
318 __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_info, 15, 8, typeID);
319}
320
321CFTypeID __CFGenericTypeID(const void *cf) {
322 return __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 15, 8);
323}
324
325CF_INLINE CFTypeID __CFGenericTypeID_inline(const void *cf) {
326 return __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 15, 8);
327}
328
329CFTypeID CFTypeGetTypeID(void) {
330 return __kCFTypeTypeID;
331}
332
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); \
337}
338
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);
341
342#if !defined(__MACH__)
343
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)
347
348#endif
349
350#if defined(__MACH__)
351
352CF_INLINE int CFTYPE_IS_OBJC(const void *obj) {
353 CFTypeID typeID = __CFGenericTypeID_inline(obj);
d8925383 354 return CF_IS_OBJC(typeID, obj);
9ce05555
A
355}
356
357#define CFTYPE_OBJC_FUNCDISPATCH0(rettype, obj, sel) \
358 if (CFTYPE_IS_OBJC(obj)) \
d8925383
A
359 {rettype (*func)(void *, SEL) = (void *)__CFSendObjCMsg; \
360 static SEL s = NULL; if (!s) s = sel_registerName(sel); \
361 return func((void *)obj, s);}
9ce05555
A
362#define CFTYPE_OBJC_FUNCDISPATCH1(rettype, obj, sel, a1) \
363 if (CFTYPE_IS_OBJC(obj)) \
d8925383
A
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));}
9ce05555
A
367
368#endif
369
370CFTypeID CFGetTypeID(CFTypeRef cf) {
371#if defined(DEBUG)
372 if (NULL == cf) HALT;
373#endif
374 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeID, cf, "_cfTypeID");
375 __CFGenericAssertIsCF(cf);
376 return __CFGenericTypeID_inline(cf);
377}
378
379CFStringRef 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);
382}
383
384static CFSpinLock_t __CFGlobalRetainLock = 0;
385static CFMutableDictionaryRef __CFRuntimeExternRefCountTable = NULL;
386
387#define DISGUISE(object) ((void *)(((unsigned)object) + 1))
388#define UNDISGUISE(disguised) ((id)(((unsigned)disguised) - 1))
389
390extern void _CFDictionaryIncrementValue(CFMutableDictionaryRef dict, const void *key);
391extern int _CFDictionaryDecrementValue(CFMutableDictionaryRef dict, const void *key);
392
393// Bit 31 (highest bit) in second word of cf instance indicates external ref count
394
d8925383
A
395extern void _CFRelease(CFTypeRef cf);
396extern CFTypeRef _CFRetain(CFTypeRef cf);
397extern CFHashCode _CFHash(CFTypeRef cf);
398
9ce05555 399CFTypeRef CFRetain(CFTypeRef cf) {
d8925383
A
400 // always honor CFRetain's with a hard reference
401 if (CF_IS_COLLECTABLE(cf)) {
402 auto_zone_retain(__CFCollectableZone, (void*)cf);
403 return cf;
404 }
405 // XXX_PCB some Objc objects aren't really reference counted, perhaps they should be able to make that distinction?
9ce05555
A
406 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeRef, cf, "retain");
407 __CFGenericAssertIsCF(cf);
d8925383 408 return _CFRetain(cf);
9ce05555
A
409}
410
411__private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf);
412
413void CFRelease(CFTypeRef cf) {
d8925383
A
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);
417 return;
418 }
419 // XXX_PCB some objects aren't really reference counted.
9ce05555
A
420 CFTYPE_OBJC_FUNCDISPATCH0(void, cf, "release");
421 __CFGenericAssertIsCF(cf);
d8925383 422 _CFRelease(cf);
9ce05555
A
423}
424
425static uint64_t __CFGetFullRetainCount(CFTypeRef cf) {
426 uint32_t lowBits = 0;
427 uint64_t highBits = 0, compositeRC;
428 lowBits = ((CFRuntimeBase *)cf)->_rc;
429 if (0 == lowBits) {
d8925383 430 return (uint64_t)0x00ffffffffffffffULL;
9ce05555
A
431 }
432 if ((lowBits & 0x08000) != 0) {
d8925383 433 highBits = (uint64_t)(uintptr_t)CFDictionaryGetValue(__CFRuntimeExternRefCountTable, DISGUISE(cf));
9ce05555
A
434 }
435 compositeRC = (lowBits & 0x7fff) + (highBits << 15);
436 return compositeRC;
437}
438
d8925383
A
439CFTypeRef _CFRetainGC(CFTypeRef cf)
440{
441#if defined(DEBUG)
442 if (CF_USING_COLLECTABLE_MEMORY && !CF_IS_COLLECTABLE(cf)) {
443 fprintf(stderr, "non-auto object %p passed to _CFRetainGC.\n", cf);
444 HALT;
445 }
446#endif
447 return CF_USING_COLLECTABLE_MEMORY ? cf : CFRetain(cf);
448}
449
450void _CFReleaseGC(CFTypeRef cf)
451{
452#if defined(DEBUG)
453 if (CF_USING_COLLECTABLE_MEMORY && !CF_IS_COLLECTABLE(cf)) {
454 fprintf(stderr, "non-auto object %p passed to _CFReleaseGC.\n", cf);
455 HALT;
456 }
457#endif
458 if (!CF_USING_COLLECTABLE_MEMORY) CFRelease(cf);
459}
460
9ce05555
A
461CFIndex CFGetRetainCount(CFTypeRef cf) {
462 uint64_t rc;
463 CFIndex result;
464#if defined(DEBUG)
465 if (NULL == cf) HALT;
466#endif
d8925383
A
467 if (CF_IS_COLLECTABLE(cf)) {
468 return auto_zone_retain_count(__CFCollectableZone, cf);
469 }
9ce05555
A
470 CFTYPE_OBJC_FUNCDISPATCH0(CFIndex, cf, "retainCount");
471 __CFGenericAssertIsCF(cf);
472 rc = __CFGetFullRetainCount(cf);
473 result = (rc < (uint64_t)0x7FFFFFFF) ? (CFIndex)rc : (CFIndex)0x7FFFFFFF;
474 return result;
475}
476
d8925383
A
477CFTypeRef CFMakeCollectable(CFTypeRef cf)
478{
479 if (!cf) return NULL;
480 if (CF_USING_COLLECTABLE_MEMORY) {
481#if defined(DEBUG)
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);
485 HALT;
486 }
487#endif
488 if (CFGetRetainCount(cf) == 0) {
489 CFLog(0, CFSTR("object %p with 0 retain-count passed to CFMakeCollected."), cf);
490 return cf;
491 }
492 CFRelease(cf);
493 }
494 return cf;
495}
496
9ce05555
A
497Boolean CFEqual(CFTypeRef cf1, CFTypeRef cf2) {
498#if defined(DEBUG)
499 if (NULL == cf1) HALT;
500 if (NULL == cf2) HALT;
501#endif
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);
510 }
511 return false;
512}
513
514CFHashCode CFHash(CFTypeRef cf) {
9ce05555
A
515 CFTYPE_OBJC_FUNCDISPATCH0(CFHashCode, cf, "hash");
516 __CFGenericAssertIsCF(cf);
d8925383 517 return _CFHash(cf);
9ce05555
A
518}
519
520// definition: produces a normally non-NULL debugging description of the object
521CFStringRef CFCopyDescription(CFTypeRef cf) {
522#if defined(DEBUG)
523 if (NULL == cf) HALT;
524#endif
d8925383
A
525 if (CFTYPE_IS_OBJC(cf)) {
526 static SEL s = NULL;
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
531 return result;
532 }
533 // CFTYPE_OBJC_FUNCDISPATCH0(CFStringRef, cf, "_copyDescription"); // XXX returns 0 refcounted item under GC
9ce05555
A
534 __CFGenericAssertIsCF(cf);
535 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyDebugDesc) {
536 CFStringRef result;
537 result = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyDebugDesc(cf);
538 if (NULL != result) return result;
539 }
540 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<%s %p [%p]>"), __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->className, cf, CFGetAllocator(cf));
541}
542
543// Definition: if type produces a formatting description, return that string, otherwise NULL
544__private_extern__ CFStringRef __CFCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
545#if defined(DEBUG)
546 if (NULL == cf) HALT;
547#endif
548#if defined(__MACH__)
549 if (CFTYPE_IS_OBJC(cf)) {
550 static SEL s = NULL, r = NULL;
551 CFStringRef (*func)(void *, SEL, ...) = (void *)__CFSendObjCMsg;
d8925383
A
552 if (!s) s = sel_registerName("_copyFormattingDescription:");
553 if (!r) r = sel_registerName("respondsToSelector:");
9ce05555
A
554 if (s && func((void *)cf, r, s)) return func((void *)cf, s, formatOptions);
555 return NULL;
556 }
557#endif
558 __CFGenericAssertIsCF(cf);
559 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyFormattingDesc) {
560 return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyFormattingDesc(cf, formatOptions);
561 }
562 return NULL;
563}
564
565extern CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef);
566
567CFAllocatorRef CFGetAllocator(CFTypeRef cf) {
568#if defined(DEBUG)
569 if (NULL == cf) HALT;
570#endif
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);
576 }
577 return __CFGetAllocator(cf);
578}
579
580extern void __CFBaseInitialize(void);
581extern void __CFNullInitialize(void);
582extern void __CFAllocatorInitialize(void);
583extern void __CFStringInitialize(void);
584extern void __CFArrayInitialize(void);
585extern void __CFBagInitialize(void);
586extern void __CFBooleanInitialize(void);
587extern void __CFCharacterSetInitialize(void);
588extern void __CFDataInitialize(void);
589extern void __CFDateInitialize(void);
590extern void __CFDictionaryInitialize(void);
591extern void __CFNumberInitialize(void);
592extern void __CFSetInitialize(void);
593extern void __CFStorageInitialize(void);
594extern void __CFTimeZoneInitialize(void);
595extern void __CFTreeInitialize(void);
596extern void __CFURLInitialize(void);
597extern void __CFXMLNodeInitialize(void);
598extern void __CFXMLParserInitialize(void);
d8925383
A
599extern void __CFLocaleInitialize(void);
600extern void __CFCalendarInitialize(void);
601extern void __CFNumberFormatterInitialize(void);
602extern void __CFDateFormatterInitialize(void);
9ce05555
A
603#if defined(__MACH__)
604extern void __CFMessagePortInitialize(void);
605extern void __CFMachPortInitialize(void);
606#endif
607#if defined(__MACH__) || defined(__WIN32__)
608extern void __CFRunLoopInitialize(void);
609extern void __CFRunLoopObserverInitialize(void);
610extern void __CFRunLoopSourceInitialize(void);
611extern void __CFRunLoopTimerInitialize(void);
612extern void __CFSocketInitialize(void);
613#endif
614extern void __CFBundleInitialize(void);
615extern void __CFPlugInInitialize(void);
616extern void __CFPlugInInstanceInitialize(void);
617extern void __CFUUIDInitialize(void);
618extern void __CFBinaryHeapInitialize(void);
619extern void __CFBitVectorInitialize(void);
d8925383
A
620#if defined(__WIN32__)
621extern void __CFWindowsMessageQueueInitialize(void);
622extern void __CFBaseCleanup(void);
623#endif
624extern void __CFStreamInitialize(void);
625#if defined(__MACH__)
626extern void __CFPreferencesDomainInitialize(void);
627extern void __CFUserNotificationInitialize(void);
628#endif
9ce05555
A
629
630#if defined(DEBUG)
631#define DO_SYSCALL_TRACE_HELPERS 1
632#endif
633#if defined(DO_SYSCALL_TRACE_HELPERS) && defined(__MACH__)
634extern void ptrace(int, int, int, int);
d8925383 635#define SYSCALL_TRACE(N) do ptrace(N, 0, 0, 0); while (0)
9ce05555 636#else
d8925383 637#define SYSCALL_TRACE(N) do {} while (0)
9ce05555
A
638#endif
639
640#if defined(__MACH__) && defined(PROFILE)
641static void _CF_mcleanup(void) {
642 monitor(0,0,0,0,0);
643}
644#endif
645
9ce05555
A
646const void *__CFArgStuff = NULL;
647__private_extern__ void *__CFAppleLanguages = NULL;
648__private_extern__ void *__CFSessionID = NULL;
649
650#if defined(__LINUX__) || defined(__FREEBSD__)
651static void __CFInitialize(void) __attribute__ ((constructor));
652static
653#endif
654#if defined(__WIN32__)
655CF_EXPORT
656#endif
657void __CFInitialize(void) {
658 static int __done = 0;
659 if (sizeof(int) != sizeof(long) || 4 != sizeof(long)) __HALT();
9ce05555 660
d8925383 661 if (!__done) {
9ce05555
A
662 __done = 1;
663 SYSCALL_TRACE(0xC000);
d8925383
A
664 {
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;
673 }
674 }
675#if defined(DEBUG) || defined(ENABLE_ZOMBIES)
9ce05555
A
676 {
677 const char *value = getenv("CFZombieLevel");
678 if (NULL != value) {
679 __CFZombieLevel = strtoul(value, NULL, 0);
680 }
681 if (0x0 == __CFZombieLevel) __CFZombieLevel = 0xCF00FC00; // default
682 }
683#endif
684#if defined(__MACH__) && defined(PROFILE)
685 {
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);
694 moninit();
695 }
696 }
697#endif
698
699 __CFBaseInitialize();
700
701#if defined(__MACH__)
d8925383
A
702 {
703 CFIndex idx;
704 for (idx = 0; idx < __CFMaxRuntimeTypes; idx++) {
705 __CFRuntimeObjCClassTable[idx] = &__CFNSTypeClass;
706 }
707 }
9ce05555
A
708#endif
709
710 /* Here so that two runtime classes get indices 0, 1. */
711 __kCFNotATypeTypeID = _CFRuntimeRegisterClass(&__CFNotATypeClass);
712 __kCFTypeTypeID = _CFRuntimeRegisterClass(&__CFTypeClass);
713
714 /* Here so that __kCFAllocatorTypeID gets index 2. */
715 __CFAllocatorInitialize();
716
717 /* Basic collections need to be up before CFString. */
718 __CFDictionaryInitialize();
719 __CFArrayInitialize();
720 __CFDataInitialize();
721 __CFSetInitialize();
722
723#if defined(__MACH__)
724 {
d8925383 725 CFIndex idx, cnt;
9ce05555
A
726 char **args = *_NSGetArgv();
727 cnt = *_NSGetArgc();
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);
733 break;
734 }
735 }
736 }
737#endif
738
d8925383
A
739
740 // Creating this lazily in CFRetain causes recursive call to CFRetain
741 __CFRuntimeExternRefCountTable = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
742
743 /*** _CFRuntimeCreateInstance() can finally be called generally after this line. ***/
744
745 __CFStringInitialize(); // CFString's TypeID must be 0x7, now and forever
9ce05555
A
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
751
752 __CFBinaryHeapInitialize();
753 __CFBitVectorInitialize();
754 __CFBagInitialize();
755 __CFCharacterSetInitialize();
756 __CFStorageInitialize();
757 __CFTreeInitialize();
758 __CFURLInitialize();
d8925383 759 __CFXMLNodeInitialize();
9ce05555
A
760 __CFXMLParserInitialize();
761 __CFBundleInitialize();
762 __CFPlugInInitialize();
763 __CFPlugInInstanceInitialize();
764 __CFUUIDInitialize();
765#if defined(__MACH__)
766 __CFMessagePortInitialize();
767 __CFMachPortInitialize();
768#endif
769#if defined(__MACH__) || defined(__WIN32__)
770 __CFRunLoopInitialize();
771 __CFRunLoopObserverInitialize();
772 __CFRunLoopSourceInitialize();
773 __CFRunLoopTimerInitialize();
774 __CFSocketInitialize();
775#endif
d8925383 776 __CFStreamInitialize();
9ce05555 777#if defined(__MACH__)
d8925383
A
778 __CFPreferencesDomainInitialize();
779#endif // __MACH__
780
9ce05555
A
781
782 SYSCALL_TRACE(0xC001);
783
784#if defined(__MACH__)
785 {
d8925383 786 CFIndex idx, cnt;
9ce05555
A
787 char **args = *_NSGetArgv();
788 CFIndex count;
789 cnt = *_NSGetArgc();
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.
802 }
803 if (NULL != list[count]) count++;
804 }
805 __CFArgStuff = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)list, count, &kCFTypeArrayCallBacks);
806 }
807
808 __CFSessionID = getenv("SECURITYSESSIONID");
809#endif
810 _CFProcessPath(); // cache this early
811
812#if defined(__MACH__)
d8925383 813 __CFOAInitialize();
9ce05555
A
814 SYSCALL_TRACE(0xC003);
815#endif
816
d8925383
A
817 if (__CFRuntimeClassTableCount < 100) __CFRuntimeClassTableCount = 100;
818
9ce05555
A
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"));
822#endif
823 SYSCALL_TRACE(0xC0FF);
824 }
825}
826
827#if defined(__WIN32__)
828
829/* We have to call __CFInitialize when library is attached to the process.
830 * (Sergey Zubarev)
831 */
832WINBOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID pReserved ) {
833 if (dwReason == DLL_PROCESS_ATTACH) {
d8925383 834 __CFInitialize();
9ce05555 835 } else if (dwReason == DLL_PROCESS_DETACH) {
d8925383
A
836 __CFStringCleanup();
837 __CFSocketCleanup();
838 __CFUniCharCleanup();
839 __CFStreamCleanup();
840 __CFBaseCleanup();
841 } else if (dwReason == DLL_THREAD_DETACH) {
842 __CFFinalizeThreadData(NULL);
9ce05555
A
843 }
844 return TRUE;
845}
846
847#endif
848
849
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
852
853Boolean _CFEqual(CFTypeRef cf1, CFTypeRef cf2) {
854#if defined(DEBUG)
855 if (NULL == cf1) HALT;
856 if (NULL == cf2) HALT;
857#endif
858 if (cf1 == cf2) return true;
859 __CFGenericAssertIsCF(cf1);
860 __CFGenericAssertIsCF(cf2);
d8925383
A
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);
9ce05555
A
864 }
865 return false;
866}
867
868CFIndex _CFGetRetainCount(CFTypeRef cf) {
869 uint64_t rc;
870 CFIndex result;
871 rc = __CFGetFullRetainCount(cf);
872 result = (rc < (uint64_t)0x7FFFFFFF) ? (CFIndex)rc : (CFIndex)0x7FFFFFFF;
873 return result;
874}
875
876CFHashCode _CFHash(CFTypeRef cf) {
d8925383
A
877#if defined(DEBUG)
878 if (NULL == cf) HALT;
879#endif
9ce05555
A
880 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->hash) {
881 return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->hash(cf);
882 }
883 return (CFHashCode)cf;
884}
885
886CF_EXPORT CFTypeRef _CFRetain(CFTypeRef cf) {
887 CFIndex lowBits = 0;
9ce05555
A
888#if defined(DEBUG)
889 if (NULL == cf) HALT;
890#endif
d8925383 891 __CFSpinLock(&__CFGlobalRetainLock);
9ce05555 892 lowBits = ((CFRuntimeBase *)cf)->_rc;
d8925383
A
893 if (__builtin_expect(0 == lowBits, 0)) { // Constant CFTypeRef
894 __CFSpinUnlock(&__CFGlobalRetainLock);
9ce05555
A
895 return cf;
896 }
897 lowBits++;
d8925383 898 if (__builtin_expect((lowBits & 0x07fff) == 0, 0)) {
9ce05555
A
899 // Roll over another bit to the external ref count
900 _CFDictionaryIncrementValue(__CFRuntimeExternRefCountTable, DISGUISE(cf));
901 lowBits = 0x8000; // Bit 16 indicates external ref count
902 }
903 ((CFRuntimeBase *)cf)->_rc = lowBits;
d8925383
A
904 __CFSpinUnlock(&__CFGlobalRetainLock);
905 if (__builtin_expect(__CFOASafe, 0)) {
9ce05555
A
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);
910 }
911 return cf;
912}
913
914CF_EXPORT void _CFRelease(CFTypeRef cf) {
915 CFIndex lowBits = 0;
9ce05555
A
916#if defined(DEBUG)
917 if (NULL == cf) HALT;
918#endif
d8925383 919 __CFSpinLock(&__CFGlobalRetainLock);
9ce05555 920 lowBits = ((CFRuntimeBase *)cf)->_rc;
d8925383
A
921 if (__builtin_expect(0 == lowBits, 0)) { // Constant CFTypeRef
922 __CFSpinUnlock(&__CFGlobalRetainLock);
9ce05555
A
923 return;
924 }
d8925383
A
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)
9ce05555
A
930 __CFZombifyDeallocatedMemory((void *)cf);
931 if (!(__CFZombieLevel & (1 << 4))) {
932 __CFAllocatorDeallocate((void *)cf);
933 }
934#else
935 __CFAllocatorDeallocate((void *)cf);
936#endif
937 } else {
938 CFAllocatorRef allocator;
d8925383
A
939// ((CFRuntimeBase *)cf)->_rc = 0;
940 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->finalize) {
941 __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->finalize(cf);
9ce05555 942 }
d8925383 943 if (__builtin_expect(__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 7, 7), 1)) {
9ce05555
A
944 allocator = kCFAllocatorSystemDefault;
945 } else {
946 allocator = CFGetAllocator(cf);
947 (intptr_t)cf -= sizeof(CFAllocatorRef);
948 }
d8925383 949#if defined(DEBUG) || defined(ENABLE_ZOMBIES)
9ce05555
A
950 __CFZombifyDeallocatedMemory((void *)cf);
951 if (!(__CFZombieLevel & (1 << 4))) {
952 CFAllocatorDeallocate(allocator, (void *)cf);
953 }
954#else
955 CFAllocatorDeallocate(allocator, (void *)cf);
956#endif
957 if (kCFAllocatorSystemDefault != allocator) {
958 CFRelease(allocator);
959 }
960 }
961 } else {
d8925383 962 if (__builtin_expect(0x8000 == lowBits, 0)) {
9ce05555
A
963 // Time to remove a bit from the external ref count
964 if (0 == _CFDictionaryDecrementValue(__CFRuntimeExternRefCountTable, DISGUISE(cf))) {
965 lowBits = 0x07fff;
966 } else {
967 lowBits = 0x0ffff;
968 }
969 } else {
970 lowBits--;
971 }
972 ((CFRuntimeBase *)cf)->_rc = lowBits;
d8925383
A
973 __CFSpinUnlock(&__CFGlobalRetainLock);
974 if (__builtin_expect(__CFOASafe, 0)) {
9ce05555
A
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);
979 }
980 }
981}
982
983#undef DO_SYSCALL_TRACE_HELPERS
984#undef SYSCALL_TRACE
985#undef __kCFAllocatorTypeID_CONST
986#undef __CFGenericAssertIsCF