/* * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* CFBase.c Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ #include #include "CFInternal.h" #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD #include #endif #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED #include extern size_t malloc_good_size(size_t size); #include #include #endif #include #include // -------- -------- -------- -------- -------- -------- -------- -------- #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED // CFAllocator structure must match struct _malloc_zone_t! // The first two reserved fields in struct _malloc_zone_t are for us with CFRuntimeBase #endif struct __CFAllocator { CFRuntimeBase _base; #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED size_t (*size)(struct _malloc_zone_t *zone, const void *ptr); /* returns the size of a block or 0 if not in this zone; must be fast, especially for negative answers */ void *(*malloc)(struct _malloc_zone_t *zone, size_t size); void *(*calloc)(struct _malloc_zone_t *zone, size_t num_items, size_t size); /* same as malloc, but block returned is set to zero */ void *(*valloc)(struct _malloc_zone_t *zone, size_t size); /* same as malloc, but block returned is set to zero and is guaranteed to be page aligned */ void (*free)(struct _malloc_zone_t *zone, void *ptr); void *(*realloc)(struct _malloc_zone_t *zone, void *ptr, size_t size); void (*destroy)(struct _malloc_zone_t *zone); /* zone is destroyed and all memory reclaimed */ const char *zone_name; /* Optional batch callbacks; these may be NULL */ unsigned (*batch_malloc)(struct _malloc_zone_t *zone, size_t size, void **results, unsigned num_requested); /* given a size, returns pointers capable of holding that size; returns the number of pointers allocated (maybe 0 or less than num_requested) */ void (*batch_free)(struct _malloc_zone_t *zone, void **to_be_freed, unsigned num_to_be_freed); /* frees all the pointers in to_be_freed; note that to_be_freed may be overwritten during the process */ struct malloc_introspection_t *introspect; unsigned version; /* aligned memory allocation. The callback may be NULL. */ void *(*memalign)(struct _malloc_zone_t *zone, size_t alignment, size_t size); /* free a pointer known to be in zone and known to have the given size. The callback may be NULL. */ void (*free_definite_size)(struct _malloc_zone_t *zone, void *ptr, size_t size); #endif CFAllocatorRef _allocator; CFAllocatorContext _context; }; CF_INLINE CFAllocatorRetainCallBack __CFAllocatorGetRetainFunction(const CFAllocatorContext *context) { CFAllocatorRetainCallBack retval = NULL; retval = context->retain; return retval; } CF_INLINE CFAllocatorReleaseCallBack __CFAllocatorGetReleaseFunction(const CFAllocatorContext *context) { CFAllocatorReleaseCallBack retval = NULL; retval = context->release; return retval; } CF_INLINE CFAllocatorCopyDescriptionCallBack __CFAllocatorGetCopyDescriptionFunction(const CFAllocatorContext *context) { CFAllocatorCopyDescriptionCallBack retval = NULL; retval = context->copyDescription; return retval; } CF_INLINE CFAllocatorAllocateCallBack __CFAllocatorGetAllocateFunction(const CFAllocatorContext *context) { CFAllocatorAllocateCallBack retval = NULL; retval = context->allocate; return retval; } CF_INLINE CFAllocatorReallocateCallBack __CFAllocatorGetReallocateFunction(const CFAllocatorContext *context) { CFAllocatorReallocateCallBack retval = NULL; retval = context->reallocate; return retval; } CF_INLINE CFAllocatorDeallocateCallBack __CFAllocatorGetDeallocateFunction(const CFAllocatorContext *context) { CFAllocatorDeallocateCallBack retval = NULL; retval = context->deallocate; return retval; } CF_INLINE CFAllocatorPreferredSizeCallBack __CFAllocatorGetPreferredSizeFunction(const CFAllocatorContext *context) { CFAllocatorPreferredSizeCallBack retval = NULL; retval = context->preferredSize; return retval; } #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf); static kern_return_t __CFAllocatorZoneIntrospectNoOp(void) { return 0; } static boolean_t __CFAllocatorZoneIntrospectTrue(void) { return 1; } static size_t __CFAllocatorCustomSize(malloc_zone_t *zone, const void *ptr) { return 0; // The only way to implement this with a version 0 allocator would be // for CFAllocator to keep track of all blocks allocated itself, which // could be done, but would be bad for performance, so we don't do it. // size_t (*size)(struct _malloc_zone_t *zone, const void *ptr); /* returns the size of a block or 0 if not in this zone; * must be fast, especially for negative answers */ } static void *__CFAllocatorCustomMalloc(malloc_zone_t *zone, size_t size) { CFAllocatorRef allocator = (CFAllocatorRef)zone; return CFAllocatorAllocate(allocator, size, 0); } static void *__CFAllocatorCustomCalloc(malloc_zone_t *zone, size_t num_items, size_t size) { CFAllocatorRef allocator = (CFAllocatorRef)zone; void *newptr = CFAllocatorAllocate(allocator, size, 0); if (newptr) memset(newptr, 0, size); return newptr; } static void *__CFAllocatorCustomValloc(malloc_zone_t *zone, size_t size) { CFAllocatorRef allocator = (CFAllocatorRef)zone; if (size >= ULONG_MAX - 2 * vm_page_size) return NULL; // avoid integer overflow plus don't allow all pages to be allocated either void *newptr = CFAllocatorAllocate(allocator, size + vm_page_size, 0); newptr = (void *)round_page((uintptr_t)newptr); return newptr; } static void __CFAllocatorCustomFree(malloc_zone_t *zone, void *ptr) { CFAllocatorRef allocator = (CFAllocatorRef)zone; CFAllocatorDeallocate(allocator, ptr); } static void *__CFAllocatorCustomRealloc(malloc_zone_t *zone, void *ptr, size_t size) { CFAllocatorRef allocator = (CFAllocatorRef)zone; return CFAllocatorReallocate(allocator, ptr, size, 0); } static void __CFAllocatorCustomDestroy(malloc_zone_t *zone) { CFAllocatorRef allocator = (CFAllocatorRef)zone; // !!! we do it, and caller of malloc_destroy_zone() assumes // COMPLETE responsibility for the result; NO Apple library // code should be modified as a result of discovering that // some activity results in inconveniences to developers // trying to use malloc_destroy_zone() with a CFAllocatorRef; // that's just too bad for them. __CFAllocatorDeallocate(allocator); } static size_t __CFAllocatorCustomGoodSize(malloc_zone_t *zone, size_t size) { CFAllocatorRef allocator = (CFAllocatorRef)zone; return CFAllocatorGetPreferredSizeForSize(allocator, size, 0); } static struct malloc_introspection_t __CFAllocatorZoneIntrospect = { (void *)__CFAllocatorZoneIntrospectNoOp, (void *)__CFAllocatorCustomGoodSize, (void *)__CFAllocatorZoneIntrospectTrue, (void *)__CFAllocatorZoneIntrospectNoOp, (void *)__CFAllocatorZoneIntrospectNoOp, (void *)__CFAllocatorZoneIntrospectNoOp, (void *)__CFAllocatorZoneIntrospectNoOp, (void *)__CFAllocatorZoneIntrospectNoOp }; static size_t __CFAllocatorNullSize(malloc_zone_t *zone, const void *ptr) { return 0; } static void * __CFAllocatorNullMalloc(malloc_zone_t *zone, size_t size) { return NULL; } static void * __CFAllocatorNullCalloc(malloc_zone_t *zone, size_t num_items, size_t size) { return NULL; } static void * __CFAllocatorNullValloc(malloc_zone_t *zone, size_t size) { return NULL; } static void __CFAllocatorNullFree(malloc_zone_t *zone, void *ptr) { } static void * __CFAllocatorNullRealloc(malloc_zone_t *zone, void *ptr, size_t size) { return NULL; } static void __CFAllocatorNullDestroy(malloc_zone_t *zone) { } static size_t __CFAllocatorNullGoodSize(malloc_zone_t *zone, size_t size) { return size; } static struct malloc_introspection_t __CFAllocatorNullZoneIntrospect = { (void *)__CFAllocatorZoneIntrospectNoOp, (void *)__CFAllocatorNullGoodSize, (void *)__CFAllocatorZoneIntrospectTrue, (void *)__CFAllocatorZoneIntrospectNoOp, (void *)__CFAllocatorZoneIntrospectNoOp, (void *)__CFAllocatorZoneIntrospectNoOp, (void *)__CFAllocatorZoneIntrospectNoOp, (void *)__CFAllocatorZoneIntrospectNoOp }; static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) { return malloc_zone_malloc(info, size); } static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) { return malloc_zone_realloc(info, ptr, newsize); } static void __CFAllocatorSystemDeallocate(void *ptr, void *info) { #if defined(DEBUG) size_t size = malloc_size(ptr); if (size) memset(ptr, 0xCC, size); #endif malloc_zone_free(info, ptr); } #endif #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) { return malloc(size); } static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) { return realloc(ptr, newsize); } static void __CFAllocatorSystemDeallocate(void *ptr, void *info) { free(ptr); } #endif static void *__CFAllocatorNullAllocate(CFIndex size, CFOptionFlags hint, void *info) { return NULL; } static void *__CFAllocatorNullReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) { return NULL; } #if defined (__cplusplus) static void * __CFAllocatorCPPMalloc(CFIndex allocSize, CFOptionFlags hint, void *info) { return malloc(allocSize); } static void * __CFAllocatorCPPReAlloc(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) { return realloc(ptr, newsize); } static void __CFAllocatorCPPFree(void *ptr, void *info) { free(ptr); } #endif // C++ static struct __CFAllocator __kCFAllocatorMalloc = { INIT_CFRUNTIME_BASE(), #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED __CFAllocatorCustomSize, __CFAllocatorCustomMalloc, __CFAllocatorCustomCalloc, __CFAllocatorCustomValloc, __CFAllocatorCustomFree, __CFAllocatorCustomRealloc, __CFAllocatorNullDestroy, "kCFAllocatorMalloc", NULL, NULL, &__CFAllocatorZoneIntrospect, 6, NULL, NULL, #endif NULL, // _allocator // Using the malloc functions directly is a total cheat, but works (in C) // because the function signatures match in their common prefix of arguments. // This saves us one hop through an adaptor function. #if !defined (__cplusplus) {0, NULL, NULL, NULL, NULL, (void *)malloc, (void *)realloc, (void *)free, NULL} #else {0, NULL, NULL, NULL, NULL, __CFAllocatorCPPMalloc,__CFAllocatorCPPReAlloc, __CFAllocatorCPPFree, NULL} #endif // __cplusplus }; static struct __CFAllocator __kCFAllocatorMallocZone = { INIT_CFRUNTIME_BASE(), #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED __CFAllocatorCustomSize, __CFAllocatorCustomMalloc, __CFAllocatorCustomCalloc, __CFAllocatorCustomValloc, __CFAllocatorCustomFree, __CFAllocatorCustomRealloc, __CFAllocatorNullDestroy, "kCFAllocatorMallocZone", NULL, NULL, &__CFAllocatorZoneIntrospect, 6, NULL, NULL, #endif NULL, // _allocator {0, NULL, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL} }; static struct __CFAllocator __kCFAllocatorSystemDefault = { INIT_CFRUNTIME_BASE(), #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED __CFAllocatorCustomSize, __CFAllocatorCustomMalloc, __CFAllocatorCustomCalloc, __CFAllocatorCustomValloc, __CFAllocatorCustomFree, __CFAllocatorCustomRealloc, __CFAllocatorNullDestroy, "kCFAllocatorSystemDefault", NULL, NULL, &__CFAllocatorZoneIntrospect, 6, NULL, NULL, #endif NULL, // _allocator {0, NULL, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL} }; static struct __CFAllocator __kCFAllocatorNull = { INIT_CFRUNTIME_BASE(), #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED __CFAllocatorNullSize, __CFAllocatorNullMalloc, __CFAllocatorNullCalloc, __CFAllocatorNullValloc, __CFAllocatorNullFree, __CFAllocatorNullRealloc, __CFAllocatorNullDestroy, "kCFAllocatorNull", NULL, NULL, &__CFAllocatorNullZoneIntrospect, 6, NULL, NULL, #endif NULL, // _allocator {0, NULL, NULL, NULL, NULL, __CFAllocatorNullAllocate, __CFAllocatorNullReallocate, NULL, NULL} }; const CFAllocatorRef kCFAllocatorDefault = NULL; const CFAllocatorRef kCFAllocatorSystemDefault = &__kCFAllocatorSystemDefault; const CFAllocatorRef kCFAllocatorMalloc = &__kCFAllocatorMalloc; const CFAllocatorRef kCFAllocatorMallocZone = &__kCFAllocatorMallocZone; const CFAllocatorRef kCFAllocatorNull = &__kCFAllocatorNull; const CFAllocatorRef kCFAllocatorUseContext = (CFAllocatorRef)0x03ab; #undef kCFAllocatorSystemDefaultGCRefZero #undef kCFAllocatorDefaultGCRefZero const CFAllocatorRef kCFAllocatorSystemDefaultGCRefZero = (CFAllocatorRef)0x03ad; const CFAllocatorRef kCFAllocatorDefaultGCRefZero = (CFAllocatorRef)0x03af; static CFStringRef __CFAllocatorCopyDescription(CFTypeRef cf) { CFAllocatorRef self = (CFAllocatorRef)cf; CFAllocatorRef allocator = (kCFAllocatorUseContext == self->_allocator) ? self : self->_allocator; return CFStringCreateWithFormat(allocator, NULL, CFSTR("{info = %p}"), cf, allocator, self->_context.info); // CF: should use copyDescription function here to describe info field // remember to release value returned from copydescr function when this happens } __private_extern__ CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef cf) { CFAllocatorRef allocator = (CFAllocatorRef)cf; return (kCFAllocatorUseContext == allocator->_allocator) ? allocator : allocator->_allocator; } __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf) { CFAllocatorRef self = (CFAllocatorRef)cf; CFAllocatorRef allocator = self->_allocator; CFAllocatorReleaseCallBack releaseFunc = __CFAllocatorGetReleaseFunction(&self->_context); if (kCFAllocatorUseContext == allocator) { /* Rather a chicken and egg problem here, so we do things in the reverse order from what was done at create time. */ CFAllocatorDeallocateCallBack deallocateFunc = __CFAllocatorGetDeallocateFunction(&self->_context); void *info = self->_context.info; if (NULL != deallocateFunc) { INVOKE_CALLBACK2(deallocateFunc, (void *)self, info); } if (NULL != releaseFunc) { INVOKE_CALLBACK1(releaseFunc, info); } } else { if (NULL != releaseFunc) { INVOKE_CALLBACK1(releaseFunc, self->_context.info); } if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) CFAllocatorDeallocate(allocator, (void *)self); } } static CFTypeID __kCFAllocatorTypeID = _kCFRuntimeNotATypeID; static const CFRuntimeClass __CFAllocatorClass = { 0, "CFAllocator", NULL, // init NULL, // copy NULL, NULL, // equal NULL, // hash NULL, // __CFAllocatorCopyDescription }; __private_extern__ void __CFAllocatorInitialize(void) { __kCFAllocatorTypeID = _CFRuntimeRegisterClass(&__CFAllocatorClass); _CFRuntimeSetInstanceTypeID(&__kCFAllocatorSystemDefault, __kCFAllocatorTypeID); __kCFAllocatorSystemDefault._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED __kCFAllocatorSystemDefault._context.info = (kCFUseCollectableAllocator ? objc_collectableZone() : malloc_default_zone()); #endif __kCFAllocatorSystemDefault._allocator = kCFAllocatorSystemDefault; _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMalloc, __kCFAllocatorTypeID); __kCFAllocatorMalloc._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); __kCFAllocatorMalloc._allocator = kCFAllocatorSystemDefault; #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMallocZone, __kCFAllocatorTypeID); __kCFAllocatorMallocZone._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); __kCFAllocatorMallocZone._allocator = kCFAllocatorSystemDefault; __kCFAllocatorMallocZone._context.info = malloc_default_zone(); #endif _CFRuntimeSetInstanceTypeID(&__kCFAllocatorNull, __kCFAllocatorTypeID); __kCFAllocatorNull._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); __kCFAllocatorNull._allocator = kCFAllocatorSystemDefault; } CFTypeID CFAllocatorGetTypeID(void) { return __kCFAllocatorTypeID; } CFAllocatorRef CFAllocatorGetDefault(void) { return __CFGetDefaultAllocator(); } void CFAllocatorSetDefault(CFAllocatorRef allocator) { if (kCFAllocatorSystemDefaultGCRefZero == allocator || kCFAllocatorDefaultGCRefZero == allocator) { HALT; } CFAllocatorRef current = __CFGetDefaultAllocator(); #if defined(DEBUG) if (NULL != allocator) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } #endif #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED if (allocator && allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return; // require allocator to this function to be an allocator } #endif if (NULL != allocator && allocator != current) { if (current) CFRelease(current); CFRetain(allocator); // We retain an extra time so that anything set as the default // allocator never goes away. CFRetain(allocator); _CFSetTSD(__CFTSDKeyAllocator, (void *)allocator, NULL); } } static CFAllocatorRef __CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) { struct __CFAllocator *memory = NULL; CFAllocatorRetainCallBack retainFunc; CFAllocatorAllocateCallBack allocateFunc; void *retainedInfo; #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED if (allocator && kCFAllocatorUseContext != allocator && allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return NULL; // require allocator to this function to be an allocator } #endif retainFunc = context->retain; FAULT_CALLBACK((void **)&retainFunc); allocateFunc = context->allocate; FAULT_CALLBACK((void **)&allocateFunc); if (NULL != retainFunc) { retainedInfo = (void *)INVOKE_CALLBACK1(retainFunc, context->info); } else { retainedInfo = context->info; } // We don't use _CFRuntimeCreateInstance() if (kCFAllocatorUseContext == allocator) { memory = NULL; if (allocateFunc) { memory = (struct __CFAllocator *)INVOKE_CALLBACK3(allocateFunc, sizeof(struct __CFAllocator), 0, retainedInfo); } if (NULL == memory) { return NULL; } } else { allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; memory = (struct __CFAllocator *)CFAllocatorAllocate(allocator, sizeof(struct __CFAllocator), __kCFAllocatorGCObjectMemory); if (NULL == memory) { return NULL; } if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFAllocator"); } memset(memory, 0, sizeof(CFRuntimeBase)); memory->_base._cfisa = 0; #if __LP64__ memory->_base._rc = 1; #else memory->_base._cfinfo[CF_RC_BITS] = 1; #endif memory->_base._cfinfo[CF_INFO_BITS] = 0; _CFRuntimeSetInstanceTypeID(memory, __kCFAllocatorTypeID); memory->_base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED memory->size = __CFAllocatorCustomSize; memory->malloc = __CFAllocatorCustomMalloc; memory->calloc = __CFAllocatorCustomCalloc; memory->valloc = __CFAllocatorCustomValloc; memory->free = __CFAllocatorCustomFree; memory->realloc = __CFAllocatorCustomRealloc; memory->destroy = __CFAllocatorCustomDestroy; memory->zone_name = "Custom CFAllocator"; memory->batch_malloc = NULL; memory->batch_free = NULL; memory->introspect = &__CFAllocatorZoneIntrospect; memory->version = 6; memory->memalign = NULL; memory->free_definite_size = NULL; #endif memory->_allocator = allocator; memory->_context.version = context->version; memory->_context.info = retainedInfo; memory->_context.retain = retainFunc; memory->_context.release = context->release; FAULT_CALLBACK((void **)&(memory->_context.release)); memory->_context.copyDescription = context->copyDescription; FAULT_CALLBACK((void **)&(memory->_context.copyDescription)); memory->_context.allocate = allocateFunc; memory->_context.reallocate = context->reallocate; FAULT_CALLBACK((void **)&(memory->_context.reallocate)); memory->_context.deallocate = context->deallocate; FAULT_CALLBACK((void **)&(memory->_context.deallocate)); memory->_context.preferredSize = context->preferredSize; FAULT_CALLBACK((void **)&(memory->_context.preferredSize)); return memory; } CFAllocatorRef CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) { return __CFAllocatorCreate(allocator, context); } void *CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) { CFAllocatorAllocateCallBack allocateFunc; void *newptr = NULL; Boolean initialRefcountOne = true; if (kCFAllocatorSystemDefaultGCRefZero == allocator) { allocator = kCFAllocatorSystemDefault; initialRefcountOne = false; } else if (kCFAllocatorDefaultGCRefZero == allocator) { // Under GC, we can't use just any old allocator when the GCRefZero allocator was requested allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator(); if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) initialRefcountOne = false; } else if (NULL == allocator) { allocator = __CFGetDefaultAllocator(); } #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } #else __CFGenericValidateType(allocator, __kCFAllocatorTypeID); #endif if (0 == size) return NULL; #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return malloc_zone_malloc((malloc_zone_t *)allocator, size); } #endif if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { newptr = auto_zone_allocate_object((auto_zone_t*)allocator->_context.info, size, CF_GET_GC_MEMORY_TYPE(hint), initialRefcountOne, false); } else { newptr = NULL; allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context); if (allocateFunc) { newptr = (void *)INVOKE_CALLBACK3(allocateFunc, size, hint, allocator->_context.info); } } return newptr; } void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint) { CFAllocatorAllocateCallBack allocateFunc; CFAllocatorReallocateCallBack reallocateFunc; CFAllocatorDeallocateCallBack deallocateFunc; void *newptr; if (kCFAllocatorSystemDefaultGCRefZero == allocator) { allocator = kCFAllocatorSystemDefault; } else if (kCFAllocatorDefaultGCRefZero == allocator) { // Under GC, we can't use just any old allocator when the GCRefZero allocator was requested allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator(); } else if (NULL == allocator) { allocator = __CFGetDefaultAllocator(); } #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } #else __CFGenericValidateType(allocator, __kCFAllocatorTypeID); #endif if (NULL == ptr && 0 < newsize) { #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return malloc_zone_malloc((malloc_zone_t *)allocator, newsize); } #endif newptr = NULL; allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context); if (allocateFunc) { newptr = (void *)INVOKE_CALLBACK3(allocateFunc, newsize, hint, allocator->_context.info); } return newptr; } if (NULL != ptr && 0 == newsize) { #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * #if defined(DEBUG) size_t size = malloc_size(ptr); if (size) memset(ptr, 0xCC, size); #endif malloc_zone_free((malloc_zone_t *)allocator, ptr); return NULL; } #endif deallocateFunc = __CFAllocatorGetDeallocateFunction(&allocator->_context); if (NULL != deallocateFunc) { INVOKE_CALLBACK2(deallocateFunc, ptr, allocator->_context.info); } return NULL; } if (NULL == ptr && 0 == newsize) return NULL; #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return malloc_zone_realloc((malloc_zone_t *)allocator, ptr, newsize); } #endif reallocateFunc = __CFAllocatorGetReallocateFunction(&allocator->_context); if (NULL == reallocateFunc) return NULL; newptr = (void *)INVOKE_CALLBACK4(reallocateFunc, ptr, newsize, hint, allocator->_context.info); return newptr; } void CFAllocatorDeallocate(CFAllocatorRef allocator, void *ptr) { CFAllocatorDeallocateCallBack deallocateFunc; if (kCFAllocatorSystemDefaultGCRefZero == allocator) { if (_CFAllocatorIsGCRefZero(allocator)) return; allocator = kCFAllocatorSystemDefault; } else if (kCFAllocatorDefaultGCRefZero == allocator) { // Under GC, we can't use just any old allocator when the GCRefZero allocator was requested allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator(); if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) return; } else if (NULL == allocator) { allocator = __CFGetDefaultAllocator(); } #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } #else __CFGenericValidateType(allocator, __kCFAllocatorTypeID); #endif #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * #if defined(DEBUG) size_t size = malloc_size(ptr); if (size) memset(ptr, 0xCC, size); #endif return malloc_zone_free((malloc_zone_t *)allocator, ptr); } #endif deallocateFunc = __CFAllocatorGetDeallocateFunction(&allocator->_context); if (NULL != ptr && NULL != deallocateFunc) { INVOKE_CALLBACK2(deallocateFunc, ptr, allocator->_context.info); } } CFIndex CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) { CFAllocatorPreferredSizeCallBack prefFunc; CFIndex newsize = 0; if (kCFAllocatorSystemDefaultGCRefZero == allocator) { allocator = kCFAllocatorSystemDefault; } else if (kCFAllocatorDefaultGCRefZero == allocator) { // Under GC, we can't use just any old allocator when the GCRefZero allocator was requested allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator(); } else if (NULL == allocator) { allocator = __CFGetDefaultAllocator(); } #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } #else __CFGenericValidateType(allocator, __kCFAllocatorTypeID); #endif #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return malloc_good_size(size); } #endif prefFunc = __CFAllocatorGetPreferredSizeFunction(&allocator->_context); if (0 < size && NULL != prefFunc) { newsize = (CFIndex)(INVOKE_CALLBACK3(prefFunc, size, hint, allocator->_context.info)); } if (newsize < size) newsize = size; return newsize; } void CFAllocatorGetContext(CFAllocatorRef allocator, CFAllocatorContext *context) { if (kCFAllocatorSystemDefaultGCRefZero == allocator) { allocator = kCFAllocatorSystemDefault; } else if (kCFAllocatorDefaultGCRefZero == allocator) { // Under GC, we can't use just any old allocator when the GCRefZero allocator was requested allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator(); } else if (NULL == allocator) { allocator = __CFGetDefaultAllocator(); } #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } #else __CFGenericValidateType(allocator, __kCFAllocatorTypeID); #endif CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__); #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return; } #endif context->version = 0; context->info = allocator->_context.info; context->retain = __CFAllocatorGetRetainFunction(&allocator->_context); context->release = __CFAllocatorGetReleaseFunction(&allocator->_context); context->copyDescription = __CFAllocatorGetCopyDescriptionFunction(&allocator->_context); context->allocate = __CFAllocatorGetAllocateFunction(&allocator->_context); context->reallocate = __CFAllocatorGetReallocateFunction(&allocator->_context); context->deallocate = __CFAllocatorGetDeallocateFunction(&allocator->_context); context->preferredSize = __CFAllocatorGetPreferredSizeFunction(&allocator->_context); #if SUPPORT_CFM context->retain = (void *)((uintptr_t)context->retain & ~0x3); context->release = (void *)((uintptr_t)context->release & ~0x3); context->copyDescription = (void *)((uintptr_t)context->copyDescription & ~0x3); context->allocate = (void *)((uintptr_t)context->allocate & ~0x3); context->reallocate = (void *)((uintptr_t)context->reallocate & ~0x3); context->deallocate = (void *)((uintptr_t)context->deallocate & ~0x3); context->preferredSize = (void *)((uintptr_t)context->preferredSize & ~0x3); #endif } __private_extern__ void *_CFAllocatorAllocateGC(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) { if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, size, CF_GET_GC_MEMORY_TYPE(hint), false, false); else return CFAllocatorAllocate(allocator, size, hint); } __private_extern__ void *_CFAllocatorReallocateGC(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint) { if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { if (ptr && (newsize == 0)) { return NULL; // equivalent to _CFAllocatorDeallocateGC. } if (ptr == NULL) { return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, newsize, CF_GET_GC_MEMORY_TYPE(hint), false, false); // eq. to _CFAllocator } } // otherwise, auto_realloc() now preserves layout type and refCount. return CFAllocatorReallocate(allocator, ptr, newsize, hint); } __private_extern__ void _CFAllocatorDeallocateGC(CFAllocatorRef allocator, void *ptr) { // when running GC, don't deallocate. if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) CFAllocatorDeallocate(allocator, ptr); } // -------- -------- -------- -------- -------- -------- -------- -------- CFRange __CFRangeMake(CFIndex loc, CFIndex len) { CFRange range; range.location = loc; range.length = len; return range; } struct __CFNull { CFRuntimeBase _base; }; static struct __CFNull __kCFNull = { INIT_CFRUNTIME_BASE() }; const CFNullRef kCFNull = &__kCFNull; static CFStringRef __CFNullCopyDescription(CFTypeRef cf) { return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR(""), cf, CFGetAllocator(cf)); } static CFStringRef __CFNullCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { return (CFStringRef)CFRetain(CFSTR("null")); } static void __CFNullDeallocate(CFTypeRef cf) { CFAssert(false, __kCFLogAssertion, "Deallocated CFNull!"); } static CFTypeID __kCFNullTypeID = _kCFRuntimeNotATypeID; static const CFRuntimeClass __CFNullClass = { 0, "CFNull", NULL, // init NULL, // copy __CFNullDeallocate, NULL, NULL, __CFNullCopyFormattingDescription, __CFNullCopyDescription }; __private_extern__ void __CFNullInitialize(void) { __kCFNullTypeID = _CFRuntimeRegisterClass(&__CFNullClass); _CFRuntimeSetInstanceTypeID(&__kCFNull, __kCFNullTypeID); __kCFNull._base._cfisa = __CFISAForTypeID(__kCFNullTypeID); } CFTypeID CFNullGetTypeID(void) { return __kCFNullTypeID; } void CFCollection_non_gc_storage_error(void) { } #if !SUPPORT_CFM void _CFRuntimeSetCFMPresent(void *addr) { } #endif #if SUPPORT_CFM static int hasCFM = 0; void _CFRuntimeSetCFMPresent(void *addr) { hasCFM = 1; } /* See comments below */ __private_extern__ void __CF_FAULT_CALLBACK(void **ptr) { uintptr_t p = (uintptr_t)*ptr; if ((0 == p) || (p & 0x1)) return; if (0 == hasCFM || (0x90000000 <= p && p < 0xA0000000)) { *ptr = (void *)(p | 0x1); } else { uintptr_t known = ~0; Dl_info info; known = dladdr((void *)p, &info); *ptr = (void *)(p | (known ? 0x1 : 0x3)); } } /* Jump to callback function. r2 is not saved and restored in the jump-to-CFM case, since we assume that dyld code never uses that register and that CF is dyld. There are three states for (ptr & 0x3): 0b00: check not yet done (or not going to be done, and is a dyld func ptr) 0b01: check done, dyld function pointer 0b11: check done, CFM tvector pointer (but a NULL callback just stays NULL) There may be up to 5 word-sized arguments. Floating point arguments can be done, but count as two word arguments. Return value can be integral or real. */ /* Keep this assembly at the bottom of the source file! */ __asm__ ( ".text\n" " .align 2\n" ".private_extern ___CF_INVOKE_CALLBACK\n" "___CF_INVOKE_CALLBACK:\n" "rlwinm r12,r3,0,0,29\n" "andi. r0,r3,0x2\n" "or r3,r4,r4\n" "or r4,r5,r5\n" "or r5,r6,r6\n" "or r6,r7,r7\n" "or r7,r8,r8\n" "beq- Lcall\n" "lwz r2,0x4(r12)\n" "lwz r12,0x0(r12)\n" "Lcall: mtspr ctr,r12\n" "bctr\n"); #endif // void __HALT(void); /* Keep this assembly at the bottom of the source file! */ extern void __HALT() { #if defined(__ppc__) __asm__("trap"); #elif defined(__i386__) || defined(__x86_64__) #if defined(_MSC_VER) __asm int 3; #else __asm__("int3"); #endif #endif }