]> git.saurik.com Git - apple/cf.git/blob - CFRuntime.c
CF-744.12.tar.gz
[apple/cf.git] / CFRuntime.c
1 /*
2 * Copyright (c) 2012 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-2012, 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 __private_extern__ 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 __private_extern__ CFRuntimeClass * __CFRuntimeClassTable[__CFRuntimeClassTableSize] = {0};
203 __private_extern__ int32_t __CFRuntimeClassTableCount = 0;
204
205 __private_extern__ 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 __private_extern__ uint8_t __CFZombieEnabled = 0;
270 __private_extern__ 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 && (kCFAllocatorSystemDefaultGCRefZero == allocator || kCFAllocatorDefaultGCRefZero == allocator)) {
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 = _CFConvertAllocatorToNonGCRefZeroEquivalent(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 memory->_cfisa = __CFISAForTypeID(typeID);
334 uint32_t rc = 0;
335 #if __LP64__
336 if (!kCFUseCollectableAllocator || (kCFAllocatorSystemDefaultGCRefZero != allocator && kCFAllocatorDefaultGCRefZero != allocator)) {
337 memory->_rc = 1;
338 }
339 if (customRC) {
340 memory->_rc = 0xFFFFFFFFU;
341 rc = 0xFF;
342 }
343 #else
344 if (!kCFUseCollectableAllocator || (kCFAllocatorSystemDefaultGCRefZero != allocator && kCFAllocatorDefaultGCRefZero != allocator)) {
345 rc = 1;
346 }
347 if (customRC) {
348 rc = 0xFF;
349 }
350 #endif
351 uint32_t *cfinfop = (uint32_t *)&(memory->_cfinfo);
352 *cfinfop = (uint32_t)((rc << 24) | (customRC ? 0x800000 : 0x0) | ((uint32_t)typeID << 8) | (usesSystemDefaultAllocator ? 0x80 : 0x00));
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 memory->_cfisa = __CFISAForTypeID(typeID);
370 uint32_t *cfinfop = (uint32_t *)&(memory->_cfinfo);
371 *cfinfop = (uint32_t)(((customRC ? 0xFF : 0) << 24) | (customRC ? 0x800000 : 0x0) | ((uint32_t)typeID << 8) | 0x80);
372 #if __LP64__
373 memory->_rc = customRC ? 0xFFFFFFFFU : 0x0;
374 #endif
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
401 enum {
402 __kCFObjectRetainedEvent = 12,
403 __kCFObjectReleasedEvent = 13
404 };
405
406 #if DEPLOYMENT_TARGET_MACOSX
407 #define NUM_EXTERN_TABLES 8
408 #define EXTERN_TABLE_IDX(O) (((uintptr_t)(O) >> 8) & 0x7)
409 #elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
410 #define NUM_EXTERN_TABLES 1
411 #define EXTERN_TABLE_IDX(O) 0
412 #else
413 #error
414 #endif
415
416 // we disguise pointers so that programs like 'leaks' forget about these references
417 #define DISGUISE(O) (~(uintptr_t)(O))
418
419 static struct {
420 CFSpinLock_t lock;
421 CFBasicHashRef table;
422 uint8_t padding[64 - sizeof(CFBasicHashRef) - sizeof(CFSpinLock_t)];
423 } __NSRetainCounters[NUM_EXTERN_TABLES];
424
425 CF_EXPORT uintptr_t __CFDoExternRefOperation(uintptr_t op, id obj) {
426 if (nil == obj) HALT;
427 uintptr_t idx = EXTERN_TABLE_IDX(obj);
428 uintptr_t disguised = DISGUISE(obj);
429 CFSpinLock_t *lock = &__NSRetainCounters[idx].lock;
430 CFBasicHashRef table = __NSRetainCounters[idx].table;
431 uintptr_t count;
432 switch (op) {
433 case 300: // increment
434 case 350: // increment, no event
435 __CFSpinLock(lock);
436 CFBasicHashAddValue(table, disguised, disguised);
437 __CFSpinUnlock(lock);
438 if (__CFOASafe && op != 350) __CFRecordAllocationEvent(__kCFObjectRetainedEvent, obj, 0, 0, NULL);
439 return (uintptr_t)obj;
440 case 400: // decrement
441 if (__CFOASafe) __CFRecordAllocationEvent(__kCFObjectReleasedEvent, obj, 0, 0, NULL);
442 case 450: // decrement, no event
443 __CFSpinLock(lock);
444 count = (uintptr_t)CFBasicHashRemoveValue(table, disguised);
445 __CFSpinUnlock(lock);
446 return 0 == count;
447 case 500:
448 __CFSpinLock(lock);
449 count = (uintptr_t)CFBasicHashGetCountOfKey(table, disguised);
450 __CFSpinUnlock(lock);
451 return count;
452 }
453 return 0;
454 }
455
456 static void __CFExternRefNullFreeCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) {
457 }
458
459 static uintptr_t __CFExternRefNullRetainValue(CFConstBasicHashRef ht, uintptr_t stack_value) {
460 return stack_value;
461 }
462
463 static uintptr_t __CFExternRefNullRetainKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
464 return stack_key;
465 }
466
467 static void __CFExternRefNullReleaseValue(CFConstBasicHashRef ht, uintptr_t stack_value) {
468 }
469
470 static void __CFExternRefNullReleaseKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
471 }
472
473 static Boolean __CFExternRefNullEquateValues(CFConstBasicHashRef ht, uintptr_t coll_value1, uintptr_t stack_value2) {
474 return coll_value1 == stack_value2;
475 }
476
477 static Boolean __CFExternRefNullEquateKeys(CFConstBasicHashRef ht, uintptr_t coll_key1, uintptr_t stack_key2) {
478 return coll_key1 == stack_key2;
479 }
480
481 static uintptr_t __CFExternRefNullHashKey(CFConstBasicHashRef ht, uintptr_t stack_key) {
482 return stack_key;
483 }
484
485 static uintptr_t __CFExternRefNullGetIndirectKey(CFConstBasicHashRef ht, uintptr_t coll_value) {
486 return 0;
487 }
488
489 static CFStringRef __CFExternRefNullCopyValueDescription(CFConstBasicHashRef ht, uintptr_t stack_value) {
490 return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)stack_value);
491 }
492
493 static CFStringRef __CFExternRefNullCopyKeyDescription(CFConstBasicHashRef ht, uintptr_t stack_key) {
494 return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)stack_key);
495 }
496
497 static CFBasicHashCallbacks *__CFExternRefNullCopyCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb);
498
499 static const CFBasicHashCallbacks CFExternRefCallbacks = {
500 __CFExternRefNullCopyCallbacks,
501 __CFExternRefNullFreeCallbacks,
502 __CFExternRefNullRetainValue,
503 __CFExternRefNullRetainKey,
504 __CFExternRefNullReleaseValue,
505 __CFExternRefNullReleaseKey,
506 __CFExternRefNullEquateValues,
507 __CFExternRefNullEquateKeys,
508 __CFExternRefNullHashKey,
509 __CFExternRefNullGetIndirectKey,
510 __CFExternRefNullCopyValueDescription,
511 __CFExternRefNullCopyKeyDescription
512 };
513
514 static CFBasicHashCallbacks *__CFExternRefNullCopyCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) {
515 return (CFBasicHashCallbacks *)&CFExternRefCallbacks;
516 }
517
518 CF_EXPORT CFTypeID CFNumberGetTypeID(void);
519
520 CF_INLINE CFTypeID __CFGenericTypeID_inline(const void *cf) {
521 // yes, 10 bits masked off, though 12 bits are there for the type field; __CFRuntimeClassTableSize is 1024
522 uint32_t *cfinfop = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
523 CFTypeID typeID = (*cfinfop >> 8) & 0x03FF; // mask up to 0x0FFF
524 return typeID;
525 }
526
527 CFTypeID __CFGenericTypeID(const void *cf) {
528 return __CFGenericTypeID_inline(cf);
529 }
530
531 CFTypeID CFTypeGetTypeID(void) {
532 return __kCFTypeTypeID;
533 }
534
535 __private_extern__ void __CFGenericValidateType_(CFTypeRef cf, CFTypeID type, const char *func) {
536 if (cf && CF_IS_OBJC(type, cf)) return;
537 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); \
538 CFAssert3(__CFGenericTypeID_inline(cf) == type, __kCFLogAssertion, "%s(): pointer %p is not a %s", func, cf, __CFRuntimeClassTable[type]->className); \
539 }
540
541 #define __CFGenericAssertIsCF(cf) \
542 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);
543
544
545 #define CFTYPE_IS_OBJC(obj) (false)
546 #define CFTYPE_OBJC_FUNCDISPATCH0(rettype, obj, sel) do {} while (0)
547 #define CFTYPE_OBJC_FUNCDISPATCH1(rettype, obj, sel, a1) do {} while (0)
548
549
550 CFTypeID CFGetTypeID(CFTypeRef cf) {
551 #if defined(DEBUG)
552 if (NULL == cf) { CRSetCrashLogMessage("*** CFGetTypeID() called with NULL ***"); HALT; }
553 #endif
554 CFTYPE_OBJC_FUNCDISPATCH0(CFTypeID, cf, _cfTypeID);
555 __CFGenericAssertIsCF(cf);
556 return __CFGenericTypeID_inline(cf);
557 }
558
559 CFStringRef CFCopyTypeIDDescription(CFTypeID type) {
560 CFAssert2((NULL != __CFRuntimeClassTable[type]) && __kCFNotATypeTypeID != type && __kCFTypeTypeID != type, __kCFLogAssertion, "%s(): type %d is not a CF type ID", __PRETTY_FUNCTION__, type);
561 return CFStringCreateWithCString(kCFAllocatorSystemDefault, __CFRuntimeClassTable[type]->className, kCFStringEncodingASCII);
562 }
563
564 // Bit 31 (highest bit) in second word of cf instance indicates external ref count
565
566 static CFTypeRef _CFRetain(CFTypeRef cf, Boolean tryR);
567
568 CFTypeRef CFRetain(CFTypeRef cf) {
569 if (NULL == cf) { CRSetCrashLogMessage("*** CFRetain() called with NULL ***"); HALT; }
570 if (cf) __CFGenericAssertIsCF(cf);
571 return _CFRetain(cf, false);
572 }
573
574 static void _CFRelease(CFTypeRef cf);
575
576 void CFRelease(CFTypeRef cf) {
577 if (NULL == cf) { CRSetCrashLogMessage("*** CFRelease() called with NULL ***"); HALT; }
578 #if 0
579 void **addrs[2] = {&&start, &&end};
580 start:;
581 if (addrs[0] <= __builtin_return_address(0) && __builtin_return_address(0) <= addrs[1]) {
582 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]);
583 HALT;
584 }
585 #endif
586 if (cf) __CFGenericAssertIsCF(cf);
587 _CFRelease(cf);
588 #if 0
589 end:;
590 #endif
591 }
592
593
594 __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf);
595
596 __private_extern__ const void *__CFStringCollectionCopy(CFAllocatorRef allocator, const void *ptr) {
597 if (NULL == ptr) { CRSetCrashLogMessage("*** __CFStringCollectionCopy() called with NULL ***"); HALT; }
598 CFStringRef theString = (CFStringRef)ptr;
599 CFStringRef result = CFStringCreateCopy(_CFConvertAllocatorToGCRefZeroEquivalent(allocator), theString);
600 return (const void *)result;
601 }
602
603 extern void CFCollection_non_gc_storage_error(void);
604
605 __private_extern__ const void *__CFTypeCollectionRetain(CFAllocatorRef allocator, const void *ptr) {
606 if (NULL == ptr) { CRSetCrashLogMessage("*** __CFTypeCollectionRetain() called with NULL; likely a collection has been corrupted ***"); HALT; }
607 CFTypeRef cf = (CFTypeRef)ptr;
608 // only collections allocated in the GC zone can opt-out of reference counting.
609 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
610 if (CFTYPE_IS_OBJC(cf)) return cf; // do nothing for OBJC objects.
611 if (auto_zone_is_valid_pointer(objc_collectableZone(), ptr)) {
612 CFRuntimeClass *cfClass = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)];
613 if (cfClass->version & _kCFRuntimeResourcefulObject) {
614 // GC: If this a CF object in the GC heap that is marked resourceful, then
615 // it must be retained keep it alive in a CF collection.
616 CFRetain(cf);
617 }
618 else
619 ; // don't retain normal CF objects
620 return cf;
621 } else {
622 // support constant CFTypeRef objects.
623 #if __LP64__
624 uint32_t lowBits = ((CFRuntimeBase *)cf)->_rc;
625 #else
626 uint32_t lowBits = ((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS];
627 #endif
628 if (lowBits == 0) return cf;
629 // complain about non-GC objects in GC containers.
630 CFLog(kCFLogLevelWarning, CFSTR("storing a non-GC object %p in a GC collection, break on CFCollection_non_gc_storage_error to debug."), cf);
631 CFCollection_non_gc_storage_error();
632 // XXX should halt, except Patrick is using this somewhere.
633 // HALT;
634 }
635 }
636 return CFRetain(cf);
637 }
638
639
640 __private_extern__ void __CFTypeCollectionRelease(CFAllocatorRef allocator, const void *ptr) {
641 if (NULL == ptr) { CRSetCrashLogMessage("*** __CFTypeCollectionRelease() called with NULL; likely a collection has been corrupted ***"); HALT; }
642 CFTypeRef cf = (CFTypeRef)ptr;
643 // only collections allocated in the GC zone can opt-out of reference counting.
644 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
645 if (CFTYPE_IS_OBJC(cf)) return; // do nothing for OBJC objects.
646 if (auto_zone_is_valid_pointer(objc_collectableZone(), cf)) {
647 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
648 // GC: If this a CF object in the GC heap that is marked uncollectable, then
649 // must balance the retain done in __CFTypeCollectionRetain().
650 CFRuntimeClass *cfClass = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)];
651 if (cfClass->version & _kCFRuntimeResourcefulObject) {
652 // reclaim is called by _CFRelease(), which must be called to keep the
653 // CF and GC retain counts in sync.
654 CFRelease(cf);
655 } else {
656 // avoid releasing normal CF objects. Like other collections, for example
657 }
658 return;
659 #endif
660 } else {
661 // support constant CFTypeRef objects.
662 #if __LP64__
663 uint32_t lowBits = ((CFRuntimeBase *)cf)->_rc;
664 #else
665 uint32_t lowBits = ((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS];
666 #endif
667 if (lowBits == 0) return;
668 }
669 }
670 CFRelease(cf);
671 }
672
673 #if !__LP64__
674 static CFSpinLock_t __CFRuntimeExternRefCountTableLock = CFSpinLockInit;
675 #endif
676
677 static uint64_t __CFGetFullRetainCount(CFTypeRef cf) {
678 if (NULL == cf) { CRSetCrashLogMessage("*** __CFGetFullRetainCount() called with NULL ***"); HALT; }
679 #if __LP64__
680 uint32_t lowBits = ((CFRuntimeBase *)cf)->_rc;
681 if (0 == lowBits) {
682 return (uint64_t)0x0fffffffffffffffULL;
683 }
684 return lowBits;
685 #else
686 uint32_t lowBits = ((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS];
687 if (0 == lowBits) {
688 return (uint64_t)0x0fffffffffffffffULL;
689 }
690 uint64_t highBits = 0;
691 if ((lowBits & 0x80) != 0) {
692 highBits = __CFDoExternRefOperation(500, (id)cf);
693 }
694 uint64_t compositeRC = (lowBits & 0x7f) + (highBits << 6);
695 return compositeRC;
696 #endif
697 }
698
699 CFIndex CFGetRetainCount(CFTypeRef cf) {
700 if (NULL == cf) { CRSetCrashLogMessage("*** CFGetRetainCount() called with NULL ***"); HALT; }
701 uint32_t cfinfo = *(uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
702 if (cfinfo & 0x800000) { // custom ref counting for object
703 CFTypeID typeID = (cfinfo >> 8) & 0x03FF; // mask up to 0x0FFF
704 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
705 uint32_t (*refcount)(intptr_t, CFTypeRef) = cfClass->refcount;
706 if (!refcount || !(cfClass->version & _kCFRuntimeCustomRefCount) || (((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS] != 0xFF)) {
707 HALT; // bogus object
708 }
709 #if __LP64__
710 if (((CFRuntimeBase *)cf)->_rc != 0xFFFFFFFFU) {
711 HALT; // bogus object
712 }
713 #endif
714 uint32_t rc = refcount(0, cf);
715 #if __LP64__
716 return (CFIndex)rc;
717 #else
718 return (rc < LONG_MAX) ? (CFIndex)rc : (CFIndex)LONG_MAX;
719 #endif
720 }
721 uint64_t rc = __CFGetFullRetainCount(cf);
722 return (rc < (uint64_t)LONG_MAX) ? (CFIndex)rc : (CFIndex)LONG_MAX;
723 }
724
725 CFTypeRef CFMakeCollectable(CFTypeRef cf) {
726 if (NULL == cf) return NULL;
727 return cf;
728 }
729
730 CFTypeRef CFMakeUncollectable(CFTypeRef cf) {
731 if (NULL == cf) return NULL;
732 if (CF_IS_COLLECTABLE(cf)) {
733 CFRetain(cf);
734 }
735 return cf;
736 }
737
738 Boolean CFEqual(CFTypeRef cf1, CFTypeRef cf2) {
739 if (NULL == cf1) { CRSetCrashLogMessage("*** CFEqual() called with NULL first argument ***"); HALT; }
740 if (NULL == cf2) { CRSetCrashLogMessage("*** CFEqual() called with NULL second argument ***"); HALT; }
741 if (cf1 == cf2) return true;
742 CFTYPE_OBJC_FUNCDISPATCH1(Boolean, cf1, isEqual:, cf2);
743 CFTYPE_OBJC_FUNCDISPATCH1(Boolean, cf2, isEqual:, cf1);
744 __CFGenericAssertIsCF(cf1);
745 __CFGenericAssertIsCF(cf2);
746 if (__CFGenericTypeID_inline(cf1) != __CFGenericTypeID_inline(cf2)) return false;
747 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal) {
748 return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal(cf1, cf2);
749 }
750 return false;
751 }
752
753 CFHashCode CFHash(CFTypeRef cf) {
754 if (NULL == cf) { CRSetCrashLogMessage("*** CFHash() called with NULL ***"); HALT; }
755 CFTYPE_OBJC_FUNCDISPATCH0(CFHashCode, cf, hash);
756 __CFGenericAssertIsCF(cf);
757 CFHashCode (*hash)(CFTypeRef cf) = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->hash;
758 if (NULL != hash) {
759 return hash(cf);
760 }
761 if (CF_IS_COLLECTABLE(cf)) return (CFHashCode)_object_getExternalHash((id)cf);
762 return (CFHashCode)cf;
763 }
764
765 // definition: produces a normally non-NULL debugging description of the object
766 CFStringRef CFCopyDescription(CFTypeRef cf) {
767 if (NULL == cf) return NULL;
768 // CFTYPE_OBJC_FUNCDISPATCH0(CFStringRef, cf, _copyDescription); // XXX returns 0 refcounted item under GC
769 __CFGenericAssertIsCF(cf);
770 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyDebugDesc) {
771 CFStringRef result = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyDebugDesc(cf);
772 if (NULL != result) return result;
773 }
774 return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%s %p [%p]>"), __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->className, cf, CFGetAllocator(cf));
775 }
776
777 // Definition: if type produces a formatting description, return that string, otherwise NULL
778 __private_extern__ CFStringRef __CFCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
779 if (NULL == cf) return NULL;
780 __CFGenericAssertIsCF(cf);
781 if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyFormattingDesc) {
782 return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyFormattingDesc(cf, formatOptions);
783 }
784 return NULL;
785 }
786
787 extern CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef);
788
789 CFAllocatorRef CFGetAllocator(CFTypeRef cf) {
790 if (NULL == cf) return kCFAllocatorSystemDefault;
791 if (__kCFAllocatorTypeID_CONST == __CFGenericTypeID_inline(cf)) {
792 return __CFAllocatorGetAllocator(cf);
793 }
794 return __CFGetAllocator(cf);
795 }
796
797 extern void __CFNullInitialize(void);
798 extern void __CFAllocatorInitialize(void);
799 extern void __CFStringInitialize(void);
800 extern void __CFArrayInitialize(void);
801 extern void __CFBooleanInitialize(void);
802 extern void __CFCharacterSetInitialize(void);
803 extern void __CFDataInitialize(void);
804 extern void __CFNumberInitialize(void);
805 extern void __CFStorageInitialize(void);
806 extern void __CFErrorInitialize(void);
807 extern void __CFTreeInitialize(void);
808 extern void __CFURLInitialize(void);
809 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
810 extern void __CFMachPortInitialize(void);
811 #endif
812 extern void __CFMessagePortInitialize(void);
813 extern void __CFRunLoopInitialize(void);
814 extern void __CFRunLoopObserverInitialize(void);
815 extern void __CFRunLoopSourceInitialize(void);
816 extern void __CFRunLoopTimerInitialize(void);
817 extern void __CFPFactoryInitialize(void);
818 extern void __CFBundleInitialize(void);
819 extern void __CFPlugInInitialize(void);
820 extern void __CFPlugInInstanceInitialize(void);
821 extern void __CFUUIDInitialize(void);
822 extern void __CFBinaryHeapInitialize(void);
823 extern void __CFBitVectorInitialize(void);
824 #if DEPLOYMENT_TARGET_LINUX
825 __private_extern__ void __CFTSDLinuxInitialize();
826 #endif
827 #if DEPLOYMENT_TARGET_WINDOWS
828 // From CFPlatform.c
829 __private_extern__ void __CFTSDWindowsInitialize(void);
830 __private_extern__ void __CFTSDWindowsCleanup(void);
831 __private_extern__ void __CFFinalizeWindowsThreadData();
832 #endif
833 extern void __CFStreamInitialize(void);
834 extern void __CFCalendarInitialize();
835 extern void __CFTimeZoneInitialize();
836 #if DEPLOYMENT_TARGET_LINUX
837 extern void __CFCalendarInitialize();
838 extern void __CFTimeZoneInitialize();
839 #endif
840 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
841 extern void __CFXPreferencesInitialize(void);
842 #endif
843
844 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
845 __private_extern__ uint8_t __CF120290 = false;
846 __private_extern__ uint8_t __CF120291 = false;
847 __private_extern__ uint8_t __CF120293 = false;
848 __private_extern__ char * __crashreporter_info__ = NULL; // Keep this symbol, since it was exported and other things may be linking against it, like GraphicsServices.framework on iOS
849 asm(".desc ___crashreporter_info__, 0x10");
850
851 static void __01121__(void) {
852 __CF120291 = pthread_is_threaded_np() ? true : false;
853 }
854
855 static void __01123__(void) {
856 // Ideally, child-side atfork handlers should be async-cancel-safe, as fork()
857 // is async-cancel-safe and can be called from signal handlers. See also
858 // http://standards.ieee.org/reading/ieee/interp/1003-1c-95_int/pasc-1003.1c-37.html
859 // This is not a problem for CF.
860 if (__CF120290) {
861 __CF120293 = true;
862 #if DEPLOYMENT_TARGET_MACOSX
863 if (__CF120291) {
864 CRSetCrashLogMessage2("*** multi-threaded process forked ***");
865 } else {
866 CRSetCrashLogMessage2("*** single-threaded process forked ***");
867 }
868 #endif
869 }
870 }
871
872 #define EXEC_WARNING_STRING_1 "The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec().\n"
873 #define EXEC_WARNING_STRING_2 "Break on __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__() to debug.\n"
874
875 __private_extern__ void __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__(void) {
876 write(2, EXEC_WARNING_STRING_1, sizeof(EXEC_WARNING_STRING_1) - 1);
877 write(2, EXEC_WARNING_STRING_2, sizeof(EXEC_WARNING_STRING_2) - 1);
878 // HALT;
879 }
880 #endif
881
882
883 CF_EXPORT const void *__CFArgStuff;
884 const void *__CFArgStuff = NULL;
885 __private_extern__ void *__CFAppleLanguages = NULL;
886
887 // do not cache CFFIXED_USER_HOME or HOME, there are situations where they can change
888
889 static struct {
890 const char *name;
891 const char *value;
892 } __CFEnv[] = {
893 {"PATH", NULL},
894 {"USER", NULL},
895 {"HOMEPATH", NULL},
896 {"HOMEDRIVE", NULL},
897 {"USERNAME", NULL},
898 {"TZFILE", NULL},
899 {"TZ", NULL},
900 {"NEXT_ROOT", NULL},
901 {"DYLD_IMAGE_SUFFIX", NULL},
902 {"CFProcessPath", NULL},
903 {"CFNETWORK_LIBRARY_PATH", NULL},
904 {"CFUUIDVersionNumber", NULL},
905 {"CFDebugNamedDataSharing", NULL},
906 {"CFPropertyListAllowImmutableCollections", NULL},
907 {"CFBundleUseDYLD", NULL},
908 {"CFBundleDisableStringsSharing", NULL},
909 {"CFCharacterSetCheckForExpandedSet", NULL},
910 {"__CF_DEBUG_EXPANDED_SET", NULL},
911 {"CFStringDisableROM", NULL},
912 {"CF_CHARSET_PATH", NULL},
913 {"__CF_USER_TEXT_ENCODING", NULL},
914 {"__CFPREFERENCES_AUTOSYNC_INTERVAL", NULL},
915 {"__CFPREFERENCES_LOG_FAILURES", NULL},
916 {"CFNumberDisableCache", NULL},
917 {"__CFPREFERENCES_AVOID_DAEMON", NULL},
918 {NULL, NULL}, // the last one is for optional "COMMAND_MODE" "legacy", do not use this slot, insert before
919 };
920
921 __private_extern__ const char *__CFgetenv(const char *n) {
922 for (CFIndex idx = 0; idx < sizeof(__CFEnv) / sizeof(__CFEnv[0]); idx++) {
923 if (__CFEnv[idx].name && 0 == strcmp(n, __CFEnv[idx].name)) return __CFEnv[idx].value;
924 }
925 return getenv(n);
926 }
927
928 #if DEPLOYMENT_TARGET_WINDOWS
929 #define kNilPthreadT { nil, nil }
930 #else
931 #define kNilPthreadT (pthread_t)0
932 #endif
933
934
935 CF_EXPORT pthread_t _CFMainPThread;
936 pthread_t _CFMainPThread = kNilPthreadT;
937
938 #undef kCFUseCollectableAllocator
939 CF_EXPORT bool kCFUseCollectableAllocator;
940 bool kCFUseCollectableAllocator = false;
941
942 __private_extern__ Boolean __CFProphylacticAutofsAccess = false;
943 __private_extern__ Boolean __CFInitializing = 0;
944 __private_extern__ Boolean __CFInitialized = 0;
945
946 #if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
947 static void __CFInitialize(void) __attribute__ ((constructor));
948 static
949 #endif
950 #if DEPLOYMENT_TARGET_WINDOWS
951 CF_EXPORT
952 #endif
953 void __CFInitialize(void) {
954
955 if (!__CFInitialized && !__CFInitializing) {
956 __CFInitializing = 1;
957
958 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
959 if (!pthread_main_np()) HALT; // CoreFoundation must be initialized on the main thread
960 #endif
961
962 _CFMainPThread = pthread_self();
963
964 #if DEPLOYMENT_TARGET_WINDOWS
965 // Must not call any CF functions
966 __CFTSDWindowsInitialize();
967 #elif DEPLOYMENT_TARGET_LINUX
968 __CFTSDLinuxInitialize();
969 #endif
970
971 __CFProphylacticAutofsAccess = true;
972
973 for (CFIndex idx = 0; idx < sizeof(__CFEnv) / sizeof(__CFEnv[0]); idx++) {
974 __CFEnv[idx].value = __CFEnv[idx].name ? getenv(__CFEnv[idx].name) : NULL;
975 }
976
977 #if !defined(kCFUseCollectableAllocator)
978 kCFUseCollectableAllocator = objc_collectingEnabled();
979 #endif
980 if (kCFUseCollectableAllocator) {
981 #if !defined(__CFObjCIsCollectable)
982 __CFObjCIsCollectable = (bool (*)(void *))objc_isAuto;
983 #endif
984 }
985 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
986 UInt32 s, r;
987 __CFStringGetUserDefaultEncoding(&s, &r); // force the potential setenv to occur early
988 pthread_atfork(__01121__, NULL, __01123__);
989 #endif
990
991
992 memset(__CFRuntimeClassTable, 0, sizeof(__CFRuntimeClassTable));
993 memset(__CFRuntimeObjCClassTable, 0, sizeof(__CFRuntimeObjCClassTable));
994
995
996 /* Here so that two runtime classes get indices 0, 1. */
997 __kCFNotATypeTypeID = _CFRuntimeRegisterClass(&__CFNotATypeClass);
998 __kCFTypeTypeID = _CFRuntimeRegisterClass(&__CFTypeClass);
999
1000 /* Here so that __kCFAllocatorTypeID gets index 2. */
1001 __CFAllocatorInitialize();
1002
1003 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1004 {
1005 CFIndex idx, cnt;
1006 char **args = *_NSGetArgv();
1007 cnt = *_NSGetArgc();
1008 for (idx = 1; idx < cnt - 1; idx++) {
1009 if (NULL == args[idx]) continue;
1010 if (0 == strcmp(args[idx], "-AppleLanguages") && args[idx + 1]) {
1011 CFIndex length = strlen(args[idx + 1]);
1012 __CFAppleLanguages = malloc(length + 1);
1013 memmove(__CFAppleLanguages, args[idx + 1], length + 1);
1014 break;
1015 }
1016 }
1017 }
1018 #endif
1019
1020
1021 CFBasicHashGetTypeID();
1022 CFBagGetTypeID();
1023
1024 for (CFIndex idx = 0; idx < NUM_EXTERN_TABLES; idx++) {
1025 __NSRetainCounters[idx].table = CFBasicHashCreate(kCFAllocatorSystemDefault, kCFBasicHashHasCounts | kCFBasicHashLinearHashing | kCFBasicHashAggressiveGrowth, &CFExternRefCallbacks);
1026 CFBasicHashSetCapacity(__NSRetainCounters[idx].table, 40);
1027 __NSRetainCounters[idx].lock = CFSpinLockInit;
1028 }
1029
1030 /*** _CFRuntimeCreateInstance() can finally be called generally after this line. ***/
1031
1032 __CFRuntimeClassTableCount = 7;
1033 __CFStringInitialize(); // CFString's TypeID must be 0x7, now and forever
1034
1035 __CFRuntimeClassTableCount = 16;
1036 __CFNullInitialize(); // See above for hard-coding of this position
1037 CFSetGetTypeID(); // See above for hard-coding of this position
1038 CFDictionaryGetTypeID(); // See above for hard-coding of this position
1039 __CFArrayInitialize(); // See above for hard-coding of this position
1040 __CFDataInitialize(); // See above for hard-coding of this position
1041 __CFBooleanInitialize(); // See above for hard-coding of this position
1042 __CFNumberInitialize(); // See above for hard-coding of this position
1043
1044 __CFBinaryHeapInitialize();
1045 __CFBitVectorInitialize();
1046 __CFCharacterSetInitialize();
1047 __CFStorageInitialize();
1048 __CFErrorInitialize();
1049 __CFTreeInitialize();
1050 __CFURLInitialize();
1051
1052 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
1053 __CFBundleInitialize();
1054 __CFPFactoryInitialize();
1055 #endif
1056 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1057 __CFPlugInInitialize();
1058 __CFPlugInInstanceInitialize();
1059 #endif
1060 __CFUUIDInitialize();
1061 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
1062 __CFMessagePortInitialize();
1063 #endif
1064 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1065 __CFMachPortInitialize();
1066 #endif
1067 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
1068 __CFStreamInitialize();
1069 #endif
1070 #if DEPLOYMENT_TARGET_WINDOWS
1071 __CFWindowsNamedPipeInitialize();
1072 #endif
1073 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
1074 __CFRunLoopInitialize();
1075 __CFRunLoopObserverInitialize();
1076 __CFRunLoopSourceInitialize();
1077 __CFRunLoopTimerInitialize();
1078 #endif
1079 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
1080 __CFTimeZoneInitialize();
1081 __CFCalendarInitialize();
1082 #if DEPLOYMENT_TARGET_LINUX
1083 __CFTimeZoneInitialize();
1084 __CFCalendarInitialize();
1085 #endif
1086 #endif
1087
1088 {
1089 CFIndex idx, cnt;
1090 char **args;
1091 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1092 args = *_NSGetArgv();
1093 cnt = *_NSGetArgc();
1094 #elif DEPLOYMENT_TARGET_WINDOWS
1095 wchar_t *commandLine = GetCommandLineW();
1096 // result is actually pointer to wchar_t *, make sure to account for that below
1097 args = (char **)CommandLineToArgvW(commandLine, (int *)&cnt);
1098 #endif
1099 CFIndex count;
1100 CFStringRef *list, buffer[256];
1101 list = (cnt <= 256) ? buffer : (CFStringRef *)malloc(cnt * sizeof(CFStringRef));
1102 for (idx = 0, count = 0; idx < cnt; idx++) {
1103 if (NULL == args[idx]) continue;
1104 #if DEPLOYMENT_TARGET_WINDOWS
1105 list[count] = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)args[idx], wcslen((wchar_t *)args[idx]));
1106 #else
1107 list[count] = CFStringCreateWithCString(kCFAllocatorSystemDefault, args[idx], kCFStringEncodingUTF8);
1108 if (NULL == list[count]) {
1109 list[count] = CFStringCreateWithCString(kCFAllocatorSystemDefault, args[idx], kCFStringEncodingISOLatin1);
1110 // We CANNOT use the string SystemEncoding here;
1111 // Do not argue: it is not initialized yet, but these
1112 // arguments MUST be initialized before it is.
1113 // We should just ignore the argument if the UTF-8
1114 // conversion fails, but out of charity we try once
1115 // more with ISO Latin1, a standard unix encoding.
1116 }
1117 #endif
1118 if (NULL != list[count]) count++;
1119 }
1120 __CFArgStuff = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)list, count, &kCFTypeArrayCallBacks);
1121 if (list != buffer) free(list);
1122 #if DEPLOYMENT_TARGET_WINDOWS
1123 LocalFree(args);
1124 #endif
1125 }
1126
1127 _CFProcessPath(); // cache this early
1128
1129 __CFOAInitialize();
1130
1131
1132 if (__CFRuntimeClassTableCount < 256) __CFRuntimeClassTableCount = 256;
1133
1134
1135 #if defined(DEBUG) || defined(ENABLE_ZOMBIES)
1136 const char *value = __CFgetenv("NSZombieEnabled");
1137 if (value && (*value == 'Y' || *value == 'y')) _CFEnableZombies();
1138 value = __CFgetenv("NSDeallocateZombies");
1139 if (value && (*value == 'Y' || *value == 'y')) __CFDeallocateZombies = 0xff;
1140 #endif
1141
1142 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED)
1143 CFLog(kCFLogLevelWarning, CFSTR("Assertions enabled"));
1144 #endif
1145
1146 __CFProphylacticAutofsAccess = false;
1147 __CFInitializing = 0;
1148 __CFInitialized = 1;
1149 }
1150 }
1151
1152
1153 #if DEPLOYMENT_TARGET_WINDOWS
1154
1155 __private_extern__ void __CFStringCleanup(void);
1156 __private_extern__ void __CFSocketCleanup(void);
1157 __private_extern__ void __CFUniCharCleanup(void);
1158 __private_extern__ void __CFStreamCleanup(void);
1159
1160 static CFBundleRef RegisterCoreFoundationBundle(void) {
1161 #ifdef _DEBUG
1162 // might be nice to get this from the project file at some point
1163 wchar_t *DLLFileName = (wchar_t *)L"CoreFoundation_debug.dll";
1164 #else
1165 wchar_t *DLLFileName = (wchar_t *)L"CoreFoundation.dll";
1166 #endif
1167 wchar_t path[MAX_PATH+1];
1168 path[0] = path[1] = 0;
1169 DWORD wResult;
1170 CFIndex idx;
1171 HMODULE ourModule = GetModuleHandleW(DLLFileName);
1172
1173 CFAssert(ourModule, __kCFLogAssertion, "GetModuleHandle failed");
1174
1175 wResult = GetModuleFileNameW(ourModule, path, MAX_PATH+1);
1176 CFAssert1(wResult > 0, __kCFLogAssertion, "GetModuleFileName failed: %d", GetLastError());
1177 CFAssert1(wResult < MAX_PATH+1, __kCFLogAssertion, "GetModuleFileName result truncated: %s", path);
1178
1179 // strip off last component, the DLL name
1180 for (idx = wResult - 1; idx; idx--) {
1181 if ('\\' == path[idx]) {
1182 path[idx] = '\0';
1183 break;
1184 }
1185 }
1186
1187 CFStringRef fsPath = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar*)path, idx);
1188 CFURLRef dllURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, fsPath, kCFURLWindowsPathStyle, TRUE);
1189 CFURLRef bundleURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, dllURL, CFSTR("CoreFoundation.resources"), TRUE);
1190 CFRelease(fsPath);
1191 CFRelease(dllURL);
1192
1193 // this registers us so subsequent calls to CFBundleGetBundleWithIdentifier will succeed
1194 CFBundleRef bundle = CFBundleCreate(kCFAllocatorSystemDefault, bundleURL);
1195 CFRelease(bundleURL);
1196
1197 return bundle;
1198 }
1199
1200
1201 #define DLL_PROCESS_ATTACH 1
1202 #define DLL_THREAD_ATTACH 2
1203 #define DLL_THREAD_DETACH 3
1204 #define DLL_PROCESS_DETACH 0
1205
1206 int DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID pReserved ) {
1207 static CFBundleRef cfBundle = NULL;
1208 if (dwReason == DLL_PROCESS_ATTACH) {
1209 __CFInitialize();
1210 cfBundle = RegisterCoreFoundationBundle();
1211 } else if (dwReason == DLL_PROCESS_DETACH && pReserved == 0) {
1212 // Only cleanup if we are being unloaded dynamically (pReserved == 0) <rdar://problem/7480873>
1213 __CFStreamCleanup();
1214 __CFSocketCleanup();
1215 __CFUniCharCleanup();
1216
1217 #if DEPLOYMENT_TARGET_WINDOWS
1218 // No CF functions should access TSD after this is called
1219 __CFTSDWindowsCleanup();
1220 #endif
1221
1222 // do these last
1223 if (cfBundle) CFRelease(cfBundle);
1224 __CFStringCleanup();
1225 } else if (dwReason == DLL_THREAD_DETACH) {
1226 __CFFinalizeWindowsThreadData();
1227 }
1228 return TRUE;
1229 }
1230
1231 #endif
1232
1233 #if __CF_BIG_ENDIAN__
1234 #define RC_INCREMENT (1ULL)
1235 #define RC_MASK (0xFFFFFFFFULL)
1236 #define RC_GET(V) ((V) & RC_MASK)
1237 #define RC_DEALLOCATING_BIT (0x400000ULL << 32)
1238 #else
1239 #define RC_INCREMENT (1ULL << 32)
1240 #define RC_MASK (0xFFFFFFFFULL << 32)
1241 #define RC_GET(V) (((V) & RC_MASK) >> 32)
1242 #define RC_DEALLOCATING_BIT (0x400000ULL)
1243 #endif
1244
1245 #if !DEPLOYMENT_TARGET_WINDOWS && __LP64__
1246 static bool (*CAS64)(int64_t, int64_t, volatile int64_t *) = OSAtomicCompareAndSwap64Barrier;
1247 #else
1248 static bool (*CAS32)(int32_t, int32_t, volatile int32_t *) = OSAtomicCompareAndSwap32Barrier;
1249 #endif
1250
1251 // For "tryR==true", a return of NULL means "failed".
1252 static CFTypeRef _CFRetain(CFTypeRef cf, Boolean tryR) {
1253 uint32_t cfinfo = *(uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1254 if (cfinfo & 0x800000) { // custom ref counting for object
1255 if (tryR) return NULL;
1256 CFTypeID typeID = (cfinfo >> 8) & 0x03FF; // mask up to 0x0FFF
1257 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
1258 uint32_t (*refcount)(intptr_t, CFTypeRef) = cfClass->refcount;
1259 if (!refcount || !(cfClass->version & _kCFRuntimeCustomRefCount) || (((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS] != 0xFF)) {
1260 HALT; // bogus object
1261 }
1262 #if __LP64__
1263 if (((CFRuntimeBase *)cf)->_rc != 0xFFFFFFFFU) {
1264 HALT; // bogus object
1265 }
1266 #endif
1267 refcount(+1, cf);
1268 return cf;
1269 }
1270
1271 Boolean didAuto = false;
1272 #if __LP64__
1273 if (0 == ((CFRuntimeBase *)cf)->_rc && !CF_IS_COLLECTABLE(cf)) return cf; // Constant CFTypeRef
1274 #if !DEPLOYMENT_TARGET_WINDOWS
1275 uint64_t allBits;
1276 do {
1277 allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1278 if (tryR && (allBits & RC_DEALLOCATING_BIT)) return NULL;
1279 } while (!CAS64(allBits, allBits + RC_INCREMENT, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo));
1280 // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1281 if (RC_GET(allBits) == 0 && CF_IS_COLLECTABLE(cf)) {
1282 auto_zone_retain(objc_collectableZone(), (void*)cf);
1283 didAuto = true;
1284 }
1285 #else
1286 uint32_t lowBits;
1287 do {
1288 lowBits = ((CFRuntimeBase *)cf)->_rc;
1289 } while (!CAS32(lowBits, lowBits + 1, (int32_t *)&((CFRuntimeBase *)cf)->_rc));
1290 // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1291 if (lowBits == 0 && CF_IS_COLLECTABLE(cf)) {
1292 auto_zone_retain(objc_collectableZone(), (void*)cf);
1293 didAuto = true;
1294 }
1295 #endif
1296 #else
1297 #define RC_START 24
1298 #define RC_END 31
1299 volatile uint32_t *infoLocation = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1300 CFIndex rcLowBits = __CFBitfieldGetValue(cfinfo, RC_END, RC_START);
1301 if (__builtin_expect(0 == rcLowBits, 0) && !CF_IS_COLLECTABLE(cf)) return cf; // Constant CFTypeRef
1302 bool success = 0;
1303 do {
1304 cfinfo = *infoLocation;
1305 #if !DEPLOYMENT_TARGET_WINDOWS
1306 // if already deallocating, don't allow new retain
1307 if (tryR && (cfinfo & 0x400000)) return NULL;
1308 #endif
1309 uint32_t prospectiveNewInfo = cfinfo; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1310 prospectiveNewInfo += (1 << RC_START);
1311 rcLowBits = __CFBitfieldGetValue(prospectiveNewInfo, RC_END, RC_START);
1312 if (__builtin_expect((rcLowBits & 0x7f) == 0, 0)) {
1313 /* Roll over another bit to the external ref count
1314 Real ref count = low 7 bits of info[CF_RC_BITS] + external ref count << 6
1315 Bit 8 of low bits indicates that external ref count is in use.
1316 External ref count is shifted by 6 rather than 7 so that we can set the low
1317 bits to to 1100 0000 rather than 1000 0000.
1318 This prevents needing to access the external ref count for successive retains and releases
1319 when the composite retain count is right around a multiple of 1 << 7.
1320 */
1321 prospectiveNewInfo = cfinfo;
1322 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, ((1 << 7) | (1 << 6)));
1323 __CFSpinLock(&__CFRuntimeExternRefCountTableLock);
1324 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1325 if (__builtin_expect(success, 1)) {
1326 __CFDoExternRefOperation(350, (id)cf);
1327 }
1328 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock);
1329 } else {
1330 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1331 // XXX_PCB: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition.
1332 if (success && __CFBitfieldGetValue(cfinfo, RC_END, RC_START) == 0 && CF_IS_COLLECTABLE(cf)) {
1333 auto_zone_retain(objc_collectableZone(), (void*)cf);
1334 didAuto = true;
1335 }
1336 }
1337 } while (__builtin_expect(!success, 0));
1338 #endif
1339 if (!didAuto && __builtin_expect(__CFOASafe, 0)) {
1340 __CFRecordAllocationEvent(__kCFRetainEvent, (void *)cf, 0, CFGetRetainCount(cf), NULL);
1341 }
1342 return cf;
1343 }
1344
1345 // Never called under GC, only called via ARR weak subsystem; a return of NULL is failure
1346 CFTypeRef _CFTryRetain(CFTypeRef cf) {
1347 if (NULL == cf) return NULL;
1348 if (CF_IS_TAGGED_OBJ(cf)) return cf; // success
1349 return _CFRetain(cf, true);
1350 }
1351
1352 Boolean _CFIsDeallocating(CFTypeRef cf) {
1353 if (NULL == cf) return false;
1354 if (CF_IS_TAGGED_OBJ(cf)) return false;
1355 uint32_t cfinfo = *(uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1356 if (cfinfo & 0x800000) { // custom ref counting for object
1357 return true; // lie for now; this weak references to these objects cannot be formed
1358 }
1359 return (cfinfo & 0x400000) ? true : false;
1360 }
1361
1362 static void _CFRelease(CFTypeRef cf) {
1363
1364 uint32_t cfinfo = *(uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1365 CFTypeID typeID = (cfinfo >> 8) & 0x03FF; // mask up to 0x0FFF
1366 if (cfinfo & 0x800000) { // custom ref counting for object
1367 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
1368 uint32_t (*refcount)(intptr_t, CFTypeRef) = cfClass->refcount;
1369 if (!refcount || !(cfClass->version & _kCFRuntimeCustomRefCount) || (((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS] != 0xFF)) {
1370 HALT; // bogus object
1371 }
1372 #if __LP64__
1373 if (((CFRuntimeBase *)cf)->_rc != 0xFFFFFFFFU) {
1374 HALT; // bogus object
1375 }
1376 #endif
1377 refcount(-1, cf);
1378 return;
1379 }
1380
1381 CFIndex start_rc = __builtin_expect(__CFOASafe, 0) ? CFGetRetainCount(cf) : 0;
1382 Boolean isAllocator = (__kCFAllocatorTypeID_CONST == typeID);
1383 Boolean didAuto = false;
1384 #if __LP64__
1385 #if !DEPLOYMENT_TARGET_WINDOWS
1386 uint32_t lowBits;
1387 uint64_t allBits;
1388 again:;
1389 do {
1390 allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1391 lowBits = RC_GET(allBits);
1392 if (0 == lowBits) {
1393 if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf);
1394 return; // Constant CFTypeRef
1395 }
1396 if (1 == lowBits) {
1397 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
1398 if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) {
1399 cfClass->reclaim(cf);
1400 }
1401 if (!CF_IS_COLLECTABLE(cf)) {
1402 uint64_t newAllBits = allBits | RC_DEALLOCATING_BIT;
1403 if (!CAS64(allBits, newAllBits, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo)) {
1404 goto again;
1405 }
1406 allBits = newAllBits;
1407 void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize;
1408 if (NULL != func) {
1409 func(cf);
1410 }
1411 allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1412 lowBits = RC_GET(allBits);
1413 if (isAllocator || ((1 == lowBits) && CAS64(allBits, allBits - RC_INCREMENT, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo))) {
1414 goto really_free;
1415 }
1416 Boolean success = false;
1417 do { // drop the deallocating bit; racey, but this resurrection stuff isn't thread-safe anyway
1418 allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1419 uint64_t newAllBits = allBits & ~RC_DEALLOCATING_BIT;
1420 success = CAS64(allBits, newAllBits, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo);
1421 } while (!success);
1422 goto again; // still need to have the effect of a CFRelease
1423 }
1424 }
1425 } while (!CAS64(allBits, allBits - RC_INCREMENT, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo));
1426 if (lowBits == 1 && CF_IS_COLLECTABLE(cf)) {
1427 // GC: release the collector's hold over the object, which will call the finalize function later on.
1428 auto_zone_release(objc_collectableZone(), (void*)cf);
1429 didAuto = true;
1430 }
1431 #else
1432 uint32_t lowBits;
1433 do {
1434 lowBits = ((CFRuntimeBase *)cf)->_rc;
1435 if (0 == lowBits) {
1436 if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf);
1437 return; // Constant CFTypeRef
1438 }
1439 if (1 == lowBits) {
1440 // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION
1441 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
1442 if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) {
1443 cfClass->reclaim(cf);
1444 }
1445 if (!CF_IS_COLLECTABLE(cf)) {
1446 void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize;
1447 if (NULL != func) {
1448 func(cf);
1449 }
1450 if (isAllocator || CAS32(1, 0, (int32_t *)&((CFRuntimeBase *)cf)->_rc)) {
1451 goto really_free;
1452 }
1453 }
1454 }
1455 } while (!CAS32(lowBits, lowBits - 1, (int32_t *)&((CFRuntimeBase *)cf)->_rc));
1456 if (lowBits == 1 && CF_IS_COLLECTABLE(cf)) {
1457 // GC: release the collector's hold over the object, which will call the finalize function later on.
1458 auto_zone_release(objc_collectableZone(), (void*)cf);
1459 didAuto = true;
1460 }
1461 #endif
1462 #else
1463 #if !DEPLOYMENT_TARGET_WINDOWS
1464 again:;
1465 volatile uint32_t *infoLocation = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1466 CFIndex rcLowBits = __CFBitfieldGetValue(cfinfo, RC_END, RC_START);
1467 if (__builtin_expect(0 == rcLowBits, 0)) {
1468 if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf);
1469 return; // Constant CFTypeRef
1470 }
1471 bool success = 0;
1472 Boolean whack = false;
1473 do {
1474 cfinfo = *infoLocation;
1475 rcLowBits = __CFBitfieldGetValue(cfinfo, RC_END, RC_START);
1476 if (__builtin_expect(1 == rcLowBits, 0)) {
1477 // we think cf should be deallocated
1478 uint32_t prospectiveNewInfo = cfinfo | (0x400000);
1479 if (CF_IS_COLLECTABLE(cf)) {
1480 prospectiveNewInfo -= (1 << RC_START);
1481 }
1482 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1483 if (success) whack = true;
1484 } else {
1485 // not yet junk
1486 uint32_t prospectiveNewInfo = cfinfo; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1487 if (__builtin_expect((1 << 7) == rcLowBits, 0)) {
1488 // Time to remove a bit from the external ref count
1489 __CFSpinLock(&__CFRuntimeExternRefCountTableLock);
1490 CFIndex rcHighBitsCnt = __CFDoExternRefOperation(500, (id)cf);
1491 if (1 == rcHighBitsCnt) {
1492 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, (1 << 6) - 1);
1493 } else {
1494 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, ((1 << 6) | (1 << 7)) - 1);
1495 }
1496 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1497 if (__builtin_expect(success, 1)) {
1498 __CFDoExternRefOperation(450, (id)cf);
1499 }
1500 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock);
1501 } else {
1502 prospectiveNewInfo -= (1 << RC_START);
1503 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1504 }
1505 }
1506 } while (__builtin_expect(!success, 0));
1507
1508 if (whack) {
1509 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
1510 if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) {
1511 cfClass->reclaim(cf);
1512 }
1513 if (CF_IS_COLLECTABLE(cf)) {
1514 // GC: release the collector's hold over the object, which will call the finalize function later on.
1515 auto_zone_release(objc_collectableZone(), (void*)cf);
1516 didAuto = true;
1517 } else {
1518 if (isAllocator) {
1519 goto really_free;
1520 } else {
1521 void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize;
1522 if (NULL != func) {
1523 func(cf);
1524 }
1525 rcLowBits = __CFBitfieldGetValue(*infoLocation, RC_END, RC_START);
1526 if (1 == rcLowBits) {
1527 goto really_free;
1528 }
1529 do { // drop the deallocating bit; racey, but this resurrection stuff isn't thread-safe anyway
1530 cfinfo = *infoLocation;
1531 uint32_t prospectiveNewInfo = (cfinfo & ~(0x400000));
1532 success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1533 } while (!success);
1534 goto again;
1535 }
1536 }
1537 }
1538 #else
1539 volatile uint32_t *infoLocation = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo);
1540 CFIndex rcLowBits = __CFBitfieldGetValue(*infoLocation, RC_END, RC_START);
1541 if (__builtin_expect(0 == rcLowBits, 0)) {
1542 if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf);
1543 return; // Constant CFTypeRef
1544 }
1545 bool success = 0;
1546 do {
1547 uint32_t initialCheckInfo = *infoLocation;
1548 rcLowBits = __CFBitfieldGetValue(initialCheckInfo, RC_END, RC_START);
1549 if (__builtin_expect(1 == rcLowBits, 0)) {
1550 // we think cf should be deallocated
1551 // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION
1552 CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID];
1553 if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) {
1554 cfClass->reclaim(cf);
1555 }
1556 if (CF_IS_COLLECTABLE(cf)) {
1557 uint32_t prospectiveNewInfo = initialCheckInfo - (1 << RC_START);
1558 success = CAS32(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1559 // GC: release the collector's hold over the object, which will call the finalize function later on.
1560 if (success) {
1561 auto_zone_release(objc_collectableZone(), (void*)cf);
1562 didAuto = true;
1563 }
1564 } else {
1565 if (isAllocator) {
1566 goto really_free;
1567 } else {
1568 void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize;
1569 if (NULL != func) {
1570 func(cf);
1571 }
1572 // We recheck rcLowBits to see if the object has been retained again during
1573 // the finalization process. This allows for the finalizer to resurrect,
1574 // but the main point is to allow finalizers to be able to manage the
1575 // removal of objects from uniquing caches, which may race with other threads
1576 // which are allocating (looking up and finding) objects from those caches,
1577 // which (that thread) would be the thing doing the extra retain in that case.
1578 rcLowBits = __CFBitfieldGetValue(*infoLocation, RC_END, RC_START);
1579 success = (1 == rcLowBits);
1580 if (__builtin_expect(success, 1)) {
1581 goto really_free;
1582 }
1583 }
1584 }
1585 } else {
1586 // not yet junk
1587 uint32_t prospectiveNewInfo = initialCheckInfo; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory.
1588 if (__builtin_expect((1 << 7) == rcLowBits, 0)) {
1589 // Time to remove a bit from the external ref count
1590 __CFSpinLock(&__CFRuntimeExternRefCountTableLock);
1591 CFIndex rcHighBitsCnt = __CFDoExternRefOperation(500, (id)cf);
1592 if (1 == rcHighBitsCnt) {
1593 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, (1 << 6) - 1);
1594 } else {
1595 __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, ((1 << 6) | (1 << 7)) - 1);
1596 }
1597 success = CAS32(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1598 if (__builtin_expect(success, 1)) {
1599 __CFDoExternRefOperation(450, (id)cf);
1600 }
1601 __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock);
1602 } else {
1603 prospectiveNewInfo -= (1 << RC_START);
1604 success = CAS32(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation);
1605 }
1606 }
1607 } while (__builtin_expect(!success, 0));
1608 #endif
1609 #endif
1610 if (!didAuto && __builtin_expect(__CFOASafe, 0)) {
1611 __CFRecordAllocationEvent(__kCFReleaseEvent, (void *)cf, 0, start_rc - 1, NULL);
1612 }
1613 return;
1614
1615 really_free:;
1616 if (!didAuto && __builtin_expect(__CFOASafe, 0)) {
1617 // do not use CFGetRetainCount() because cf has been freed if it was an allocator
1618 __CFRecordAllocationEvent(__kCFReleaseEvent, (void *)cf, 0, 0, NULL);
1619 }
1620 // cannot zombify allocators, which get deallocated by __CFAllocatorDeallocate (finalize)
1621 if (isAllocator) {
1622 __CFAllocatorDeallocate((void *)cf);
1623 } else {
1624 CFAllocatorRef allocator = kCFAllocatorSystemDefault;
1625 Boolean usesSystemDefaultAllocator = true;
1626
1627 if (!__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 7, 7)) {
1628 allocator = CFGetAllocator(cf);
1629 usesSystemDefaultAllocator = _CFAllocatorIsSystemDefault(allocator);
1630 }
1631
1632 {
1633 CFAllocatorDeallocate(allocator, (uint8_t *)cf - (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef)));
1634 }
1635
1636 if (kCFAllocatorSystemDefault != allocator) {
1637 CFRelease(allocator);
1638 }
1639 }
1640 }
1641
1642 #undef __kCFAllocatorTypeID_CONST
1643 #undef __CFGenericAssertIsCF
1644
1645