]>
Commit | Line | Data |
---|---|---|
9ce05555 A |
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 |