]> git.saurik.com Git - apple/cf.git/blame_incremental - Base.subproj/CFRuntime.c
CF-299.tar.gz
[apple/cf.git] / Base.subproj / CFRuntime.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/* CFRuntime.c
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Christopher Kane
28*/
29
30#include "CFRuntime.h"
31#include "CFInternal.h"
32#include <string.h>
33#include <stdlib.h>
34#if defined(__MACH__)
35#include <monitor.h>
36#include <mach-o/dyld.h>
37#include <crt_externs.h>
38#else
39#define __is_threaded (1)
40#endif
41
42extern size_t malloc_size(const void *ptr);
43extern int __setonlyClocaleconv(int val);
44
45#if defined(__MACH__)
46extern void __CFRecordAllocationEvent(int eventnum, void *ptr, int size, int data, const char *classname);
47#else
48#define __CFRecordAllocationEvent(a, b, c, d, e)
49#endif
50
51enum {
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
56};
57
58/* On Win32 we should use _msize instead of malloc_size
59 * (Aleksey Dukhnyakov)
60 */
61#if defined(__WIN32__)
62#include <malloc.h>
63CF_INLINE size_t malloc_size(void *memblock) {
64 return _msize(memblock);
65}
66#endif
67
68#if defined(__MACH__)
69
70bool __CFOASafe = false;
71
72void __CFOAInitialize(void) {
73 static void (*dyfunc)(void) = (void *)0xFFFFFFFF;
74 if (NULL == getenv("OAKeepAllocationStatistics")) return;
75 if ((void *)0xFFFFFFFF == dyfunc) {
76 dyfunc = NULL;
77 if (NSIsSymbolNameDefined("__OAInitialize"))
78 dyfunc = (void *)NSAddressOfSymbol(NSLookupAndBindSymbol("__OAInitialize"));
79 }
80 if (NULL != dyfunc) {
81 dyfunc();
82 __CFOASafe = true;
83 }
84}
85
86void __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) {
90 dyfunc = NULL;
91 if (NSIsSymbolNameDefined("__OARecordAllocationEvent"))
92 dyfunc = (void *)NSAddressOfSymbol(NSLookupAndBindSymbol("__OARecordAllocationEvent"));
93 }
94 if (NULL != dyfunc) {
95 dyfunc(eventnum, ptr, size, data, classname);
96 }
97}
98
99void __CFSetLastAllocationEventName(void *ptr, const char *classname) {
100 static void (*dyfunc)(void *, const char *) = (void *)0xFFFFFFFF;
101 if (!__CFOASafe) return;
102 if ((void *)0xFFFFFFFF == dyfunc) {
103 dyfunc = NULL;
104 if (NSIsSymbolNameDefined("__OASetLastAllocationEventName"))
105 dyfunc = (void *)NSAddressOfSymbol(NSLookupAndBindSymbol("__OASetLastAllocationEventName"));
106 }
107 if (NULL != dyfunc) {
108 dyfunc(ptr, classname);
109 }
110}
111#endif
112
113extern void __HALT(void);
114
115static CFTypeID __kCFNotATypeTypeID = _kCFRuntimeNotATypeID;
116
117static const CFRuntimeClass __CFNotATypeClass = {
118 0,
119 "Not A Type",
120 (void *)__HALT,
121 (void *)__HALT,
122 (void *)__HALT,
123 (void *)__HALT,
124 (void *)__HALT,
125 (void *)__HALT,
126 (void *)__HALT
127};
128
129static CFTypeID __kCFTypeTypeID = _kCFRuntimeNotATypeID;
130
131static const CFRuntimeClass __CFTypeClass = {
132 0,
133 "CFType",
134 (void *)__HALT,
135 (void *)__HALT,
136 (void *)__HALT,
137 (void *)__HALT,
138 (void *)__HALT,
139 (void *)__HALT,
140 (void *)__HALT
141};
142
143/* bits 15-8 in the CFRuntimeBase _info are type */
144/* bits 7-0 in the CFRuntimeBase are reserved for CF's use */
145
146static CFRuntimeClass * __CFRuntimeClassTable[__CFMaxRuntimeTypes] = {NULL};
147static int32_t __CFRuntimeClassTableCount = 0;
148
149#if defined(__MACH__)
150
151__private_extern__ SEL (*__CFGetObjCSelector)(const char *) = NULL;
152__private_extern__ void * (*__CFSendObjCMsg)(const void *, SEL, ...) = NULL;
153
154__private_extern__ struct objc_class *__CFRuntimeObjCClassTable[__CFMaxRuntimeTypes] = {NULL};
155
156#endif
157
158// Compiler uses this symbol name
159int __CFConstantStringClassReference[10] = {0};
160
161#if defined(__MACH__)
162static struct objc_class __CFNSTypeClass = {{0, 0}, NULL, {0, 0, 0, 0, 0, 0, 0}};
163#else
164static void *__CFNSTypeClass[10] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
165#endif
166
167//static CFSpinLock_t __CFRuntimeLock = 0;
168
169CFTypeID _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;
175 }
176 __CFRuntimeClassTable[__CFRuntimeClassTableCount++] = (CFRuntimeClass *)cls;
177 return __CFRuntimeClassTableCount - 1;
178}
179
180const CFRuntimeClass * _CFRuntimeGetClassWithTypeID(CFTypeID typeID) {
181 return __CFRuntimeClassTable[typeID];
182}
183
184void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID) {
185 __CFRuntimeClassTable[typeID] = NULL;
186}
187
188
189#if defined(DEBUG)
190
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)
198 */
199
200static uint32_t __CFZombieLevel = 0x0;
201
202static void __CFZombifyAllocatedMemory(void *cf) {
203 if (__CFZombieLevel & (1 << 16)) {
204 void *ptr = cf;
205 size_t size = malloc_size(cf);
206 uint8_t byte = 0xCF;
207 if (__CFZombieLevel & (1 << 23)) {
208 byte = (__CFZombieLevel >> 24) & 0xFF;
209 }
210 memset(ptr, byte, size);
211 }
212}
213
214static void __CFZombifyDeallocatedMemory(void *cf) {
215 if (__CFZombieLevel & (1 << 0)) {
216 void *ptr = cf;
217 size_t size = malloc_size(cf);
218 uint8_t byte = 0xFC;
219 if (__CFZombieLevel & (1 << 1)) {
220 ptr += sizeof(CFRuntimeBase);
221 size -= sizeof(CFRuntimeBase);
222 }
223 if (__CFZombieLevel & (1 << 7)) {
224 byte = (__CFZombieLevel >> 8) & 0xFF;
225 }
226 memset(ptr, byte, size);
227 }
228}
229
230#endif /* DEBUG */
231
232CFTypeRef _CFRuntimeCreateInstance(CFAllocatorRef allocator, CFTypeID typeID, uint32_t extraBytes, unsigned char *category) {
233 CFRuntimeBase *memory;
234 Boolean usesSystemDefaultAllocator;
235 int32_t size;
236
237 if (NULL == __CFRuntimeClassTable[typeID]) {
238 return NULL;
239 }
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) {
246 return NULL;
247 }
248#if defined(DEBUG)
249 __CFZombifyAllocatedMemory((void *)memory);
250#endif
251 if (__CFOASafe && category) {
252 __CFSetLastAllocationEventName(memory, category);
253 } else if (__CFOASafe) {
254 __CFSetLastAllocationEventName(memory, __CFRuntimeClassTable[typeID]->className);
255 }
256 if (!usesSystemDefaultAllocator) {
257 *(CFAllocatorRef *)((char *)memory) = CFRetain(allocator);
258 memory = (CFRuntimeBase *)((char *)memory + sizeof(CFAllocatorRef));
259 }
260 memory->_isa = __CFISAForTypeID(typeID);
261 memory->_rc = 1;
262 memory->_info = 0;
263 __CFBitfieldSetValue(memory->_info, 15, 8, typeID);
264 if (usesSystemDefaultAllocator) {
265 __CFBitfieldSetValue(memory->_info, 7, 7, 1);
266 }
267 if (NULL != __CFRuntimeClassTable[typeID]->init) {
268 (__CFRuntimeClassTable[typeID]->init)(memory);
269 }
270 return memory;
271}
272
273void _CFRuntimeSetInstanceTypeID(CFTypeRef cf, CFTypeID typeID) {
274 __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_info, 15, 8, typeID);
275}
276
277CFTypeID __CFGenericTypeID(const void *cf) {
278 return __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 15, 8);
279}
280
281CF_INLINE CFTypeID __CFGenericTypeID_inline(const void *cf) {
282 return __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 15, 8);
283}
284
285CFTypeID CFTypeGetTypeID(void) {
286 return __kCFTypeTypeID;
287}
288
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); \
293}
294
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);
297
298#if !defined(__MACH__)
299
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)
303
304#endif
305
306#if defined(__MACH__)
307
308CF_INLINE int CFTYPE_IS_OBJC(const void *obj) {
309 CFTypeID typeID = __CFGenericTypeID_inline(obj);
310 return CF_IS_OBJC(typeID, obj) && __CFSendObjCMsg;
311}
312
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));}
323
324#endif
325
326CFTypeID CFGetTypeID(CFTypeRef cf) {
327#if defined(DEBUG)
328 if (NULL == cf) HALT;
329#endif
330 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeID, cf, "_cfTypeID");
331 __CFGenericAssertIsCF(cf);
332 return __CFGenericTypeID_inline(cf);
333}
334
335CFStringRef 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);
338}
339
340static CFSpinLock_t __CFGlobalRetainLock = 0;
341static CFMutableDictionaryRef __CFRuntimeExternRefCountTable = NULL;
342
343#define DISGUISE(object) ((void *)(((unsigned)object) + 1))
344#define UNDISGUISE(disguised) ((id)(((unsigned)disguised) - 1))
345
346extern void _CFDictionaryIncrementValue(CFMutableDictionaryRef dict, const void *key);
347extern int _CFDictionaryDecrementValue(CFMutableDictionaryRef dict, const void *key);
348
349// Bit 31 (highest bit) in second word of cf instance indicates external ref count
350
351CFTypeRef CFRetain(CFTypeRef cf) {
352 CFIndex lowBits = 0;
353 bool is_threaded = __is_threaded;
354#if defined(DEBUG)
355 if (NULL == cf) HALT;
356#endif
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);
363 return cf;
364 }
365 lowBits++;
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
370 }
371 ((CFRuntimeBase *)cf)->_rc = lowBits;
372 if (is_threaded) __CFSpinUnlock(&__CFGlobalRetainLock);
373 if (__CFOASafe) {
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);
378 }
379 return cf;
380}
381
382__private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf);
383
384void CFRelease(CFTypeRef cf) {
385 CFIndex lowBits = 0;
386 bool is_threaded = __is_threaded;
387#if defined(DEBUG)
388 if (NULL == cf) HALT;
389#endif
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);
396 return;
397 }
398 if (1 == lowBits) {
399 if (is_threaded) __CFSpinUnlock(&__CFGlobalRetainLock);
400 if (__CFOASafe) __CFRecordAllocationEvent(__kCFReleaseEvent, (void *)cf, 0, 0, NULL);
401 if (__kCFAllocatorTypeID_CONST == __CFGenericTypeID_inline(cf)) {
402#if defined(DEBUG)
403 __CFZombifyDeallocatedMemory((void *)cf);
404 if (!(__CFZombieLevel & (1 << 4))) {
405 __CFAllocatorDeallocate((void *)cf);
406 }
407#else
408 __CFAllocatorDeallocate((void *)cf);
409#endif
410 } else {
411 CFAllocatorRef allocator;
412 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->finalize) {
413 __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->finalize(cf);
414 }
415 if (__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 7, 7)) {
416 allocator = kCFAllocatorSystemDefault;
417 } else {
418 allocator = CFGetAllocator(cf);
419 (intptr_t)cf -= sizeof(CFAllocatorRef);
420 }
421#if defined(DEBUG)
422 __CFZombifyDeallocatedMemory((void *)cf);
423 if (!(__CFZombieLevel & (1 << 4))) {
424 CFAllocatorDeallocate(allocator, (void *)cf);
425 }
426#else
427 CFAllocatorDeallocate(allocator, (void *)cf);
428#endif
429 if (kCFAllocatorSystemDefault != allocator) {
430 CFRelease(allocator);
431 }
432 }
433 } else {
434 if (0x8000 == lowBits) {
435 // Time to remove a bit from the external ref count
436 if (0 == _CFDictionaryDecrementValue(__CFRuntimeExternRefCountTable, DISGUISE(cf))) {
437 lowBits = 0x07fff;
438 } else {
439 lowBits = 0x0ffff;
440 }
441 } else {
442 lowBits--;
443 }
444 ((CFRuntimeBase *)cf)->_rc = lowBits;
445 if (is_threaded) __CFSpinUnlock(&__CFGlobalRetainLock);
446 if (__CFOASafe) {
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);
451 }
452 }
453}
454
455static uint64_t __CFGetFullRetainCount(CFTypeRef cf) {
456 uint32_t lowBits = 0;
457 uint64_t highBits = 0, compositeRC;
458 lowBits = ((CFRuntimeBase *)cf)->_rc;
459 if (0 == lowBits) {
460 return (uint64_t)0x00FFFFFFFFFFFFFFULL;
461 }
462 if ((lowBits & 0x08000) != 0) {
463 highBits = (uint64_t)(uintptr_t)CFDictionaryGetValue(__CFRuntimeExternRefCountTable, DISGUISE(cf));
464 }
465 compositeRC = (lowBits & 0x7fff) + (highBits << 15);
466 return compositeRC;
467}
468
469CFIndex CFGetRetainCount(CFTypeRef cf) {
470 uint64_t rc;
471 CFIndex result;
472#if defined(DEBUG)
473 if (NULL == cf) HALT;
474#endif
475 CFTYPE_OBJC_FUNCDISPATCH0(CFIndex, cf, "retainCount");
476 __CFGenericAssertIsCF(cf);
477 rc = __CFGetFullRetainCount(cf);
478 result = (rc < (uint64_t)0x7FFFFFFF) ? (CFIndex)rc : (CFIndex)0x7FFFFFFF;
479 return result;
480}
481
482Boolean CFEqual(CFTypeRef cf1, CFTypeRef cf2) {
483#if defined(DEBUG)
484 if (NULL == cf1) HALT;
485 if (NULL == cf2) HALT;
486#endif
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);
495 }
496 return false;
497}
498
499CFHashCode CFHash(CFTypeRef cf) {
500#if defined(DEBUG)
501 if (NULL == cf) HALT;
502#endif
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);
507 }
508 return (CFHashCode)cf;
509}
510
511// definition: produces a normally non-NULL debugging description of the object
512CFStringRef CFCopyDescription(CFTypeRef cf) {
513#if defined(DEBUG)
514 if (NULL == cf) HALT;
515#endif
516 CFTYPE_OBJC_FUNCDISPATCH0(CFStringRef, cf, "_copyDescription");
517 __CFGenericAssertIsCF(cf);
518 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyDebugDesc) {
519 CFStringRef result;
520 result = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyDebugDesc(cf);
521 if (NULL != result) return result;
522 }
523 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<%s %p [%p]>"), __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->className, cf, CFGetAllocator(cf));
524}
525
526// Definition: if type produces a formatting description, return that string, otherwise NULL
527__private_extern__ CFStringRef __CFCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
528#if defined(DEBUG)
529 if (NULL == cf) HALT;
530#endif
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);
538 return NULL;
539 }
540#endif
541 __CFGenericAssertIsCF(cf);
542 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyFormattingDesc) {
543 return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyFormattingDesc(cf, formatOptions);
544 }
545 return NULL;
546}
547
548extern CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef);
549
550CFAllocatorRef CFGetAllocator(CFTypeRef cf) {
551#if defined(DEBUG)
552 if (NULL == cf) HALT;
553#endif
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);
559 }
560 return __CFGetAllocator(cf);
561}
562
563extern void __CFBaseInitialize(void);
564extern void __CFNullInitialize(void);
565extern void __CFAllocatorInitialize(void);
566extern void __CFStringInitialize(void);
567extern void __CFArrayInitialize(void);
568extern void __CFBagInitialize(void);
569extern void __CFBooleanInitialize(void);
570extern void __CFCharacterSetInitialize(void);
571extern void __CFDataInitialize(void);
572extern void __CFDateInitialize(void);
573extern void __CFDictionaryInitialize(void);
574extern void __CFNumberInitialize(void);
575extern void __CFSetInitialize(void);
576extern void __CFStorageInitialize(void);
577extern void __CFTimeZoneInitialize(void);
578extern void __CFTreeInitialize(void);
579extern void __CFURLInitialize(void);
580extern void __CFXMLNodeInitialize(void);
581extern void __CFXMLParserInitialize(void);
582#if defined(__MACH__)
583extern void __CFMessagePortInitialize(void);
584extern void __CFMachPortInitialize(void);
585#endif
586#if defined(__MACH__) || defined(__WIN32__)
587extern void __CFRunLoopInitialize(void);
588extern void __CFRunLoopObserverInitialize(void);
589extern void __CFRunLoopSourceInitialize(void);
590extern void __CFRunLoopTimerInitialize(void);
591extern void __CFSocketInitialize(void);
592#endif
593extern void __CFBundleInitialize(void);
594extern void __CFPlugInInitialize(void);
595extern void __CFPlugInInstanceInitialize(void);
596extern void __CFUUIDInitialize(void);
597extern void __CFBinaryHeapInitialize(void);
598extern void __CFBitVectorInitialize(void);
599
600#if defined(DEBUG)
601#define DO_SYSCALL_TRACE_HELPERS 1
602#endif
603#if defined(DO_SYSCALL_TRACE_HELPERS) && defined(__MACH__)
604extern void ptrace(int, int, int, int);
605#define SYSCALL_TRACE(N) do ptrace(N, 0, 0, 0); while (0)
606#else
607#define SYSCALL_TRACE(N) do {} while (0)
608#endif
609
610#if defined(__MACH__) && defined(PROFILE)
611static void _CF_mcleanup(void) {
612 monitor(0,0,0,0,0);
613}
614#endif
615
616extern CFTypeID CFTimeZoneGetTypeID(void);
617extern CFTypeID CFNumberGetTypeID(void);
618extern CFTypeID CFBooleanGetTypeID(void);
619
620const void *__CFArgStuff = NULL;
621__private_extern__ void *__CFAppleLanguages = NULL;
622__private_extern__ void *__CFSessionID = NULL;
623
624#if defined(__LINUX__) || defined(__FREEBSD__)
625static void __CFInitialize(void) __attribute__ ((constructor));
626static
627#endif
628#if defined(__WIN32__)
629CF_EXPORT
630#endif
631void __CFInitialize(void) {
632 static int __done = 0;
633 if (sizeof(int) != sizeof(long) || 4 != sizeof(long)) __HALT();
634 if (!__done) {
635 CFIndex idx, cnt;
636
637 __done = 1;
638 SYSCALL_TRACE(0xC000);
639
640 __setonlyClocaleconv(1);
641#if defined(DEBUG)
642 {
643 const char *value = getenv("CFZombieLevel");
644 if (NULL != value) {
645 __CFZombieLevel = strtoul(value, NULL, 0);
646 }
647 if (0x0 == __CFZombieLevel) __CFZombieLevel = 0xCF00FC00; // default
648 }
649#endif
650#if defined(__MACH__) && defined(PROFILE)
651 {
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);
660 moninit();
661 }
662 }
663#endif
664
665 __CFBaseInitialize();
666
667#if defined(__MACH__)
668 for (idx = 0; idx < __CFMaxRuntimeTypes; idx++) {
669 __CFRuntimeObjCClassTable[idx] = &__CFNSTypeClass;
670 }
671#endif
672
673 /* Here so that two runtime classes get indices 0, 1. */
674 __kCFNotATypeTypeID = _CFRuntimeRegisterClass(&__CFNotATypeClass);
675 __kCFTypeTypeID = _CFRuntimeRegisterClass(&__CFTypeClass);
676
677 /* Here so that __kCFAllocatorTypeID gets index 2. */
678 __CFAllocatorInitialize();
679
680 /* Basic collections need to be up before CFString. */
681 __CFDictionaryInitialize();
682 __CFArrayInitialize();
683 __CFDataInitialize();
684 __CFSetInitialize();
685
686#if defined(__MACH__)
687 {
688 char **args = *_NSGetArgv();
689 cnt = *_NSGetArgc();
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);
695 break;
696 }
697 }
698 }
699#endif
700
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);
714#endif
715
716 // Creating this lazily in CFRetain causes recursive call to CFRetain
717 __CFRuntimeExternRefCountTable = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
718
719 /*** _CFRuntimeCreateInstance() can finally be called generally after this line. ***/
720
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
727
728 __CFBinaryHeapInitialize();
729 __CFBitVectorInitialize();
730 __CFBagInitialize();
731 __CFCharacterSetInitialize();
732 __CFStorageInitialize();
733 __CFTreeInitialize();
734 __CFURLInitialize();
735 __CFXMLNodeInitialize();
736 __CFXMLParserInitialize();
737 __CFBundleInitialize();
738 __CFPlugInInitialize();
739 __CFPlugInInstanceInitialize();
740 __CFUUIDInitialize();
741#if defined(__MACH__)
742 __CFMessagePortInitialize();
743 __CFMachPortInitialize();
744#endif
745#if defined(__MACH__) || defined(__WIN32__)
746 __CFRunLoopInitialize();
747 __CFRunLoopObserverInitialize();
748 __CFRunLoopSourceInitialize();
749 __CFRunLoopTimerInitialize();
750 __CFSocketInitialize();
751#endif
752
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);
759#endif
760
761 SYSCALL_TRACE(0xC001);
762
763#if defined(__MACH__)
764 {
765 char **args = *_NSGetArgv();
766 CFIndex count;
767 cnt = *_NSGetArgc();
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.
780 }
781 if (NULL != list[count]) count++;
782 }
783 __CFArgStuff = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)list, count, &kCFTypeArrayCallBacks);
784 }
785
786 __CFSessionID = getenv("SECURITYSESSIONID");
787#endif
788 _CFProcessPath(); // cache this early
789
790#if defined(__MACH__)
791 __CFOAInitialize();
792 SYSCALL_TRACE(0xC003);
793#endif
794
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"));
798#endif
799 SYSCALL_TRACE(0xC0FF);
800 }
801}
802
803#if defined(__WIN32__)
804
805/* We have to call __CFInitialize when library is attached to the process.
806 * (Sergey Zubarev)
807 */
808WINBOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID pReserved ) {
809 if (dwReason == DLL_PROCESS_ATTACH) {
810 __CFInitialize();
811 } else if (dwReason == DLL_PROCESS_DETACH) {
812 }
813 return TRUE;
814}
815
816#endif
817
818
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
821
822Boolean _CFEqual(CFTypeRef cf1, CFTypeRef cf2) {
823#if defined(DEBUG)
824 if (NULL == cf1) HALT;
825 if (NULL == cf2) HALT;
826#endif
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);
833 }
834 return false;
835}
836
837CFIndex _CFGetRetainCount(CFTypeRef cf) {
838 uint64_t rc;
839 CFIndex result;
840 rc = __CFGetFullRetainCount(cf);
841 result = (rc < (uint64_t)0x7FFFFFFF) ? (CFIndex)rc : (CFIndex)0x7FFFFFFF;
842 return result;
843}
844
845CFHashCode _CFHash(CFTypeRef cf) {
846 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->hash) {
847 return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->hash(cf);
848 }
849 return (CFHashCode)cf;
850}
851
852CF_EXPORT CFTypeRef _CFRetain(CFTypeRef cf) {
853 CFIndex lowBits = 0;
854 bool is_threaded = __is_threaded;
855#if defined(DEBUG)
856 if (NULL == cf) HALT;
857#endif
858 if (is_threaded) __CFSpinLock(&__CFGlobalRetainLock);
859 lowBits = ((CFRuntimeBase *)cf)->_rc;
860 if (0 == lowBits) { // Constant CFTypeRef
861 if (is_threaded) __CFSpinUnlock(&__CFGlobalRetainLock);
862 return cf;
863 }
864 lowBits++;
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
869 }
870 ((CFRuntimeBase *)cf)->_rc = lowBits;
871 if (is_threaded) __CFSpinUnlock(&__CFGlobalRetainLock);
872 if (__CFOASafe) {
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);
877 }
878 return cf;
879}
880
881CF_EXPORT void _CFRelease(CFTypeRef cf) {
882 CFIndex lowBits = 0;
883 bool is_threaded = __is_threaded;
884#if defined(DEBUG)
885 if (NULL == cf) HALT;
886#endif
887 if (is_threaded) __CFSpinLock(&__CFGlobalRetainLock);
888 lowBits = ((CFRuntimeBase *)cf)->_rc;
889 if (0 == lowBits) { // Constant CFTypeRef
890 if (is_threaded) __CFSpinUnlock(&__CFGlobalRetainLock);
891 return;
892 }
893 if (1 == lowBits) {
894 if (is_threaded) __CFSpinUnlock(&__CFGlobalRetainLock);
895 if (__CFOASafe) __CFRecordAllocationEvent(__kCFReleaseEvent, (void *)cf, 0, 0, NULL);
896 if (__kCFAllocatorTypeID_CONST == __CFGenericTypeID(cf)) {
897#if defined(DEBUG)
898 __CFZombifyDeallocatedMemory((void *)cf);
899 if (!(__CFZombieLevel & (1 << 4))) {
900 __CFAllocatorDeallocate((void *)cf);
901 }
902#else
903 __CFAllocatorDeallocate((void *)cf);
904#endif
905 } else {
906 CFAllocatorRef allocator;
907 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID(cf)]->finalize) {
908 __CFRuntimeClassTable[__CFGenericTypeID(cf)]->finalize(cf);
909 }
910 if (__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 7, 7)) {
911 allocator = kCFAllocatorSystemDefault;
912 } else {
913 allocator = CFGetAllocator(cf);
914 (intptr_t)cf -= sizeof(CFAllocatorRef);
915 }
916#if defined(DEBUG)
917 __CFZombifyDeallocatedMemory((void *)cf);
918 if (!(__CFZombieLevel & (1 << 4))) {
919 CFAllocatorDeallocate(allocator, (void *)cf);
920 }
921#else
922 CFAllocatorDeallocate(allocator, (void *)cf);
923#endif
924 if (kCFAllocatorSystemDefault != allocator) {
925 CFRelease(allocator);
926 }
927 }
928 } else {
929 if (0x8000 == lowBits) {
930 // Time to remove a bit from the external ref count
931 if (0 == _CFDictionaryDecrementValue(__CFRuntimeExternRefCountTable, DISGUISE(cf))) {
932 lowBits = 0x07fff;
933 } else {
934 lowBits = 0x0ffff;
935 }
936 } else {
937 lowBits--;
938 }
939 ((CFRuntimeBase *)cf)->_rc = lowBits;
940 if (is_threaded) __CFSpinUnlock(&__CFGlobalRetainLock);
941 if (__CFOASafe) {
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);
946 }
947 }
948}
949
950#undef DO_SYSCALL_TRACE_HELPERS
951#undef SYSCALL_TRACE
952#undef __kCFAllocatorTypeID_CONST
953#undef __CFGenericAssertIsCF