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
48OBJC_EXPORT void *objc_destructInstance(id obj);
49#endif
50
51
52
53#if DEPLOYMENT_TARGET_WINDOWS
54#include <Shellapi.h>
55#endif
56
57enum {
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
73CF_PRIVATE void __CFOAInitializeNSObject(void);  // from NSObject.m
74
75bool __CFOASafe = false;
76
77void (*__CFObjectAllocRecordAllocationFunction)(int, void *, int64_t , uint64_t, const char *) = NULL;
78void (*__CFObjectAllocSetLastAllocEventNameFunction)(void *, const char *) = NULL;
79
80void __CFOAInitialize(void) {
81}
82
83void __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
88void __CFSetLastAllocationEventName(void *ptr, const char *classname) {
89    if (!__CFOASafe || !__CFObjectAllocSetLastAllocEventNameFunction) return;
90    __CFObjectAllocSetLastAllocEventNameFunction(ptr, classname);
91}
92
93#elif FAKE_INSTRUMENTS
94
95CF_EXPORT bool __CFOASafe = true;
96
97void __CFOAInitialize(void) { }
98
99void __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
119void __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
127bool __CFOASafe = false;
128
129void __CFOAInitialize(void) { }
130void __CFRecordAllocationEvent(int eventnum, void *ptr, int64_t size, uint64_t data, const char *classname) { }
131void __CFSetLastAllocationEventName(void *ptr, const char *classname) { }
132
133#endif
134
135extern void __HALT(void);
136
137static CFTypeID __kCFNotATypeTypeID = _kCFRuntimeNotATypeID;
138
139#if !defined (__cplusplus)
140static 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
152static CFTypeID __kCFTypeTypeID = _kCFRuntimeNotATypeID;
153
154static 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
166void SIG1(CFTypeRef){__HALT();};;
167CFTypeRef SIG2(CFAllocatorRef,CFTypeRef){__HALT();return NULL;};
168Boolean SIG3(CFTypeRef,CFTypeRef){__HALT();return FALSE;};
169CFHashCode SIG4(CFTypeRef){__HALT(); return 0;};
170CFStringRef SIG5(CFTypeRef,CFDictionaryRef){__HALT();return NULL;};
171CFStringRef SIG6(CFTypeRef){__HALT();return NULL;};
172
173static 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
185static CFTypeID __kCFTypeTypeID = _kCFRuntimeNotATypeID;
186
187static 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
201static CFSpinLock_t __CFBigRuntimeFunnel = CFSpinLockInit;
202CF_PRIVATE CFRuntimeClass * __CFRuntimeClassTable[__CFRuntimeClassTableSize] = {0};
203CF_PRIVATE int32_t __CFRuntimeClassTableCount = 0;
204
205CF_PRIVATE uintptr_t __CFRuntimeObjCClassTable[__CFRuntimeClassTableSize] = {0};
206
207#if !defined(__CFObjCIsCollectable)
208bool (*__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__
214int __CFConstantStringClassReference[24] = {0};
215#else
216int __CFConstantStringClassReference[12] = {0};
217#endif
218#endif
219
220#if __LP64__
221int __CFConstantStringClassReference[24] = {0};
222#else
223int __CFConstantStringClassReference[12] = {0};
224#endif
225
226void *__CFConstantStringClassReferencePtr = NULL;
227
228Boolean _CFIsObjC(CFTypeID typeID, void *obj) {
229    return CF_IS_OBJC(typeID, obj);
230}
231
232CFTypeID _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
256const CFRuntimeClass * _CFRuntimeGetClassWithTypeID(CFTypeID typeID) {
257    return __CFRuntimeClassTable[typeID]; // hopelessly unthreadsafe
258}
259
260void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID) {
261    __CFSpinLock(&__CFBigRuntimeFunnel);
262    __CFRuntimeClassTable[typeID] = NULL;
263    __CFSpinUnlock(&__CFBigRuntimeFunnel);
264}
265
266
267#if defined(DEBUG) || defined(ENABLE_ZOMBIES)
268
269CF_PRIVATE uint8_t __CFZombieEnabled = 0;
270CF_PRIVATE uint8_t __CFDeallocateZombies = 0;
271
272extern void __CFZombifyNSObject(void);  // from NSObject.m
273
274void _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
282CF_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
290CFTypeRef _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
359void _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
380void _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
400CF_PRIVATE void _CFRuntimeSetInstanceTypeIDAndIsa(CFTypeRef cf, CFTypeID newTypeID) {
401    _CFRuntimeSetInstanceTypeID(cf, newTypeID);
402}
403
404
405enum {
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
423static struct {
424    CFSpinLock_t lock;
425    CFBasicHashRef table;
426    uint8_t padding[64 - sizeof(CFBasicHashRef) - sizeof(CFSpinLock_t)];
427} __NSRetainCounters[NUM_EXTERN_TABLES];
428
429CF_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
460CF_EXPORT CFTypeID CFNumberGetTypeID(void);
461
462CF_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
469CFTypeID __CFGenericTypeID(const void *cf) {
470    return __CFGenericTypeID_inline(cf);
471}
472
473CFTypeID CFTypeGetTypeID(void) {
474    return __kCFTypeTypeID;
475}
476
477CF_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
492CFTypeID 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
501CFStringRef 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
508static CFTypeRef _CFRetain(CFTypeRef cf, Boolean tryR);
509
510CFTypeRef 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
516CFTypeRef CFAutorelease(CFTypeRef __attribute__((cf_consumed)) cf) {
517    if (NULL == cf) { CRSetCrashLogMessage("*** CFAutorelease() called with NULL ***"); HALT; }
518    return cf;
519}
520
521static void _CFRelease(CFTypeRef cf);
522
523void 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
541CF_PRIVATE void __CFAllocatorDeallocate(CFTypeRef cf);
542
543CF_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
553extern void CFCollection_non_gc_storage_error(void);
554
555CF_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
590CF_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__
624static CFSpinLock_t __CFRuntimeExternRefCountTableLock = CFSpinLockInit;
625#endif
626
627static 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
649CFIndex 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
675CFTypeRef CFMakeCollectable(CFTypeRef cf) {
676    if (NULL == cf) return NULL;
677    return cf;
678}
679
680CFTypeRef CFMakeUncollectable(CFTypeRef cf) {
681    if (NULL == cf) return NULL;
682    if (CF_IS_COLLECTABLE(cf)) {
683        CFRetain(cf);
684    }
685    return cf;
686}
687
688Boolean 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
703CFHashCode 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
716CFStringRef 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
728CF_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
737extern CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef);
738
739CFAllocatorRef 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
747extern void __CFNullInitialize(void);
748extern void __CFAllocatorInitialize(void);
749extern void __CFStringInitialize(void);
750extern void __CFArrayInitialize(void);
751extern void __CFBooleanInitialize(void);
752extern void __CFCharacterSetInitialize(void);
753extern void __CFDataInitialize(void);
754extern void __CFNumberInitialize(void);
755extern void __CFStorageInitialize(void);
756extern void __CFErrorInitialize(void);
757extern void __CFTreeInitialize(void);
758extern void __CFURLInitialize(void);
759#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
760extern void __CFMachPortInitialize(void);
761#endif
762extern void __CFMessagePortInitialize(void);
763extern void __CFRunLoopInitialize(void);
764extern void __CFRunLoopObserverInitialize(void);
765extern void __CFRunLoopSourceInitialize(void);
766extern void __CFRunLoopTimerInitialize(void);
767extern void __CFPFactoryInitialize(void);
768extern void __CFBundleInitialize(void);
769extern void __CFPlugInInitialize(void);
770extern void __CFPlugInInstanceInitialize(void);
771extern void __CFUUIDInitialize(void);
772extern void __CFBinaryHeapInitialize(void);
773extern void __CFBitVectorInitialize(void);
774CF_PRIVATE void __CFDateInitialize(void);
775#if DEPLOYMENT_TARGET_LINUX
776CF_PRIVATE void __CFTSDLinuxInitialize();
777#endif
778#if DEPLOYMENT_TARGET_WINDOWS
779// From CFPlatform.c
780CF_PRIVATE void __CFTSDWindowsInitialize(void);
781CF_PRIVATE void __CFTSDWindowsCleanup(void);
782CF_PRIVATE void __CFFinalizeWindowsThreadData();
783#endif
784extern void __CFStreamInitialize(void);
785extern void __CFCalendarInitialize();
786extern void __CFTimeZoneInitialize();
787#if DEPLOYMENT_TARGET_LINUX
788extern void __CFCalendarInitialize();
789extern void __CFTimeZoneInitialize();
790#endif
791#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
792extern void __CFXPreferencesInitialize(void);
793#endif
794
795#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
796CF_PRIVATE uint8_t __CF120290 = false;
797CF_PRIVATE uint8_t __CF120291 = false;
798CF_PRIVATE uint8_t __CF120293 = false;
799CF_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
800asm(".desc ___crashreporter_info__, 0x10");
801
802static void __01121__(void) {
803    __CF120291 = pthread_is_threaded_np() ? true : false;
804}
805
806static 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
826CF_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
834CF_EXPORT const void *__CFArgStuff;
835const void *__CFArgStuff = NULL;
836CF_PRIVATE void *__CFAppleLanguages = NULL;
837
838// do not cache CFFIXED_USER_HOME or HOME, there are situations where they can change
839
840static 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
873CF_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
880CF_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
892CF_EXPORT bool kCFUseCollectableAllocator;
893bool kCFUseCollectableAllocator = false;
894
895CF_PRIVATE Boolean __CFProphylacticAutofsAccess = false;
896CF_PRIVATE Boolean __CFInitializing = 0;
897CF_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
900CF_EXPORT pthread_t _CFMainPThread;
901pthread_t _CFMainPThread = kNilPthreadT;
902#if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_IPHONESIMULATOR
903
904CF_EXPORT pthread_t _CF_pthread_main_thread_np(void);
905pthread_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
913static void __CFInitialize(void) __attribute__ ((constructor));
914static
915#endif
916#if DEPLOYMENT_TARGET_WINDOWS
917CF_EXPORT
918#endif
919void __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
1125CF_PRIVATE void __CFStringCleanup(void);
1126CF_PRIVATE void __CFSocketCleanup(void);
1127CF_PRIVATE void __CFUniCharCleanup(void);
1128CF_PRIVATE void __CFStreamCleanup(void);
1129
1130static 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
1176int 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__
1216static bool (*CAS64)(int64_t, int64_t, volatile int64_t *) = OSAtomicCompareAndSwap64Barrier;
1217#else
1218static bool (*CAS32)(int32_t, int32_t, volatile int32_t *) = OSAtomicCompareAndSwap32Barrier;
1219#endif
1220
1221// For "tryR==true", a return of NULL means "failed".
1222static 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
1316CFTypeRef _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
1324Boolean _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
1336static 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
1620