]> git.saurik.com Git - apple/cf.git/blob - CFRuntime.c
CF-855.14.tar.gz
[apple/cf.git] / CFRuntime.c
1 /*
2 * Copyright (c) 2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /* CFRuntime.c
25 Copyright (c) 1999-2013, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
27 */
28
29 #define ENABLE_ZOMBIES 1
30
31 #include <CoreFoundation/CFRuntime.h>
32 #include "CFInternal.h"
33 #include "CFBasicHash.h"
34 #include <string.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
38 #include <dlfcn.h>
39 #include <mach-o/dyld.h>
40 #include <mach/mach.h>
41 #include <crt_externs.h>
42 #include <unistd.h>
43 #include <sys/stat.h>
44 #include <CoreFoundation/CFStringDefaultEncoding.h>
45 #endif
46 #if DEPLOYMENT_TARGET_EMBEDDED
47 // This isn't in the embedded runtime.h header
48 OBJC_EXPORT void *objc_destructInstance(id obj);
49 #endif
50
51
52
53 #if DEPLOYMENT_TARGET_WINDOWS
54 #include <Shellapi.h>
55 #endif
56
57 enum {
58 // retain/release recording constants -- must match values
59 // used by OA for now; probably will change in the future
60 __kCFRetainEvent = 28,
61 __kCFReleaseEvent = 29
62 };
63
64 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
65 #include <malloc.h>
66 #else
67 #include <malloc/malloc.h>
68 #endif
69
70 #define FAKE_INSTRUMENTS 0
71
72 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
73 CF_PRIVATE void __CFOAInitializeNSObject(void); // from NSObject.m
74
75 bool __CFOASafe = false;
76
77 void (*__CFObjectAllocRecordAllocationFunction)(int, void *, int64_t , uint64_t, const char *) = NULL;
78 void (*__CFObjectAllocSetLastAllocEventNameFunction)(void *, const char *) = NULL;
79
80 void __CFOAInitialize(void) {
81 }
82
83 void __CFRecordAllocationEvent(int eventnum, void *ptr, int64_t size, uint64_t data, const char *classname) {
84 if (!__CFOASafe || !__CFObjectAllocRecordAllocationFunction) return;
85 __CFObjectAllocRecordAllocationFunction(eventnum, ptr, size, data, classname);
86 }
87
88 void __CFSetLastAllocationEventName(void *ptr, const char *classname) {
89 if (!__CFOASafe || !__CFObjectAllocSetLastAllocEventNameFunction) return;
90 __CFObjectAllocSetLastAllocEventNameFunction(ptr, classname);
91 }
92
93 #elif FAKE_INSTRUMENTS
94
95 CF_EXPORT bool __CFOASafe = true;
96
97 void __CFOAInitialize(void) { }
98
99 void __CFRecordAllocationEvent(int eventnum, void *ptr, int64_t size, uint64_t data, const char *classname) {
100 if (!__CFOASafe) return;
101 if (!classname) classname = "(no class)";
102 const char *event = "unknown event";
103 switch (eventnum) {
104 case 21:
105 event = "zombie";
106 break;
107 case 13:
108 case __kCFReleaseEvent:
109 event = "release";
110 break;
111 case 12:
112 case __kCFRetainEvent:
113 event = "retain";
114 break;
115 }
116 fprintf(stdout, "event,%d,%s,%p,%ld,%lu,%s\n", eventnum, event, ptr, (long)size, (unsigned long)data, classname);
117 }
118
119 void __CFSetLastAllocationEventName(void *ptr, const char *classname) {
120 if (!__CFOASafe) return;
121 if (!classname) classname = "(no class)";
122 fprintf(stdout, "name,%p,%s\n", ptr, classname ? classname : "(no class)");
123 }
124
125 #else
126
127 bool __CFOASafe = false;
128
129 void __CFOAInitialize(void) { }
130 void __CFRecordAllocationEvent(int eventnum, void *ptr, int64_t size, uint64_t data, const char *classname) { }
131 void __CFSetLastAllocationEventName(void *ptr, const char *classname) { }
132
133 #endif
134
135 extern void __HALT(void);
136
137 static CFTypeID __kCFNotATypeTypeID = _kCFRuntimeNotATypeID;
138
139 #if !defined (__cplusplus)
140 static const CFRuntimeClass __CFNotATypeClass = {
141 0,
142 "Not A Type",
143 (void *)__HALT,
144 (void *)__HALT,
145 (void *)__HALT,
146 (void *)__HALT,
147 (void *)__HALT,
148 (void *)__HALT,
149 (void *)__HALT
150 };
151
152 static CFTypeID __kCFTypeTypeID = _kCFRuntimeNotATypeID;
153
154 static const CFRuntimeClass __CFTypeClass = {
155 0,
156 "CFType",
157 (void *)__HALT,
158 (void *)__HALT,
159 (void *)__HALT,
160 (void *)__HALT,
161 (void *)__HALT,
162 (void *)__HALT,
163 (void *)__HALT
164 };
165 #else
166 void SIG1(CFTypeRef){__HALT();};;
167 CFTypeRef SIG2(CFAllocatorRef,CFTypeRef){__HALT();return NULL;};
168 Boolean SIG3(CFTypeRef,CFTypeRef){__HALT();return FALSE;};
169 CFHashCode SIG4(CFTypeRef){__HALT(); return 0;};
170 CFStringRef SIG5(CFTypeRef,CFDictionaryRef){__HALT();return NULL;};
171 CFStringRef SIG6(CFTypeRef){__HALT();return NULL;};
172
173 static const CFRuntimeClass __CFNotATypeClass = {
174 0,
175 "Not A Type",
176 SIG1,
177 SIG2,
178 SIG1,
179 SIG3,
180 SIG4,
181 SIG5,
182 SIG6
183 };
184
185 static CFTypeID __kCFTypeTypeID = _kCFRuntimeNotATypeID;
186
187 static const CFRuntimeClass __CFTypeClass = {
188 0,
189 "CFType",
190 SIG1,
191 SIG2,
192 SIG1,
193 SIG3,
194 SIG4,
195 SIG5,
196 SIG6
197 };
198 #endif //__cplusplus
199
200 // the lock does not protect most reading of these; we just leak the old table to allow read-only accesses to continue to work
201 static CFSpinLock_t __CFBigRuntimeFunnel = CFSpinLockInit;
202 CF_PRIVATE CFRuntimeClass * __CFRuntimeClassTable[__CFRuntimeClassTableSize] = {0};
203 CF_PRIVATE int32_t __CFRuntimeClassTableCount = 0;
204
205 CF_PRIVATE uintptr_t __CFRuntimeObjCClassTable[__CFRuntimeClassTableSize] = {0};
206
207 #if !defined(__CFObjCIsCollectable)
208 bool (*__CFObjCIsCollectable)(void *) = NULL;
209 #endif
210
211 #if !__CONSTANT_CFSTRINGS__ || DEPLOYMENT_TARGET_EMBEDDED_MINI
212 // Compiler uses this symbol name; must match compiler built-in decl, so we use 'int'
213 #if __LP64__
214 int __CFConstantStringClassReference[24] = {0};
215 #else
216 int __CFConstantStringClassReference[12] = {0};
217 #endif
218 #endif
219
220 #if __LP64__
221 int __CFConstantStringClassReference[24] = {0};
222 #else
223 int __CFConstantStringClassReference[12] = {0};
224 #endif
225
226 void *__CFConstantStringClassReferencePtr = NULL;
227
228 Boolean _CFIsObjC(CFTypeID typeID, void *obj) {
229 return CF_IS_OBJC(typeID, obj);
230 }
231
232 CFTypeID _CFRuntimeRegisterClass(const CFRuntimeClass * const cls) {
233 // className must be pure ASCII string, non-null
234 if ((cls->version & _kCFRuntimeCustomRefCount) && !cls->refcount) {
235 CFLog(kCFLogLevelWarning, CFSTR("*** _CFRuntimeRegisterClass() given inconsistent class '%s'. Program will crash soon."), cls->className);
236 return _kCFRuntimeNotATypeID;
237 }
238 __CFSpinLock(&__CFBigRuntimeFunnel);
239 if (__CFMaxRuntimeTypes <= __CFRuntimeClassTableCount) {
240 CFLog(kCFLogLevelWarning, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls->className);
241 __CFSpinUnlock(&__CFBigRuntimeFunnel);
242 return _kCFRuntimeNotATypeID;
243 }
244 if (__CFRuntimeClassTableSize <= __CFRuntimeClassTableCount) {
245 CFLog(kCFLogLevelWarning, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls->className);
246 __CFSpinUnlock(&__CFBigRuntimeFunnel);
247 return _kCFRuntimeNotATypeID;
248 }
249 __CFRuntimeClassTable[__CFRuntimeClassTableCount++] = (CFRuntimeClass *)cls;
250 CFTypeID typeID = __CFRuntimeClassTableCount - 1;
251 __CFSpinUnlock(&__CFBigRuntimeFunnel);
252 return typeID;
253 }
254
255
256 const CFRuntimeClass * _CFRuntimeGetClassWithTypeID(CFTypeID typeID) {
257 return __CFRuntimeClassTable[typeID]; // hopelessly unthreadsafe
258 }
259
260 void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID) {
261 __CFSpinLock(&__CFBigRuntimeFunnel);
262 __CFRuntimeClassTable[typeID] = NULL;
263 __CFSpinUnlock(&__CFBigRuntimeFunnel);
264 }
265
266
267 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
268
269 CF_PRIVATE uint8_t __CFZombieEnabled = 0;
270 CF_PRIVATE uint8_t __CFDeallocateZombies = 0;
271
272 extern void __CFZombifyNSObject(void); // from NSObject.m
273
274 void _CFEnableZombies(void) {
275 }
276
277 #endif /* DEBUG */
278
279 // XXX_PCB: use the class version field as a bitmask, to allow classes to opt-in for GC scanning.
280
281 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
282 CF_INLINE CFOptionFlags CF_GET_COLLECTABLE_MEMORY_TYPE(const CFRuntimeClass *cls)
283 {
284 return ((cls->version & _kCFRuntimeScannedObject) ? __kCFAllocatorGCScannedMemory : 0) | __kCFAllocatorGCObjectMemory;
285 }
286 #else
287 #define CF_GET_COLLECTABLE_MEMORY_TYPE(x) (0)
288 #endif
289
290 CFTypeRef _CFRuntimeCreateInstance(CFAllocatorRef allocator, CFTypeID typeID, CFIndex extraBytes, unsigned char *category) {
291 if (__CFRuntimeClassTableSize <= typeID) HALT;
292 CFAssert1(typeID != _kCFRuntimeNotATypeID, __kCFLogAssertion, "%s(): Uninitialized type id", __PRETTY_FUNCTION__);
293 CFRuntimeClass *cls = __CFRuntimeClassTable[typeID];
294 if (NULL == cls) {
295 return NULL;
296 }
297 Boolean customRC = !!(cls->version & _kCFRuntimeCustomRefCount);
298 if (customRC && !cls->refcount) {
299 CFLog(kCFLogLevelWarning, CFSTR("*** _CFRuntimeCreateInstance() found inconsistent class '%s'."), cls->className);
300 return NULL;
301 }
302 if (customRC && kCFUseCollectableAllocator && (0 || 0)) {
303 CFLog(kCFLogLevelWarning, CFSTR("*** _CFRuntimeCreateInstance(): special zero-ref allocators cannot be used with class '%s' with custom ref counting."), cls->className);
304 return NULL;
305 }
306 CFAllocatorRef realAllocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
307 if (kCFAllocatorNull == realAllocator) {
308 return NULL;
309 }
310 Boolean usesSystemDefaultAllocator = _CFAllocatorIsSystemDefault(realAllocator);
311 CFIndex size = sizeof(CFRuntimeBase) + extraBytes + (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef));
312 size = (size + 0xF) & ~0xF; // CF objects are multiples of 16 in size
313 // CFType version 0 objects are unscanned by default since they don't have write-barriers and hard retain their innards
314 // CFType version 1 objects are scanned and use hand coded write-barriers to store collectable storage within
315 CFRuntimeBase *memory = (CFRuntimeBase *)CFAllocatorAllocate(allocator, size, CF_GET_COLLECTABLE_MEMORY_TYPE(cls));
316 if (NULL == memory) {
317 return NULL;
318 }
319 if (!kCFUseCollectableAllocator || !CF_IS_COLLECTABLE_ALLOCATOR(allocator) || !(CF_GET_COLLECTABLE_MEMORY_TYPE(cls) & __kCFAllocatorGCScannedMemory)) {
320 memset(memory, 0, size);
321 }
322 if (__CFOASafe && category) {
323 __CFSetLastAllocationEventName(memory, (char *)category);
324 } else if (__CFOASafe) {
325 __CFSetLastAllocationEventName(memory, (char *)cls->className);
326 }
327 if (!usesSystemDefaultAllocator) {
328 // add space to hold allocator ref for non-standard allocators.
329 // (this screws up 8 byte alignment but seems to work)
330 *(CFAllocatorRef *)((char *)memory) = (CFAllocatorRef)CFRetain(realAllocator);
331 memory = (CFRuntimeBase *)((char *)memory + sizeof(CFAllocatorRef));
332 }
333 uint32_t rc = 0;
334 #if __LP64__
335 if (!kCFUseCollectableAllocator || (1 && 1)) {
336 memory->_rc = 1;
337 }
338 if (customRC) {
339 memory->_rc = 0xFFFFFFFFU;
340 rc = 0xFF;
341 }
342 #else
343 if (!kCFUseCollectableAllocator || (1 && 1)) {
344 rc = 1;
345 }
346 if (customRC) {
347 rc = 0xFF;
348 }
349 #endif
350 uint32_t *cfinfop = (uint32_t *)&(memory->_cfinfo);
351 *cfinfop = (uint32_t)((rc << 24) | (customRC ? 0x800000 : 0x0) | ((uint32_t)typeID << 8) | (usesSystemDefaultAllocator ? 0x80 : 0x00));
352 memory->_cfisa = 0;
353 if (NULL != cls->init) {
354 (cls->init)(memory);
355 }
356 return memory;
357 }
358
359 void _CFRuntimeInitStaticInstance(void *ptr, CFTypeID typeID) {
360 CFAssert1(typeID != _kCFRuntimeNotATypeID, __kCFLogAssertion, "%s(): Uninitialized type id", __PRETTY_FUNCTION__);
361 if (__CFRuntimeClassTableSize <= typeID) HALT;
362 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
363 Boolean customRC = !!(cfClass->version & _kCFRuntimeCustomRefCount);
364 if (customRC) {
365 CFLog(kCFLogLevelError, CFSTR("*** Cannot initialize a static instance to a class (%s) with custom ref counting"), cfClass->className);
366 return;
367 }
368 CFRuntimeBase *memory = (CFRuntimeBase *)ptr;
369 uint32_t *cfinfop = (uint32_t *)&(memory->_cfinfo);
370 *cfinfop = (uint32_t)(((customRC ? 0xFF : 0) << 24) | (customRC ? 0x800000 : 0x0) | ((uint32_t)typeID << 8) | 0x80);
371 #if __LP64__
372 memory->_rc = customRC ? 0xFFFFFFFFU : 0x0;
373 #endif
374 memory->_cfisa = 0;
375 if (NULL != cfClass->init) {
376 (cfClass->init)(memory);
377 }
378 }
379
380 void _CFRuntimeSetInstanceTypeID(CFTypeRef cf, CFTypeID newTypeID) {
381 if (__CFRuntimeClassTableSize <= newTypeID) HALT;
382 uint32_t *cfinfop = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
383 CFTypeID currTypeID = (*cfinfop >> 8) & 0x03FF; // mask up to 0x0FFF
384 CFRuntimeClass *newcfClass = __CFRuntimeClassTable[newTypeID];
385 Boolean newCustomRC = (newcfClass->version & _kCFRuntimeCustomRefCount);
386 CFRuntimeClass *currcfClass = __CFRuntimeClassTable[currTypeID];
387 Boolean currCustomRC = (currcfClass->version & _kCFRuntimeCustomRefCount);
388 if (currCustomRC || (0 != currTypeID && newCustomRC)) {
389 CFLog(kCFLogLevelError, CFSTR("*** Cannot change the CFTypeID of a %s to a %s due to custom ref counting"), currcfClass->className, newcfClass->className);
390 return;
391 }
392 // Going from current type ID of 0 to anything is allowed, but if
393 // the object has somehow already been retained and the transition
394 // is to a class doing custom ref counting, the ref count isn't
395 // transferred and there will probably be a crash later when the
396 // object is freed too early.
397 *cfinfop = (*cfinfop & 0xFFF000FFU) | ((uint32_t)newTypeID << 8);
398 }
399
400 CF_PRIVATE void _CFRuntimeSetInstanceTypeIDAndIsa(CFTypeRef cf, CFTypeID newTypeID) {
401 _CFRuntimeSetInstanceTypeID(cf, newTypeID);
402 }
403
404
405 enum {
406 __kCFObjectRetainedEvent = 12,
407 __kCFObjectReleasedEvent = 13
408 };
409
410 #if DEPLOYMENT_TARGET_MACOSX
411 #define NUM_EXTERN_TABLES 8
412 #define EXTERN_TABLE_IDX(O) (((uintptr_t)(O) >> 8) & 0x7)
413 #elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
414 #define NUM_EXTERN_TABLES 1
415 #define EXTERN_TABLE_IDX(O) 0
416 #else
417 #error
418 #endif
419
420 // we disguise pointers so that programs like 'leaks' forget about these references
421 #define DISGUISE(O) (~(uintptr_t)(O))
422
423 static struct {
424 CFSpinLock_t lock;
425 CFBasicHashRef table;
426 uint8_t padding[64 - sizeof(CFBasicHashRef) - sizeof(CFSpinLock_t)];
427 } __NSRetainCounters[NUM_EXTERN_TABLES];
428
429 CF_EXPORT uintptr_t __CFDoExternRefOperation(uintptr_t op, id obj) {
430 if (nil == obj) HALT;
431 uintptr_t idx = EXTERN_TABLE_IDX(obj);
432 uintptr_t disguised = DISGUISE(obj);
433 CFSpinLock_t *lock = &__NSRetainCounters[idx].lock;
434 CFBasicHashRef table = __NSRetainCounters[idx].table;
435 uintptr_t count;
436 switch (op) {
437 case 300: // increment
438 case 350: // increment, no event
439 __CFSpinLock(lock);
440 CFBasicHashAddValue(table, disguised, disguised);
441 __CFSpinUnlock(lock);
442 if (__CFOASafe && op != 350) __CFRecordAllocationEvent(__kCFObjectRetainedEvent, obj, 0, 0, NULL);
443 return (uintptr_t)obj;
444 case 400: // decrement
445 if (__CFOASafe) __CFRecordAllocationEvent(__kCFObjectReleasedEvent, obj, 0, 0, NULL);
446 case 450: // decrement, no event
447 __CFSpinLock(lock);
448 count = (uintptr_t)CFBasicHashRemoveValue(table, disguised);
449 __CFSpinUnlock(lock);
450 return 0 == count;
451 case 500:
452 __CFSpinLock(lock);
453 count = (uintptr_t)CFBasicHashGetCountOfKey(table, disguised);
454 __CFSpinUnlock(lock);
455 return count;
456 }
457 return 0;
458 }
459
460 CF_EXPORT CFTypeID CFNumberGetTypeID(void);
461
462 CF_INLINE CFTypeID __CFGenericTypeID_inline(const void *cf) {
463 // yes, 10 bits masked off, though 12 bits are there for the type field; __CFRuntimeClassTableSize is 1024
464 uint32_t *cfinfop = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
465 CFTypeID typeID = (*cfinfop >> 8) & 0x03FF; // mask up to 0x0FFF
466 return typeID;
467 }
468
469 CFTypeID __CFGenericTypeID(const void *cf) {
470 return __CFGenericTypeID_inline(cf);
471 }
472
473 CFTypeID CFTypeGetTypeID(void) {
474 return __kCFTypeTypeID;
475 }
476
477 CF_PRIVATE void __CFGenericValidateType_(CFTypeRef cf, CFTypeID type, const char *func) {
478 if (cf && CF_IS_OBJC(type, cf)) return;
479 CFAssert2((cf != NULL) && (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]) && (__kCFNotATypeTypeID != __CFGenericTypeID_inline(cf)) && (__kCFTypeTypeID != __CFGenericTypeID_inline(cf)), __kCFLogAssertion, "%s(): pointer %p is not a CF object", func, cf); \
480 CFAssert3(__CFGenericTypeID_inline(cf) == type, __kCFLogAssertion, "%s(): pointer %p is not a %s", func, cf, __CFRuntimeClassTable[type]->className); \
481 }
482
483 #define __CFGenericAssertIsCF(cf) \
484 CFAssert2(cf != NULL && (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]) && (__kCFNotATypeTypeID != __CFGenericTypeID_inline(cf)) && (__kCFTypeTypeID != __CFGenericTypeID_inline(cf)), __kCFLogAssertion, "%s(): pointer %p is not a CF object", __PRETTY_FUNCTION__, cf);
485
486
487 #define CFTYPE_IS_OBJC(obj) (false)
488 #define CFTYPE_OBJC_FUNCDISPATCH0(rettype, obj, sel) do {} while (0)
489 #define CFTYPE_OBJC_FUNCDISPATCH1(rettype, obj, sel, a1) do {} while (0)
490
491
492 CFTypeID CFGetTypeID(CFTypeRef cf) {
493 #if defined(DEBUG)
494 if (NULL == cf) { CRSetCrashLogMessage("*** CFGetTypeID() called with NULL ***"); HALT; }
495 #endif
496 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeID, cf, _cfTypeID);
497 __CFGenericAssertIsCF(cf);
498 return __CFGenericTypeID_inline(cf);
499 }
500
501 CFStringRef CFCopyTypeIDDescription(CFTypeID type) {
502 CFAssert2((NULL != __CFRuntimeClassTable[type]) && __kCFNotATypeTypeID != type && __kCFTypeTypeID != type, __kCFLogAssertion, "%s(): type %d is not a CF type ID", __PRETTY_FUNCTION__, type);
503 return CFStringCreateWithCString(kCFAllocatorSystemDefault, __CFRuntimeClassTable[type]->className, kCFStringEncodingASCII);
504 }
505
506 // Bit 31 (highest bit) in second word of cf instance indicates external ref count
507
508 static CFTypeRef _CFRetain(CFTypeRef cf, Boolean tryR);
509
510 CFTypeRef CFRetain(CFTypeRef cf) {
511 if (NULL == cf) { CRSetCrashLogMessage("*** CFRetain() called with NULL ***"); HALT; }
512 if (cf) __CFGenericAssertIsCF(cf);
513 return _CFRetain(cf, false);
514 }
515
516 CFTypeRef CFAutorelease(CFTypeRef __attribute__((cf_consumed)) cf) {
517 if (NULL == cf) { CRSetCrashLogMessage("*** CFAutorelease() called with NULL ***"); HALT; }
518 return cf;
519 }
520
521 static void _CFRelease(CFTypeRef cf);
522
523 void CFRelease(CFTypeRef cf) {
524 if (NULL == cf) { CRSetCrashLogMessage("*** CFRelease() called with NULL ***"); HALT; }
525 #if 0
526 void **addrs[2] = {&&start, &&end};
527 start:;
528 if (addrs[0] <= __builtin_return_address(0) && __builtin_return_address(0) <= addrs[1]) {
529 CFLog(3, CFSTR("*** WARNING: Recursion in CFRelease(%p) : %p '%s' : 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx 0x%08lx"), cf, object_getClass(cf), object_getClassName(cf), ((uintptr_t *)cf)[0], ((uintptr_t *)cf)[1], ((uintptr_t *)cf)[2], ((uintptr_t *)cf)[3], ((uintptr_t *)cf)[4], ((uintptr_t *)cf)[5]);
530 HALT;
531 }
532 #endif
533 if (cf) __CFGenericAssertIsCF(cf);
534 _CFRelease(cf);
535 #if 0
536 end:;
537 #endif
538 }
539
540
541 CF_PRIVATE void __CFAllocatorDeallocate(CFTypeRef cf);
542
543 CF_PRIVATE const void *__CFStringCollectionCopy(CFAllocatorRef allocator, const void *ptr) {
544 if (NULL == ptr) { CRSetCrashLogMessage("*** __CFStringCollectionCopy() called with NULL ***"); HALT; }
545 CFStringRef theString = (CFStringRef)ptr;
546 CFStringRef result = CFStringCreateCopy((allocator), theString);
547 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
548 result = (CFStringRef)CFMakeCollectable(result);
549 }
550 return (const void *)result;
551 }
552
553 extern void CFCollection_non_gc_storage_error(void);
554
555 CF_PRIVATE const void *__CFTypeCollectionRetain(CFAllocatorRef allocator, const void *ptr) {
556 if (NULL == ptr) { CRSetCrashLogMessage("*** __CFTypeCollectionRetain() called with NULL; likely a collection has been corrupted ***"); HALT; }
557 CFTypeRef cf = (CFTypeRef)ptr;
558 // only collections allocated in the GC zone can opt-out of reference counting.
559 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
560 if (CFTYPE_IS_OBJC(cf)) return cf; // do nothing for OBJC objects.
561 if (auto_zone_is_valid_pointer(objc_collectableZone(), ptr)) {
562 CFRuntimeClass *cfClass = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)];
563 if (cfClass->version & _kCFRuntimeResourcefulObject) {
564 // GC: If this a CF object in the GC heap that is marked resourceful, then
565 // it must be retained keep it alive in a CF collection.
566 CFRetain(cf);
567 }
568 else
569 ; // don't retain normal CF objects
570 return cf;
571 } else {
572 // support constant CFTypeRef objects.
573 #if __LP64__
574 uint32_t lowBits = ((CFRuntimeBase *)cf)->_rc;
575 #else
576 uint32_t lowBits = ((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS];
577 #endif
578 if (lowBits == 0) return cf;
579 // complain about non-GC objects in GC containers.
580 CFLog(kCFLogLevelWarning, CFSTR("storing a non-GC object %p in a GC collection, break on CFCollection_non_gc_storage_error to debug."), cf);
581 CFCollection_non_gc_storage_error();
582 // XXX should halt, except Patrick is using this somewhere.
583 // HALT;
584 }
585 }
586 return CFRetain(cf);
587 }
588
589
590 CF_PRIVATE void __CFTypeCollectionRelease(CFAllocatorRef allocator, const void *ptr) {
591 if (NULL == ptr) { CRSetCrashLogMessage("*** __CFTypeCollectionRelease() called with NULL; likely a collection has been corrupted ***"); HALT; }
592 CFTypeRef cf = (CFTypeRef)ptr;
593 // only collections allocated in the GC zone can opt-out of reference counting.
594 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
595 if (CFTYPE_IS_OBJC(cf)) return; // do nothing for OBJC objects.
596 if (auto_zone_is_valid_pointer(objc_collectableZone(), cf)) {
597 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
598 // GC: If this a CF object in the GC heap that is marked uncollectable, then
599 // must balance the retain done in __CFTypeCollectionRetain().
600 CFRuntimeClass *cfClass = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)];
601 if (cfClass->version & _kCFRuntimeResourcefulObject) {
602 // reclaim is called by _CFRelease(), which must be called to keep the
603 // CF and GC retain counts in sync.
604 CFRelease(cf);
605 } else {
606 // avoid releasing normal CF objects. Like other collections, for example
607 }
608 return;
609 #endif
610 } else {
611 // support constant CFTypeRef objects.
612 #if __LP64__
613 uint32_t lowBits = ((CFRuntimeBase *)cf)->_rc;
614 #else
615 uint32_t lowBits = ((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS];
616 #endif
617 if (lowBits == 0) return;
618 }
619 }
620 CFRelease(cf);
621 }
622
623 #if !__LP64__
624 static CFSpinLock_t __CFRuntimeExternRefCountTableLock = CFSpinLockInit;
625 #endif
626
627 static uint64_t __CFGetFullRetainCount(CFTypeRef cf) {
628 if (NULL == cf) { CRSetCrashLogMessage("*** __CFGetFullRetainCount() called with NULL ***"); HALT; }
629 #if __LP64__
630 uint32_t lowBits = ((CFRuntimeBase *)cf)->_rc;
631 if (0 == lowBits) {
632 return (uint64_t)0x0fffffffffffffffULL;
633 }
634 return lowBits;
635 #else
636 uint32_t lowBits = ((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS];
637 if (0 == lowBits) {
638 return (uint64_t)0x0fffffffffffffffULL;
639 }
640 uint64_t highBits = 0;
641 if ((lowBits & 0x80) != 0) {
642 highBits = __CFDoExternRefOperation(500, (id)cf);
643 }
644 uint64_t compositeRC = (lowBits & 0x7f) + (highBits << 6);
645 return compositeRC;
646 #endif
647 }
648
649 CFIndex CFGetRetainCount(CFTypeRef cf) {
650 if (NULL == cf) { CRSetCrashLogMessage("*** CFGetRetainCount() called with NULL ***"); HALT; }
651 uint32_t cfinfo = *(uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
652 if (cfinfo & 0x800000) { // custom ref counting for object
653 CFTypeID typeID = (cfinfo >> 8) & 0x03FF; // mask up to 0x0FFF
654 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
655 uint32_t (*refcount)(intptr_t, CFTypeRef) = cfClass->refcount;
656 if (!refcount || !(cfClass->version & _kCFRuntimeCustomRefCount) || (((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS] != 0xFF)) {
657 HALT; // bogus object
658 }
659 #if __LP64__
660 if (((CFRuntimeBase *)cf)->_rc != 0xFFFFFFFFU) {
661 HALT; // bogus object
662 }
663 #endif
664 uint32_t rc = refcount(0, cf);
665 #if __LP64__
666 return (CFIndex)rc;
667 #else
668 return (rc < LONG_MAX) ? (CFIndex)rc : (CFIndex)LONG_MAX;
669 #endif
670 }
671 uint64_t rc = __CFGetFullRetainCount(cf);
672 return (rc < (uint64_t)LONG_MAX) ? (CFIndex)rc : (CFIndex)LONG_MAX;
673 }
674
675 CFTypeRef CFMakeCollectable(CFTypeRef cf) {
676 if (NULL == cf) return NULL;
677 return cf;
678 }
679
680 CFTypeRef CFMakeUncollectable(CFTypeRef cf) {
681 if (NULL == cf) return NULL;
682 if (CF_IS_COLLECTABLE(cf)) {
683 CFRetain(cf);
684 }
685 return cf;
686 }
687
688 Boolean CFEqual(CFTypeRef cf1, CFTypeRef cf2) {
689 if (NULL == cf1) { CRSetCrashLogMessage("*** CFEqual() called with NULL first argument ***"); HALT; }
690 if (NULL == cf2) { CRSetCrashLogMessage("*** CFEqual() called with NULL second argument ***"); HALT; }
691 if (cf1 == cf2) return true;
692 CFTYPE_OBJC_FUNCDISPATCH1(Boolean, cf1, isEqual:, cf2);
693 CFTYPE_OBJC_FUNCDISPATCH1(Boolean, cf2, isEqual:, cf1);
694 __CFGenericAssertIsCF(cf1);
695 __CFGenericAssertIsCF(cf2);
696 if (__CFGenericTypeID_inline(cf1) != __CFGenericTypeID_inline(cf2)) return false;
697 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal) {
698 return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal(cf1, cf2);
699 }
700 return false;
701 }
702
703 CFHashCode CFHash(CFTypeRef cf) {
704 if (NULL == cf) { CRSetCrashLogMessage("*** CFHash() called with NULL ***"); HALT; }
705 CFTYPE_OBJC_FUNCDISPATCH0(CFHashCode, cf, hash);
706 __CFGenericAssertIsCF(cf);
707 CFHashCode (*hash)(CFTypeRef cf) = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->hash;
708 if (NULL != hash) {
709 return hash(cf);
710 }
711 if (CF_IS_COLLECTABLE(cf)) return (CFHashCode)_object_getExternalHash((id)cf);
712 return (CFHashCode)cf;
713 }
714
715 // definition: produces a normally non-NULL debugging description of the object
716 CFStringRef CFCopyDescription(CFTypeRef cf) {
717 if (NULL == cf) return NULL;
718 // CFTYPE_OBJC_FUNCDISPATCH0(CFStringRef, cf, _copyDescription); // XXX returns 0 refcounted item under GC
719 __CFGenericAssertIsCF(cf);
720 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyDebugDesc) {
721 CFStringRef result = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyDebugDesc(cf);
722 if (NULL != result) return result;
723 }
724 return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%s %p [%p]>"), __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->className, cf, CFGetAllocator(cf));
725 }
726
727 // Definition: if type produces a formatting description, return that string, otherwise NULL
728 CF_PRIVATE CFStringRef __CFCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
729 if (NULL == cf) return NULL;
730 __CFGenericAssertIsCF(cf);
731 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyFormattingDesc) {
732 return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyFormattingDesc(cf, formatOptions);
733 }
734 return NULL;
735 }
736
737 extern CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef);
738
739 CFAllocatorRef CFGetAllocator(CFTypeRef cf) {
740 if (NULL == cf) return kCFAllocatorSystemDefault;
741 if (__kCFAllocatorTypeID_CONST == __CFGenericTypeID_inline(cf)) {
742 return __CFAllocatorGetAllocator(cf);
743 }
744 return __CFGetAllocator(cf);
745 }
746
747 extern void __CFNullInitialize(void);
748 extern void __CFAllocatorInitialize(void);
749 extern void __CFStringInitialize(void);
750 extern void __CFArrayInitialize(void);
751 extern void __CFBooleanInitialize(void);
752 extern void __CFCharacterSetInitialize(void);
753 extern void __CFDataInitialize(void);
754 extern void __CFNumberInitialize(void);
755 extern void __CFStorageInitialize(void);
756 extern void __CFErrorInitialize(void);
757 extern void __CFTreeInitialize(void);
758 extern void __CFURLInitialize(void);
759 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
760 extern void __CFMachPortInitialize(void);
761 #endif
762 extern void __CFMessagePortInitialize(void);
763 extern void __CFRunLoopInitialize(void);
764 extern void __CFRunLoopObserverInitialize(void);
765 extern void __CFRunLoopSourceInitialize(void);
766 extern void __CFRunLoopTimerInitialize(void);
767 extern void __CFPFactoryInitialize(void);
768 extern void __CFBundleInitialize(void);
769 extern void __CFPlugInInitialize(void);
770 extern void __CFPlugInInstanceInitialize(void);
771 extern void __CFUUIDInitialize(void);
772 extern void __CFBinaryHeapInitialize(void);
773 extern void __CFBitVectorInitialize(void);
774 CF_PRIVATE void __CFDateInitialize(void);
775 #if DEPLOYMENT_TARGET_LINUX
776 CF_PRIVATE void __CFTSDLinuxInitialize();
777 #endif
778 #if DEPLOYMENT_TARGET_WINDOWS
779 // From CFPlatform.c
780 CF_PRIVATE void __CFTSDWindowsInitialize(void);
781 CF_PRIVATE void __CFTSDWindowsCleanup(void);
782 CF_PRIVATE void __CFFinalizeWindowsThreadData();
783 #endif
784 extern void __CFStreamInitialize(void);
785 extern void __CFCalendarInitialize();
786 extern void __CFTimeZoneInitialize();
787 #if DEPLOYMENT_TARGET_LINUX
788 extern void __CFCalendarInitialize();
789 extern void __CFTimeZoneInitialize();
790 #endif
791 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
792 extern void __CFXPreferencesInitialize(void);
793 #endif
794
795 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
796 CF_PRIVATE uint8_t __CF120290 = false;
797 CF_PRIVATE uint8_t __CF120291 = false;
798 CF_PRIVATE uint8_t __CF120293 = false;
799 CF_PRIVATE char * __crashreporter_info__ = NULL; // Keep this symbol, since it was exported and other things may be linking against it, like GraphicsServices.framework on iOS
800 asm(".desc ___crashreporter_info__, 0x10");
801
802 static void __01121__(void) {
803 __CF120291 = pthread_is_threaded_np() ? true : false;
804 }
805
806 static void __01123__(void) {
807 // Ideally, child-side atfork handlers should be async-cancel-safe, as fork()
808 // is async-cancel-safe and can be called from signal handlers. See also
809 // http://standards.ieee.org/reading/ieee/interp/1003-1c-95_int/pasc-1003.1c-37.html
810 // This is not a problem for CF.
811 if (__CF120290) {
812 __CF120293 = true;
813 #if DEPLOYMENT_TARGET_MACOSX
814 if (__CF120291) {
815 CRSetCrashLogMessage2("*** multi-threaded process forked ***");
816 } else {
817 CRSetCrashLogMessage2("*** single-threaded process forked ***");
818 }
819 #endif
820 }
821 }
822
823 #define EXEC_WARNING_STRING_1 "The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec().\n"
824 #define EXEC_WARNING_STRING_2 "Break on __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__() to debug.\n"
825
826 CF_PRIVATE void __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__(void) {
827 write(2, EXEC_WARNING_STRING_1, sizeof(EXEC_WARNING_STRING_1) - 1);
828 write(2, EXEC_WARNING_STRING_2, sizeof(EXEC_WARNING_STRING_2) - 1);
829 // HALT;
830 }
831 #endif
832
833
834 CF_EXPORT const void *__CFArgStuff;
835 const void *__CFArgStuff = NULL;
836 CF_PRIVATE void *__CFAppleLanguages = NULL;
837
838 // do not cache CFFIXED_USER_HOME or HOME, there are situations where they can change
839
840 static struct {
841 const char *name;
842 const char *value;
843 } __CFEnv[] = {
844 {"PATH", NULL},
845 {"USER", NULL},
846 {"HOMEPATH", NULL},
847 {"HOMEDRIVE", NULL},
848 {"USERNAME", NULL},
849 {"TZFILE", NULL},
850 {"TZ", NULL},
851 {"NEXT_ROOT", NULL},
852 {"DYLD_IMAGE_SUFFIX", NULL},
853 {"CFProcessPath", NULL},
854 {"CFNETWORK_LIBRARY_PATH", NULL},
855 {"CFUUIDVersionNumber", NULL},
856 {"CFDebugNamedDataSharing", NULL},
857 {"CFPropertyListAllowImmutableCollections", NULL},
858 {"CFBundleUseDYLD", NULL},
859 {"CFBundleDisableStringsSharing", NULL},
860 {"CFCharacterSetCheckForExpandedSet", NULL},
861 {"__CF_DEBUG_EXPANDED_SET", NULL},
862 {"CFStringDisableROM", NULL},
863 {"CF_CHARSET_PATH", NULL},
864 {"__CF_USER_TEXT_ENCODING", NULL},
865 {"__CFPREFERENCES_AUTOSYNC_INTERVAL", NULL},
866 {"__CFPREFERENCES_LOG_FAILURES", NULL},
867 {"CFNumberDisableCache", NULL},
868 {"__CFPREFERENCES_AVOID_DAEMON", NULL},
869 {"APPLE_FRAMEWORKS_ROOT", NULL},
870 {NULL, NULL}, // the last one is for optional "COMMAND_MODE" "legacy", do not use this slot, insert before
871 };
872
873 CF_PRIVATE const char *__CFgetenv(const char *n) {
874 for (CFIndex idx = 0; idx < sizeof(__CFEnv) / sizeof(__CFEnv[0]); idx++) {
875 if (__CFEnv[idx].name && 0 == strcmp(n, __CFEnv[idx].name)) return __CFEnv[idx].value;
876 }
877 return getenv(n);
878 }
879
880 CF_PRIVATE Boolean __CFProcessIsRestricted() {
881 return issetugid();
882 }
883
884 #if DEPLOYMENT_TARGET_WINDOWS
885 #define kNilPthreadT { nil, nil }
886 #else
887 #define kNilPthreadT (pthread_t)0
888 #endif
889
890
891 #undef kCFUseCollectableAllocator
892 CF_EXPORT bool kCFUseCollectableAllocator;
893 bool kCFUseCollectableAllocator = false;
894
895 CF_PRIVATE Boolean __CFProphylacticAutofsAccess = false;
896 CF_PRIVATE Boolean __CFInitializing = 0;
897 CF_PRIVATE Boolean __CFInitialized = 0;
898
899 // move the next 2 lines down into the #if below, and make it static, after Foundation gets off this symbol on other platforms
900 CF_EXPORT pthread_t _CFMainPThread;
901 pthread_t _CFMainPThread = kNilPthreadT;
902 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_IPHONESIMULATOR
903
904 CF_EXPORT pthread_t _CF_pthread_main_thread_np(void);
905 pthread_t _CF_pthread_main_thread_np(void) {
906 return _CFMainPThread;
907 }
908 #define pthread_main_thread_np() _CF_pthread_main_thread_np()
909
910 #endif
911
912 #if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
913 static void __CFInitialize(void) __attribute__ ((constructor));
914 static
915 #endif
916 #if DEPLOYMENT_TARGET_WINDOWS
917 CF_EXPORT
918 #endif
919 void __CFInitialize(void) {
920
921 if (!__CFInitialized && !__CFInitializing) {
922 __CFInitializing = 1;
923
924 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_IPHONESIMULATOR
925 if (!pthread_main_np()) HALT; // CoreFoundation must be initialized on the main thread
926 #endif
927 // move this next line up into the #if above after Foundation gets off this symbol
928 _CFMainPThread = pthread_self();
929
930 #if DEPLOYMENT_TARGET_WINDOWS
931 // Must not call any CF functions
932 __CFTSDWindowsInitialize();
933 #elif DEPLOYMENT_TARGET_LINUX
934 __CFTSDLinuxInitialize();
935 #endif
936
937 __CFProphylacticAutofsAccess = true;
938
939 for (CFIndex idx = 0; idx < sizeof(__CFEnv) / sizeof(__CFEnv[0]); idx++) {
940 __CFEnv[idx].value = __CFEnv[idx].name ? getenv(__CFEnv[idx].name) : NULL;
941 }
942
943 #if !defined(kCFUseCollectableAllocator)
944 kCFUseCollectableAllocator = objc_collectingEnabled();
945 #endif
946 if (kCFUseCollectableAllocator) {
947 #if !defined(__CFObjCIsCollectable)
948 __CFObjCIsCollectable = (bool (*)(void *))objc_isAuto;
949 #endif
950 }
951 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
952 UInt32 s, r;
953 __CFStringGetUserDefaultEncoding(&s, &r); // force the potential setenv to occur early
954 pthread_atfork(__01121__, NULL, __01123__);
955 #endif
956
957
958 memset(__CFRuntimeClassTable, 0, sizeof(__CFRuntimeClassTable));
959 memset(__CFRuntimeObjCClassTable, 0, sizeof(__CFRuntimeObjCClassTable));
960
961
962 /* Here so that two runtime classes get indices 0, 1. */
963 __kCFNotATypeTypeID = _CFRuntimeRegisterClass(&__CFNotATypeClass);
964 __kCFTypeTypeID = _CFRuntimeRegisterClass(&__CFTypeClass);
965
966 /* Here so that __kCFAllocatorTypeID gets index 2. */
967 __CFAllocatorInitialize();
968
969 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
970 {
971 CFIndex idx, cnt;
972 char **args = *_NSGetArgv();
973 cnt = *_NSGetArgc();
974 for (idx = 1; idx < cnt - 1; idx++) {
975 if (NULL == args[idx]) continue;
976 if (0 == strcmp(args[idx], "-AppleLanguages") && args[idx + 1]) {
977 CFIndex length = strlen(args[idx + 1]);
978 __CFAppleLanguages = malloc(length + 1);
979 memmove(__CFAppleLanguages, args[idx + 1], length + 1);
980 break;
981 }
982 }
983 }
984 #endif
985
986
987 CFBasicHashGetTypeID();
988 CFBagGetTypeID();
989
990 for (CFIndex idx = 0; idx < NUM_EXTERN_TABLES; idx++) {
991 CFBasicHashCallbacks callbacks = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
992 __NSRetainCounters[idx].table = CFBasicHashCreate(kCFAllocatorSystemDefault, kCFBasicHashHasCounts | kCFBasicHashLinearHashing | kCFBasicHashAggressiveGrowth, &callbacks);
993 CFBasicHashSetCapacity(__NSRetainCounters[idx].table, 40);
994 __NSRetainCounters[idx].lock = CFSpinLockInit;
995 }
996
997 /*** _CFRuntimeCreateInstance() can finally be called generally after this line. ***/
998
999 __CFRuntimeClassTableCount = 7;
1000 __CFStringInitialize(); // CFString's TypeID must be 0x7, now and forever
1001
1002 __CFRuntimeClassTableCount = 16;
1003 __CFNullInitialize(); // See above for hard-coding of this position
1004 CFSetGetTypeID(); // See above for hard-coding of this position
1005 CFDictionaryGetTypeID(); // See above for hard-coding of this position
1006 __CFArrayInitialize(); // See above for hard-coding of this position
1007 __CFDataInitialize(); // See above for hard-coding of this position
1008 __CFBooleanInitialize(); // See above for hard-coding of this position
1009 __CFNumberInitialize(); // See above for hard-coding of this position
1010
1011 __CFBinaryHeapInitialize();
1012 __CFBitVectorInitialize();
1013 __CFCharacterSetInitialize();
1014 __CFStorageInitialize();
1015 __CFErrorInitialize();
1016 __CFTreeInitialize();
1017 __CFURLInitialize();
1018
1019 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
1020 __CFBundleInitialize();
1021 __CFPFactoryInitialize();
1022 #endif
1023 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1024 __CFPlugInInitialize();
1025 __CFPlugInInstanceInitialize();
1026 #endif
1027 __CFUUIDInitialize();
1028 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
1029 __CFMessagePortInitialize();
1030 #endif
1031 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1032 __CFMachPortInitialize();
1033 #endif
1034 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
1035 __CFStreamInitialize();
1036 #endif
1037 #if DEPLOYMENT_TARGET_WINDOWS
1038 __CFWindowsNamedPipeInitialize();
1039 #endif
1040
1041 __CFDateInitialize();
1042
1043 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
1044 __CFRunLoopInitialize();
1045 __CFRunLoopObserverInitialize();
1046 __CFRunLoopSourceInitialize();
1047 __CFRunLoopTimerInitialize();
1048 #endif
1049 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1050 __CFTimeZoneInitialize();
1051 __CFCalendarInitialize();
1052 #if DEPLOYMENT_TARGET_LINUX
1053 __CFTimeZoneInitialize();
1054 __CFCalendarInitialize();
1055 #endif
1056 #endif
1057
1058 {
1059 CFIndex idx, cnt = 0;
1060 char **args = NULL;
1061 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1062 args = *_NSGetArgv();
1063 cnt = *_NSGetArgc();
1064 #elif DEPLOYMENT_TARGET_WINDOWS
1065 wchar_t *commandLine = GetCommandLineW();
1066 // result is actually pointer to wchar_t *, make sure to account for that below
1067 args = (char **)CommandLineToArgvW(commandLine, (int *)&cnt);
1068 #endif
1069 CFIndex count;
1070 CFStringRef *list, buffer[256];
1071 list = (cnt <= 256) ? buffer : (CFStringRef *)malloc(cnt * sizeof(CFStringRef));
1072 for (idx = 0, count = 0; idx < cnt; idx++) {
1073 if (NULL == args[idx]) continue;
1074 #if DEPLOYMENT_TARGET_WINDOWS
1075 list[count] = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)args[idx], wcslen((wchar_t *)args[idx]));
1076 #else
1077 list[count] = CFStringCreateWithCString(kCFAllocatorSystemDefault, args[idx], kCFStringEncodingUTF8);
1078 if (NULL == list[count]) {
1079 list[count] = CFStringCreateWithCString(kCFAllocatorSystemDefault, args[idx], kCFStringEncodingISOLatin1);
1080 // We CANNOT use the string SystemEncoding here;
1081 // Do not argue: it is not initialized yet, but these
1082 // arguments MUST be initialized before it is.
1083 // We should just ignore the argument if the UTF-8
1084 // conversion fails, but out of charity we try once
1085 // more with ISO Latin1, a standard unix encoding.
1086 }
1087 #endif
1088 if (NULL != list[count]) count++;
1089 }
1090 __CFArgStuff = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)list, count, &kCFTypeArrayCallBacks);
1091 if (list != buffer) free(list);
1092 #if DEPLOYMENT_TARGET_WINDOWS
1093 LocalFree(args);
1094 #endif
1095 }
1096
1097 _CFProcessPath(); // cache this early
1098
1099 __CFOAInitialize();
1100
1101
1102 if (__CFRuntimeClassTableCount < 256) __CFRuntimeClassTableCount = 256;
1103
1104
1105 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
1106 const char *value = __CFgetenv("NSZombieEnabled");
1107 if (value && (*value == 'Y' || *value == 'y')) _CFEnableZombies();
1108 value = __CFgetenv("NSDeallocateZombies");
1109 if (value && (*value == 'Y' || *value == 'y')) __CFDeallocateZombies = 0xff;
1110 #endif
1111
1112 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED)
1113 CFLog(kCFLogLevelWarning, CFSTR("Assertions enabled"));
1114 #endif
1115
1116 __CFProphylacticAutofsAccess = false;
1117 __CFInitializing = 0;
1118 __CFInitialized = 1;
1119 }
1120 }
1121
1122
1123 #if DEPLOYMENT_TARGET_WINDOWS
1124
1125 CF_PRIVATE void __CFStringCleanup(void);
1126 CF_PRIVATE void __CFSocketCleanup(void);
1127 CF_PRIVATE void __CFUniCharCleanup(void);
1128 CF_PRIVATE void __CFStreamCleanup(void);
1129
1130 static CFBundleRef RegisterCoreFoundationBundle(void) {
1131 #ifdef _DEBUG
1132 // might be nice to get this from the project file at some point
1133 wchar_t *DLLFileName = (wchar_t *)L"CoreFoundation_debug.dll";
1134 #else
1135 wchar_t *DLLFileName = (wchar_t *)L"CoreFoundation.dll";
1136 #endif
1137 wchar_t path[MAX_PATH+1];
1138 path[0] = path[1] = 0;
1139 DWORD wResult;
1140 CFIndex idx;
1141 HMODULE ourModule = GetModuleHandleW(DLLFileName);
1142
1143 CFAssert(ourModule, __kCFLogAssertion, "GetModuleHandle failed");
1144
1145 wResult = GetModuleFileNameW(ourModule, path, MAX_PATH+1);
1146 CFAssert1(wResult > 0, __kCFLogAssertion, "GetModuleFileName failed: %d", GetLastError());
1147 CFAssert1(wResult < MAX_PATH+1, __kCFLogAssertion, "GetModuleFileName result truncated: %s", path);
1148
1149 // strip off last component, the DLL name
1150 for (idx = wResult - 1; idx; idx--) {
1151 if ('\\' == path[idx]) {
1152 path[idx] = '\0';
1153 break;
1154 }
1155 }
1156
1157 CFStringRef fsPath = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar*)path, idx);
1158 CFURLRef dllURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, fsPath, kCFURLWindowsPathStyle, TRUE);
1159 CFURLRef bundleURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, dllURL, CFSTR("CoreFoundation.resources"), TRUE);
1160 CFRelease(fsPath);
1161 CFRelease(dllURL);
1162
1163 // this registers us so subsequent calls to CFBundleGetBundleWithIdentifier will succeed
1164 CFBundleRef bundle = CFBundleCreate(kCFAllocatorSystemDefault, bundleURL);
1165 CFRelease(bundleURL);
1166
1167 return bundle;
1168 }
1169
1170
1171 #define DLL_PROCESS_ATTACH 1
1172 #define DLL_THREAD_ATTACH 2
1173 #define DLL_THREAD_DETACH 3
1174 #define DLL_PROCESS_DETACH 0
1175
1176 int DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID pReserved ) {
1177 static CFBundleRef cfBundle = NULL;
1178 if (dwReason == DLL_PROCESS_ATTACH) {
1179 __CFInitialize();
1180 cfBundle = RegisterCoreFoundationBundle();
1181 } else if (dwReason == DLL_PROCESS_DETACH && pReserved == 0) {
1182 // Only cleanup if we are being unloaded dynamically (pReserved == 0) <rdar://problem/7480873>
1183 __CFStreamCleanup();
1184 __CFSocketCleanup();
1185 __CFUniCharCleanup();
1186
1187 #if DEPLOYMENT_TARGET_WINDOWS
1188 // No CF functions should access TSD after this is called
1189 __CFTSDWindowsCleanup();
1190 #endif
1191
1192 // do these last
1193 if (cfBundle) CFRelease(cfBundle);
1194 __CFStringCleanup();
1195 } else if (dwReason == DLL_THREAD_DETACH) {
1196 __CFFinalizeWindowsThreadData();
1197 }
1198 return TRUE;
1199 }
1200
1201 #endif
1202
1203 #if __CF_BIG_ENDIAN__
1204 #define RC_INCREMENT (1ULL)
1205 #define RC_MASK (0xFFFFFFFFULL)
1206 #define RC_GET(V) ((V) & RC_MASK)
1207 #define RC_DEALLOCATING_BIT (0x400000ULL << 32)
1208 #else
1209 #define RC_INCREMENT (1ULL << 32)
1210 #define RC_MASK (0xFFFFFFFFULL << 32)
1211 #define RC_GET(V) (((V) & RC_MASK) >> 32)
1212 #define RC_DEALLOCATING_BIT (0x400000ULL)
1213 #endif
1214
1215 #if !DEPLOYMENT_TARGET_WINDOWS && __LP64__
1216 static bool (*CAS64)(int64_t, int64_t, volatile int64_t *) = OSAtomicCompareAndSwap64Barrier;
1217 #else
1218 static bool (*CAS32)(int32_t, int32_t, volatile int32_t *) = OSAtomicCompareAndSwap32Barrier;
1219 #endif
1220
1221 // For "tryR==true", a return of NULL means "failed".
1222 static CFTypeRef _CFRetain(CFTypeRef cf, Boolean tryR) {
1223 uint32_t cfinfo = *(uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1224 if (cfinfo & 0x800000) { // custom ref counting for object
1225 if (tryR) return NULL;
1226 CFTypeID typeID = (cfinfo >> 8) & 0x03FF; // mask up to 0x0FFF
1227 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
1228 uint32_t (*refcount)(intptr_t, CFTypeRef) = cfClass->refcount;
1229 if (!refcount || !(cfClass->version & _kCFRuntimeCustomRefCount) || (((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS] != 0xFF)) {
1230 HALT; // bogus object
1231 }
1232 #if __LP64__
1233 if (((CFRuntimeBase *)cf)->_rc != 0xFFFFFFFFU) {
1234 HALT; // bogus object
1235 }
1236 #endif
1237 refcount(+1, cf);
1238 return cf;
1239 }
1240
1241 Boolean didAuto = false;
1242 #if __LP64__
1243 if (0 == ((CFRuntimeBase *)cf)->_rc && !CF_IS_COLLECTABLE(cf)) return cf; // Constant CFTypeRef
1244 #if !DEPLOYMENT_TARGET_WINDOWS
1245 uint64_t allBits;
1246 do {
1247 allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1248 if (tryR && (allBits & RC_DEALLOCATING_BIT)) return NULL;
1249 } while (!CAS64(allBits, allBits + RC_INCREMENT, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo));
1250 // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1251 if (RC_GET(allBits) == 0 && CF_IS_COLLECTABLE(cf)) {
1252 auto_zone_retain(objc_collectableZone(), (void*)cf);
1253 didAuto = true;
1254 }
1255 #else
1256 uint32_t lowBits;
1257 do {
1258 lowBits = ((CFRuntimeBase *)cf)->_rc;
1259 } while (!CAS32(lowBits, lowBits + 1, (int32_t *)&((CFRuntimeBase *)cf)->_rc));
1260 // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1261 if (lowBits == 0 && CF_IS_COLLECTABLE(cf)) {
1262 auto_zone_retain(objc_collectableZone(), (void*)cf);
1263 didAuto = true;
1264 }
1265 #endif
1266 #else
1267 #define RC_START 24
1268 #define RC_END 31
1269 volatile uint32_t *infoLocation = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1270 CFIndex rcLowBits = __CFBitfieldGetValue(cfinfo, RC_END, RC_START);
1271 if (__builtin_expect(0 == rcLowBits, 0) && !CF_IS_COLLECTABLE(cf)) return cf; // Constant CFTypeRef
1272 bool success = 0;
1273 do {
1274 cfinfo = *infoLocation;
1275 #if !DEPLOYMENT_TARGET_WINDOWS
1276 // if already deallocating, don't allow new retain
1277 if (tryR && (cfinfo & 0x400000)) return NULL;
1278 #endif
1279 uint32_t prospectiveNewInfo = cfinfo; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1280 prospectiveNewInfo += (1 << RC_START);
1281 rcLowBits = __CFBitfieldGetValue(prospectiveNewInfo, RC_END, RC_START);
1282 if (__builtin_expect((rcLowBits & 0x7f) == 0, 0)) {
1283 /* Roll over another bit to the external ref count
1284 Real ref count = low 7 bits of info[CF_RC_BITS] + external ref count << 6
1285 Bit 8 of low bits indicates that external ref count is in use.
1286 External ref count is shifted by 6 rather than 7 so that we can set the low
1287 bits to to 1100 0000 rather than 1000 0000.
1288 This prevents needing to access the external ref count for successive retains and releases
1289 when the composite retain count is right around a multiple of 1 << 7.
1290 */
1291 prospectiveNewInfo = cfinfo;
1292 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, ((1 << 7) | (1 << 6)));
1293 __CFSpinLock(&__CFRuntimeExternRefCountTableLock);
1294 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1295 if (__builtin_expect(success, 1)) {
1296 __CFDoExternRefOperation(350, (id)cf);
1297 }
1298 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock);
1299 } else {
1300 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1301 // XXX_PCB: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1302 if (success && __CFBitfieldGetValue(cfinfo, RC_END, RC_START) == 0 && CF_IS_COLLECTABLE(cf)) {
1303 auto_zone_retain(objc_collectableZone(), (void*)cf);
1304 didAuto = true;
1305 }
1306 }
1307 } while (__builtin_expect(!success, 0));
1308 #endif
1309 if (!didAuto && __builtin_expect(__CFOASafe, 0)) {
1310 __CFRecordAllocationEvent(__kCFRetainEvent, (void *)cf, 0, CFGetRetainCount(cf), NULL);
1311 }
1312 return cf;
1313 }
1314
1315 // Never called under GC, only called via ARR weak subsystem; a return of NULL is failure
1316 CFTypeRef _CFTryRetain(CFTypeRef cf) {
1317 if (NULL == cf) return NULL;
1318 #if OBJC_HAVE_TAGGED_POINTERS
1319 if (_objc_isTaggedPointer(cf)) return cf; // success
1320 #endif
1321 return _CFRetain(cf, true);
1322 }
1323
1324 Boolean _CFIsDeallocating(CFTypeRef cf) {
1325 if (NULL == cf) return false;
1326 #if OBJC_HAVE_TAGGED_POINTERS
1327 if (_objc_isTaggedPointer(cf)) return false;
1328 #endif
1329 uint32_t cfinfo = *(uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1330 if (cfinfo & 0x800000) { // custom ref counting for object
1331 return true; // lie for now; this weak references to these objects cannot be formed
1332 }
1333 return (cfinfo & 0x400000) ? true : false;
1334 }
1335
1336 static void _CFRelease(CFTypeRef cf) {
1337
1338 uint32_t cfinfo = *(uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1339 CFTypeID typeID = (cfinfo >> 8) & 0x03FF; // mask up to 0x0FFF
1340 if (cfinfo & 0x800000) { // custom ref counting for object
1341 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
1342 uint32_t (*refcount)(intptr_t, CFTypeRef) = cfClass->refcount;
1343 if (!refcount || !(cfClass->version & _kCFRuntimeCustomRefCount) || (((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS] != 0xFF)) {
1344 HALT; // bogus object
1345 }
1346 #if __LP64__
1347 if (((CFRuntimeBase *)cf)->_rc != 0xFFFFFFFFU) {
1348 HALT; // bogus object
1349 }
1350 #endif
1351 refcount(-1, cf);
1352 return;
1353 }
1354
1355 CFIndex start_rc = __builtin_expect(__CFOASafe, 0) ? CFGetRetainCount(cf) : 0;
1356 Boolean isAllocator = (__kCFAllocatorTypeID_CONST == typeID);
1357 Boolean didAuto = false;
1358 #if __LP64__
1359 #if !DEPLOYMENT_TARGET_WINDOWS
1360 uint32_t lowBits;
1361 uint64_t allBits;
1362 again:;
1363 do {
1364 allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1365 lowBits = RC_GET(allBits);
1366 if (0 == lowBits) {
1367 if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf);
1368 return; // Constant CFTypeRef
1369 }
1370 if (1 == lowBits) {
1371 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
1372 if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) {
1373 cfClass->reclaim(cf);
1374 }
1375 if (!CF_IS_COLLECTABLE(cf)) {
1376 uint64_t newAllBits = allBits | RC_DEALLOCATING_BIT;
1377 if (!CAS64(allBits, newAllBits, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo)) {
1378 goto again;
1379 }
1380 allBits = newAllBits;
1381 void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize;
1382 if (NULL != func) {
1383 func(cf);
1384 }
1385 allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1386 lowBits = RC_GET(allBits);
1387 if (isAllocator || ((1 == lowBits) && CAS64(allBits, allBits - RC_INCREMENT, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo))) {
1388 goto really_free;
1389 }
1390 Boolean success = false;
1391 do { // drop the deallocating bit; racey, but this resurrection stuff isn't thread-safe anyway
1392 allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1393 uint64_t newAllBits = allBits & ~RC_DEALLOCATING_BIT;
1394 success = CAS64(allBits, newAllBits, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo);
1395 } while (!success);
1396 goto again; // still need to have the effect of a CFRelease
1397 }
1398 }
1399 } while (!CAS64(allBits, allBits - RC_INCREMENT, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo));
1400 if (lowBits == 1 && CF_IS_COLLECTABLE(cf)) {
1401 // GC: release the collector's hold over the object, which will call the finalize function later on.
1402 auto_zone_release(objc_collectableZone(), (void*)cf);
1403 didAuto = true;
1404 }
1405 #else
1406 uint32_t lowBits;
1407 do {
1408 lowBits = ((CFRuntimeBase *)cf)->_rc;
1409 if (0 == lowBits) {
1410 if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf);
1411 return; // Constant CFTypeRef
1412 }
1413 if (1 == lowBits) {
1414 // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION
1415 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
1416 if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) {
1417 cfClass->reclaim(cf);
1418 }
1419 if (!CF_IS_COLLECTABLE(cf)) {
1420 void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize;
1421 if (NULL != func) {
1422 func(cf);
1423 }
1424 if (isAllocator || CAS32(1, 0, (int32_t *)&((CFRuntimeBase *)cf)->_rc)) {
1425 goto really_free;
1426 }
1427 }
1428 }
1429 } while (!CAS32(lowBits, lowBits - 1, (int32_t *)&((CFRuntimeBase *)cf)->_rc));
1430 if (lowBits == 1 && CF_IS_COLLECTABLE(cf)) {
1431 // GC: release the collector's hold over the object, which will call the finalize function later on.
1432 auto_zone_release(objc_collectableZone(), (void*)cf);
1433 didAuto = true;
1434 }
1435 #endif
1436 #else
1437 #if !DEPLOYMENT_TARGET_WINDOWS
1438 again:;
1439 volatile uint32_t *infoLocation = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1440 CFIndex rcLowBits = __CFBitfieldGetValue(cfinfo, RC_END, RC_START);
1441 if (__builtin_expect(0 == rcLowBits, 0)) {
1442 if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf);
1443 return; // Constant CFTypeRef
1444 }
1445 bool success = 0;
1446 Boolean whack = false;
1447 do {
1448 cfinfo = *infoLocation;
1449 rcLowBits = __CFBitfieldGetValue(cfinfo, RC_END, RC_START);
1450 if (__builtin_expect(1 == rcLowBits, 0)) {
1451 // we think cf should be deallocated
1452 uint32_t prospectiveNewInfo = cfinfo | (0x400000);
1453 if (CF_IS_COLLECTABLE(cf)) {
1454 prospectiveNewInfo -= (1 << RC_START);
1455 }
1456 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1457 if (success) whack = true;
1458 } else {
1459 // not yet junk
1460 uint32_t prospectiveNewInfo = cfinfo; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1461 if (__builtin_expect((1 << 7) == rcLowBits, 0)) {
1462 // Time to remove a bit from the external ref count
1463 __CFSpinLock(&__CFRuntimeExternRefCountTableLock);
1464 CFIndex rcHighBitsCnt = __CFDoExternRefOperation(500, (id)cf);
1465 if (1 == rcHighBitsCnt) {
1466 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, (1 << 6) - 1);
1467 } else {
1468 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, ((1 << 6) | (1 << 7)) - 1);
1469 }
1470 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1471 if (__builtin_expect(success, 1)) {
1472 __CFDoExternRefOperation(450, (id)cf);
1473 }
1474 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock);
1475 } else {
1476 prospectiveNewInfo -= (1 << RC_START);
1477 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1478 }
1479 }
1480 } while (__builtin_expect(!success, 0));
1481
1482 if (whack) {
1483 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
1484 if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) {
1485 cfClass->reclaim(cf);
1486 }
1487 if (CF_IS_COLLECTABLE(cf)) {
1488 // GC: release the collector's hold over the object, which will call the finalize function later on.
1489 auto_zone_release(objc_collectableZone(), (void*)cf);
1490 didAuto = true;
1491 } else {
1492 if (isAllocator) {
1493 goto really_free;
1494 } else {
1495 void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize;
1496 if (NULL != func) {
1497 func(cf);
1498 }
1499 rcLowBits = __CFBitfieldGetValue(*infoLocation, RC_END, RC_START);
1500 if (1 == rcLowBits) {
1501 goto really_free;
1502 }
1503 do { // drop the deallocating bit; racey, but this resurrection stuff isn't thread-safe anyway
1504 cfinfo = *infoLocation;
1505 uint32_t prospectiveNewInfo = (cfinfo & ~(0x400000));
1506 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1507 } while (!success);
1508 goto again;
1509 }
1510 }
1511 }
1512 #else
1513 volatile uint32_t *infoLocation = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1514 CFIndex rcLowBits = __CFBitfieldGetValue(*infoLocation, RC_END, RC_START);
1515 if (__builtin_expect(0 == rcLowBits, 0)) {
1516 if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf);
1517 return; // Constant CFTypeRef
1518 }
1519 bool success = 0;
1520 do {
1521 uint32_t initialCheckInfo = *infoLocation;
1522 rcLowBits = __CFBitfieldGetValue(initialCheckInfo, RC_END, RC_START);
1523 if (__builtin_expect(1 == rcLowBits, 0)) {
1524 // we think cf should be deallocated
1525 // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION
1526 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
1527 if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) {
1528 cfClass->reclaim(cf);
1529 }
1530 if (CF_IS_COLLECTABLE(cf)) {
1531 uint32_t prospectiveNewInfo = initialCheckInfo - (1 << RC_START);
1532 success = CAS32(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1533 // GC: release the collector's hold over the object, which will call the finalize function later on.
1534 if (success) {
1535 auto_zone_release(objc_collectableZone(), (void*)cf);
1536 didAuto = true;
1537 }
1538 } else {
1539 if (isAllocator) {
1540 goto really_free;
1541 } else {
1542 void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize;
1543 if (NULL != func) {
1544 func(cf);
1545 }
1546 // We recheck rcLowBits to see if the object has been retained again during
1547 // the finalization process. This allows for the finalizer to resurrect,
1548 // but the main point is to allow finalizers to be able to manage the
1549 // removal of objects from uniquing caches, which may race with other threads
1550 // which are allocating (looking up and finding) objects from those caches,
1551 // which (that thread) would be the thing doing the extra retain in that case.
1552 rcLowBits = __CFBitfieldGetValue(*infoLocation, RC_END, RC_START);
1553 success = (1 == rcLowBits);
1554 if (__builtin_expect(success, 1)) {
1555 goto really_free;
1556 }
1557 }
1558 }
1559 } else {
1560 // not yet junk
1561 uint32_t prospectiveNewInfo = initialCheckInfo; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1562 if (__builtin_expect((1 << 7) == rcLowBits, 0)) {
1563 // Time to remove a bit from the external ref count
1564 __CFSpinLock(&__CFRuntimeExternRefCountTableLock);
1565 CFIndex rcHighBitsCnt = __CFDoExternRefOperation(500, (id)cf);
1566 if (1 == rcHighBitsCnt) {
1567 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, (1 << 6) - 1);
1568 } else {
1569 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, ((1 << 6) | (1 << 7)) - 1);
1570 }
1571 success = CAS32(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1572 if (__builtin_expect(success, 1)) {
1573 __CFDoExternRefOperation(450, (id)cf);
1574 }
1575 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock);
1576 } else {
1577 prospectiveNewInfo -= (1 << RC_START);
1578 success = CAS32(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1579 }
1580 }
1581 } while (__builtin_expect(!success, 0));
1582 #endif
1583 #endif
1584 if (!didAuto && __builtin_expect(__CFOASafe, 0)) {
1585 __CFRecordAllocationEvent(__kCFReleaseEvent, (void *)cf, 0, start_rc - 1, NULL);
1586 }
1587 return;
1588
1589 really_free:;
1590 if (!didAuto && __builtin_expect(__CFOASafe, 0)) {
1591 // do not use CFGetRetainCount() because cf has been freed if it was an allocator
1592 __CFRecordAllocationEvent(__kCFReleaseEvent, (void *)cf, 0, 0, NULL);
1593 }
1594 // cannot zombify allocators, which get deallocated by __CFAllocatorDeallocate (finalize)
1595 if (isAllocator) {
1596 __CFAllocatorDeallocate((void *)cf);
1597 } else {
1598 CFAllocatorRef allocator = kCFAllocatorSystemDefault;
1599 Boolean usesSystemDefaultAllocator = true;
1600
1601 if (!__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 7, 7)) {
1602 allocator = CFGetAllocator(cf);
1603 usesSystemDefaultAllocator = _CFAllocatorIsSystemDefault(allocator);
1604 }
1605
1606 {
1607 CFAllocatorDeallocate(allocator, (uint8_t *)cf - (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef)));
1608 }
1609
1610 if (kCFAllocatorSystemDefault != allocator) {
1611 CFRelease(allocator);
1612 }
1613 }
1614 }
1615
1616 #undef __kCFAllocatorTypeID_CONST
1617 #undef __CFGenericAssertIsCF
1618
1619