]> git.saurik.com Git - apple/cf.git/blob - Base.subproj/CFRuntime.c
CF-299.35.tar.gz
[apple/cf.git] / Base.subproj / CFRuntime.c
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
42 extern size_t malloc_size(const void *ptr);
43 extern int __setonlyClocaleconv(int val);
44
45 #if defined(__MACH__)
46 extern 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
51 enum {
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>
63 CF_INLINE size_t malloc_size(void *memblock) {
64 return _msize(memblock);
65 }
66 #endif
67
68 #if defined(__MACH__)
69
70 bool __CFOASafe = false;
71
72 void __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
86 void __CFRecordAllocationEvent(int eventnum, void *ptr, int size, int data, const char *classname) {
87 static void (*dyfunc)(int, void *, int, int, const char *) = (void *)0xFFFFFFFF;
88 if (!__CFOASafe) return;
89 if ((void *)0xFFFFFFFF == dyfunc) {
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
99 void __CFSetLastAllocationEventName(void *ptr, const char *classname) {
100 static void (*dyfunc)(void *, const char *) = (void *)0xFFFFFFFF;
101 if (!__CFOASafe) return;
102 if ((void *)0xFFFFFFFF == dyfunc) {
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
113 extern void __HALT(void);
114
115 static CFTypeID __kCFNotATypeTypeID = _kCFRuntimeNotATypeID;
116
117 static 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
129 static CFTypeID __kCFTypeTypeID = _kCFRuntimeNotATypeID;
130
131 static 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
146 static CFRuntimeClass * __CFRuntimeClassTable[__CFMaxRuntimeTypes] = {NULL};
147 static 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
159 int __CFConstantStringClassReference[10] = {0};
160
161 #if defined(__MACH__)
162 static struct objc_class __CFNSTypeClass = {{0, 0}, NULL, {0, 0, 0, 0, 0, 0, 0}};
163 #else
164 static void *__CFNSTypeClass[10] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
165 #endif
166
167 //static CFSpinLock_t __CFRuntimeLock = 0;
168
169 CFTypeID _CFRuntimeRegisterClass(const CFRuntimeClass * const cls) {
170 // version field must be 0
171 // className must be pure ASCII string, non-null
172 if (__CFMaxRuntimeTypes <= __CFRuntimeClassTableCount) {
173 CFLog(0, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls->className);
174 return _kCFRuntimeNotATypeID;
175 }
176 __CFRuntimeClassTable[__CFRuntimeClassTableCount++] = (CFRuntimeClass *)cls;
177 return __CFRuntimeClassTableCount - 1;
178 }
179
180 const CFRuntimeClass * _CFRuntimeGetClassWithTypeID(CFTypeID typeID) {
181 return __CFRuntimeClassTable[typeID];
182 }
183
184 void _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
200 static uint32_t __CFZombieLevel = 0x0;
201
202 static 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
214 static 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
232 CFTypeRef _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
273 void _CFRuntimeSetInstanceTypeID(CFTypeRef cf, CFTypeID typeID) {
274 __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_info, 15, 8, typeID);
275 }
276
277 CFTypeID __CFGenericTypeID(const void *cf) {
278 return __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 15, 8);
279 }
280
281 CF_INLINE CFTypeID __CFGenericTypeID_inline(const void *cf) {
282 return __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 15, 8);
283 }
284
285 CFTypeID 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
308 CF_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
326 CFTypeID 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
335 CFStringRef CFCopyTypeIDDescription(CFTypeID type) {
336 CFAssert2((NULL != __CFRuntimeClassTable[type]) && __kCFNotATypeTypeID != type && __kCFTypeTypeID != type, __kCFLogAssertion, "%s(): type %d is not a CF type ID", __PRETTY_FUNCTION__, type);
337 return CFStringCreateWithCString(kCFAllocatorDefault, __CFRuntimeClassTable[type]->className, kCFStringEncodingASCII);
338 }
339
340 static CFSpinLock_t __CFGlobalRetainLock = 0;
341 static CFMutableDictionaryRef __CFRuntimeExternRefCountTable = NULL;
342
343 #define DISGUISE(object) ((void *)(((unsigned)object) + 1))
344 #define UNDISGUISE(disguised) ((id)(((unsigned)disguised) - 1))
345
346 extern void _CFDictionaryIncrementValue(CFMutableDictionaryRef dict, const void *key);
347 extern int _CFDictionaryDecrementValue(CFMutableDictionaryRef dict, const void *key);
348
349 // Bit 31 (highest bit) in second word of cf instance indicates external ref count
350
351 CFTypeRef 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
384 void 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
455 static 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
469 CFIndex 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
482 Boolean 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
499 CFHashCode 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
512 CFStringRef 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
548 extern CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef);
549
550 CFAllocatorRef 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
563 extern void __CFBaseInitialize(void);
564 extern void __CFNullInitialize(void);
565 extern void __CFAllocatorInitialize(void);
566 extern void __CFStringInitialize(void);
567 extern void __CFArrayInitialize(void);
568 extern void __CFBagInitialize(void);
569 extern void __CFBooleanInitialize(void);
570 extern void __CFCharacterSetInitialize(void);
571 extern void __CFDataInitialize(void);
572 extern void __CFDateInitialize(void);
573 extern void __CFDictionaryInitialize(void);
574 extern void __CFNumberInitialize(void);
575 extern void __CFSetInitialize(void);
576 extern void __CFStorageInitialize(void);
577 extern void __CFTimeZoneInitialize(void);
578 extern void __CFTreeInitialize(void);
579 extern void __CFURLInitialize(void);
580 extern void __CFXMLNodeInitialize(void);
581 extern void __CFXMLParserInitialize(void);
582 #if defined(__MACH__)
583 extern void __CFMessagePortInitialize(void);
584 extern void __CFMachPortInitialize(void);
585 #endif
586 #if defined(__MACH__) || defined(__WIN32__)
587 extern void __CFRunLoopInitialize(void);
588 extern void __CFRunLoopObserverInitialize(void);
589 extern void __CFRunLoopSourceInitialize(void);
590 extern void __CFRunLoopTimerInitialize(void);
591 extern void __CFSocketInitialize(void);
592 #endif
593 extern void __CFBundleInitialize(void);
594 extern void __CFPlugInInitialize(void);
595 extern void __CFPlugInInstanceInitialize(void);
596 extern void __CFUUIDInitialize(void);
597 extern void __CFBinaryHeapInitialize(void);
598 extern void __CFBitVectorInitialize(void);
599
600 #if defined(DEBUG)
601 #define DO_SYSCALL_TRACE_HELPERS 1
602 #endif
603 #if defined(DO_SYSCALL_TRACE_HELPERS) && defined(__MACH__)
604 extern void ptrace(int, int, int, int);
605 #define SYSCALL_TRACE(N) do ptrace(N, 0, 0, 0); while (0)
606 #else
607 #define SYSCALL_TRACE(N) do {} while (0)
608 #endif
609
610 #if defined(__MACH__) && defined(PROFILE)
611 static void _CF_mcleanup(void) {
612 monitor(0,0,0,0,0);
613 }
614 #endif
615
616 extern CFTypeID CFTimeZoneGetTypeID(void);
617 extern CFTypeID CFNumberGetTypeID(void);
618 extern CFTypeID CFBooleanGetTypeID(void);
619
620 const void *__CFArgStuff = NULL;
621 __private_extern__ void *__CFAppleLanguages = NULL;
622 __private_extern__ void *__CFSessionID = NULL;
623
624 #if defined(__LINUX__) || defined(__FREEBSD__)
625 static void __CFInitialize(void) __attribute__ ((constructor));
626 static
627 #endif
628 #if defined(__WIN32__)
629 CF_EXPORT
630 #endif
631 void __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 */
808 WINBOOL 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
822 Boolean _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
837 CFIndex _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
845 CFHashCode _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
852 CF_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
881 CF_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