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