| /* |
| * Copyright (c) 2008-2009 Brent Fulgham <bfulgham@gmail.org>. All rights reserved. |
| * Copyright (c) 2009 Grant Erickson <gerickson@nuovations.com>. All rights reserved. |
| * |
| * This source code is a modified version of the CoreFoundation sources released by Apple Inc. under |
| * the terms of the APSL version 2.0 (see below). |
| * |
| * For information about changes from the original Apple source release can be found by reviewing the |
| * source control system for the project at https://sourceforge.net/svn/?group_id=246198. |
| * |
| * The original license information is as follows: |
| * |
| * Copyright (c) 2008 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 1998-2002, Apple, Inc. All rights reserved. |
| Responsibility: Christopher Kane |
| */ |
| |
| #include <CoreFoundation/CFBase.h> |
| #include "CFInternal.h" |
| #if DEPLOYMENT_TARGET_MACOSX |
| #include <pthread.h> |
| #include <malloc/malloc.h> |
| #include <mach/mach.h> |
| #include <dlfcn.h> |
| #elif DEPLOYMENT_TARGET_LINUX |
| #if defined(DEBUG) |
| #include <mcheck.h> |
| #endif |
| #include <pthread.h> |
| #elif DEPLOYMENT_TARGET_WINDOWS |
| #include <windows.h> |
| #endif |
| #include <stdlib.h> |
| #include <string.h> |
| |
| extern size_t malloc_good_size(size_t size); |
| |
| #if defined(__CYGWIN32__) || defined (D__CYGWIN_) |
| #error CoreFoundation is currently built with the Microsoft C Runtime, which is incompatible with the Cygwin DLL. You must either use the -mno-cygwin flag, or complete a port of CF to the Cygwin environment. |
| #endif |
| |
| // -------- -------- -------- -------- -------- -------- -------- -------- |
| |
| // CFAllocator structure must match struct _malloc_zone_t! |
| // The first two reserved fields in struct _malloc_zone_t are for us with CFRuntimeBase |
| struct __CFAllocator { |
| CFRuntimeBase _base; |
| #if DEPLOYMENT_TARGET_MACOSX |
| 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; |
| 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; |
| void *reserved5; |
| #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 |
| |
| __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; |
| 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); |
| } |
| |
| // These should live in the malloc.h heaer file |
| typedef double (*Fx)(double); |
| typedef kern_return_t (*mit_EnumType)(task_t task, void *, unsigned type_mask, vm_address_t zone_address, memory_reader_t reader, vm_range_recorder_t recorder); |
| typedef size_t (*mit_GoodSize)(malloc_zone_t *zone, size_t size); |
| typedef boolean_t (*mit_Check)(malloc_zone_t *zone); |
| typedef void (*mit_Print)(malloc_zone_t *zone, boolean_t verbose); |
| typedef void (*mit_Log)(malloc_zone_t *zone, void *address); |
| typedef void (*mit_ZoneAction)(malloc_zone_t *zone); |
| typedef void (*mit_Statistics)(malloc_zone_t *zone, malloc_statistics_t *stats); |
| |
| static struct malloc_introspection_t __CFAllocatorZoneIntrospect = { |
| (mit_EnumType)__CFAllocatorZoneIntrospectNoOp, |
| (mit_GoodSize)__CFAllocatorCustomGoodSize, |
| (mit_Check)__CFAllocatorZoneIntrospectTrue, |
| (mit_Print)__CFAllocatorZoneIntrospectNoOp, |
| (mit_Log)__CFAllocatorZoneIntrospectNoOp, |
| (mit_ZoneAction)__CFAllocatorZoneIntrospectNoOp, |
| (mit_ZoneAction)__CFAllocatorZoneIntrospectNoOp, |
| (mit_Statistics)__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 = { |
| (mit_EnumType)__CFAllocatorZoneIntrospectNoOp, |
| (mit_GoodSize)__CFAllocatorNullGoodSize, |
| (mit_Check)__CFAllocatorZoneIntrospectTrue, |
| (mit_Print)__CFAllocatorZoneIntrospectNoOp, |
| (mit_Log)__CFAllocatorZoneIntrospectNoOp, |
| (mit_ZoneAction)__CFAllocatorZoneIntrospectNoOp, |
| (mit_ZoneAction)__CFAllocatorZoneIntrospectNoOp, |
| (mit_Statistics)__CFAllocatorZoneIntrospectNoOp |
| }; |
| |
| static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) { |
| return malloc_zone_malloc((malloc_zone_t*)info, size); |
| } |
| |
| static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) { |
| return malloc_zone_realloc((malloc_zone_t*)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((malloc_zone_t*)info, ptr); |
| } |
| |
| #endif /* DEPLOYMENT_TARGET_MACOSX */ |
| |
| #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) { |
| #if defined(DEBUG) |
| const enum mcheck_status status = mprobe(ptr); |
| |
| CFAssert3(status == MCHECK_OK || status == MCHECK_DISABLED, |
| __kCFLogAssertion, "%s: ptr %p status %d", |
| __PRETTY_FUNCTION__, ptr, status); |
| #endif |
| |
| 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 |
| __CFAllocatorCustomSize, |
| __CFAllocatorCustomMalloc, |
| __CFAllocatorCustomCalloc, |
| __CFAllocatorCustomValloc, |
| __CFAllocatorCustomFree, |
| __CFAllocatorCustomRealloc, |
| __CFAllocatorNullDestroy, |
| "kCFAllocatorMalloc", |
| NULL, |
| NULL, |
| &__CFAllocatorZoneIntrospect, |
| 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 |
| __CFAllocatorCustomSize, |
| __CFAllocatorCustomMalloc, |
| __CFAllocatorCustomCalloc, |
| __CFAllocatorCustomValloc, |
| __CFAllocatorCustomFree, |
| __CFAllocatorCustomRealloc, |
| __CFAllocatorNullDestroy, |
| "kCFAllocatorMallocZone", |
| NULL, |
| NULL, |
| &__CFAllocatorZoneIntrospect, |
| NULL, |
| #endif |
| NULL, // _allocator |
| {0, NULL, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL} |
| }; |
| |
| static struct __CFAllocator __kCFAllocatorSystemDefault = { |
| INIT_CFRUNTIME_BASE(), |
| #if DEPLOYMENT_TARGET_MACOSX |
| __CFAllocatorCustomSize, |
| __CFAllocatorCustomMalloc, |
| __CFAllocatorCustomCalloc, |
| __CFAllocatorCustomValloc, |
| __CFAllocatorCustomFree, |
| __CFAllocatorCustomRealloc, |
| __CFAllocatorNullDestroy, |
| "kCFAllocatorSystemDefault", |
| NULL, |
| NULL, |
| &__CFAllocatorZoneIntrospect, |
| NULL, |
| #endif |
| NULL, // _allocator |
| {0, NULL, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL} |
| }; |
| |
| static struct __CFAllocator __kCFAllocatorNull = { |
| INIT_CFRUNTIME_BASE(), |
| #if DEPLOYMENT_TARGET_MACOSX |
| __CFAllocatorNullSize, |
| __CFAllocatorNullMalloc, |
| __CFAllocatorNullCalloc, |
| __CFAllocatorNullValloc, |
| __CFAllocatorNullFree, |
| __CFAllocatorNullRealloc, |
| __CFAllocatorNullDestroy, |
| "kCFAllocatorNull", |
| NULL, |
| NULL, |
| &__CFAllocatorNullZoneIntrospect, |
| 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)0x0257; |
| |
| static CFStringRef __CFAllocatorCopyDescription(CFTypeRef cf) { |
| CFAllocatorRef self = (CFAllocatorRef)cf; |
| CFAllocatorRef allocator = (kCFAllocatorUseContext == self->_allocator) ? self : self->_allocator; |
| return CFStringCreateWithFormat(allocator, NULL, CFSTR("<CFAllocator %p [%p]>{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); |
| } |
| _CFAllocatorDeallocateGC(allocator, (void *)self); |
| } |
| } |
| |
| static CFTypeID __kCFAllocatorTypeID = _kCFRuntimeNotATypeID; |
| |
| static const CFRuntimeClass __CFAllocatorClass = { |
| 0, |
| "CFAllocator", |
| NULL, // init |
| NULL, // copy |
| __CFAllocatorDeallocate, |
| 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 |
| __kCFAllocatorSystemDefault._context.info = (CF_USING_COLLECTABLE_MEMORY ? __CFCollectableZone : malloc_default_zone()); |
| memset(malloc_default_zone(), 0, 2 * sizeof(void *)); |
| #endif |
| __kCFAllocatorSystemDefault._allocator = kCFAllocatorSystemDefault; |
| #ifdef DEPLOYMENT_TARGET_WINDOWS |
| __kCFAllocatorSystemDefault._context.allocate = __CFAllocatorSystemAllocate; |
| __kCFAllocatorSystemDefault._context.reallocate = __CFAllocatorSystemReallocate; |
| __kCFAllocatorSystemDefault._context.deallocate = __CFAllocatorSystemDeallocate; |
| #endif // DEPLOYMENT_TARGET_WINDOWS |
| |
| _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMalloc, __kCFAllocatorTypeID); |
| __kCFAllocatorMalloc._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); |
| __kCFAllocatorMalloc._allocator = kCFAllocatorSystemDefault; |
| |
| #if DEPLOYMENT_TARGET_MACOSX |
| _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMallocZone, __kCFAllocatorTypeID); |
| __kCFAllocatorMallocZone._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); |
| __kCFAllocatorMallocZone._allocator = kCFAllocatorSystemDefault; |
| __kCFAllocatorMallocZone._context.info = malloc_default_zone(); |
| #endif //__MACH__ |
| |
| _CFRuntimeSetInstanceTypeID(&__kCFAllocatorNull, __kCFAllocatorTypeID); |
| __kCFAllocatorNull._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); |
| __kCFAllocatorNull._allocator = kCFAllocatorSystemDefault; |
| |
| } |
| |
| CFTypeID CFAllocatorGetTypeID(void) { |
| return __kCFAllocatorTypeID; |
| } |
| |
| CFAllocatorRef CFAllocatorGetDefault(void) { |
| CFAllocatorRef allocator = (CFAllocatorRef)__CFGetThreadSpecificData_inline()->_allocator; |
| if (NULL == allocator) { |
| allocator = kCFAllocatorSystemDefault; |
| } |
| return allocator; |
| } |
| |
| void CFAllocatorSetDefault(CFAllocatorRef allocator) { |
| CFAllocatorRef current = (CFAllocatorRef)__CFGetThreadSpecificData_inline()->_allocator; |
| #if defined(DEBUG) |
| if (NULL != allocator) { |
| __CFGenericValidateType(allocator, __kCFAllocatorTypeID); |
| } |
| #endif |
| #if DEPLOYMENT_TARGET_MACOSX |
| 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); |
| __CFGetThreadSpecificData_inline()->_allocator = (void *)allocator; |
| } |
| } |
| |
| static CFAllocatorRef __CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) { |
| struct __CFAllocator *memory = NULL; |
| CFAllocatorRetainCallBack retainFunc; |
| CFAllocatorAllocateCallBack allocateFunc; |
| void *retainedInfo; |
| #if DEPLOYMENT_TARGET_MACOSX |
| 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 (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFAllocator"); |
| if (NULL == memory) { |
| return NULL; |
| } |
| } |
| 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 |
| 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->reserved5 = 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) { |
| CFAssert1(!CF_USING_COLLECTABLE_MEMORY, __kCFLogAssertion, "%s(): Shouldn't be called when GC is enabled!", __PRETTY_FUNCTION__); |
| #if defined(DEBUG) |
| if (CF_USING_COLLECTABLE_MEMORY) |
| HALT; |
| #endif |
| return __CFAllocatorCreate(allocator, context); |
| } |
| |
| CFAllocatorRef _CFAllocatorCreateGC(CFAllocatorRef allocator, CFAllocatorContext *context) { |
| return __CFAllocatorCreate(allocator, context); |
| } |
| |
| void *CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) { |
| CFAllocatorAllocateCallBack allocateFunc; |
| void *newptr = NULL; |
| allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; |
| #if (DEPLOYMENT_TARGET_MACOSX) && defined(DEBUG) |
| if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { |
| __CFGenericValidateType(allocator, __kCFAllocatorTypeID); |
| } |
| #else |
| __CFGenericValidateType(allocator, __kCFAllocatorTypeID); |
| #endif |
| if (0 == size) return NULL; |
| #if DEPLOYMENT_TARGET_MACOSX |
| 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), true, 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; |
| allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; |
| #if (DEPLOYMENT_TARGET_MACOSX) && defined(DEBUG) |
| if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { |
| __CFGenericValidateType(allocator, __kCFAllocatorTypeID); |
| } |
| #else |
| __CFGenericValidateType(allocator, __kCFAllocatorTypeID); |
| #endif |
| if (NULL == ptr && 0 < newsize) { |
| #if DEPLOYMENT_TARGET_MACOSX |
| 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 |
| 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 /* DEPLOYMENT_TARGET_MACOSX */ |
| 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 |
| 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; |
| allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; |
| #if (DEPLOYMENT_TARGET_MACOSX) && defined(DEBUG) |
| if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { |
| __CFGenericValidateType(allocator, __kCFAllocatorTypeID); |
| } |
| #else |
| __CFGenericValidateType(allocator, __kCFAllocatorTypeID); |
| #endif |
| #if DEPLOYMENT_TARGET_MACOSX |
| 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 /* DEPLOYMENT_TARGET_MACOSX */ |
| 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; |
| allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; |
| #if (DEPLOYMENT_TARGET_MACOSX) && defined(DEBUG) |
| if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { |
| __CFGenericValidateType(allocator, __kCFAllocatorTypeID); |
| } |
| #else |
| __CFGenericValidateType(allocator, __kCFAllocatorTypeID); |
| #endif |
| #if DEPLOYMENT_TARGET_MACOSX |
| 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) { |
| allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; |
| #if (DEPLOYMENT_TARGET_MACOSX) && defined(DEBUG) |
| 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 |
| 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 (DEPLOYMENT_TARGET_MACOSX) && defined(__ppc__) |
| 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 |
| } |
| |
| 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); |
| } |
| |
| 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); |
| } |
| |
| void _CFAllocatorDeallocateGC(CFAllocatorRef allocator, void *ptr) |
| { |
| // when running GC, don't deallocate. |
| if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) CFAllocatorDeallocate(allocator, ptr); |
| } |
| |
| // -------- -------- -------- -------- -------- -------- -------- -------- |
| |
| #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD |
| __private_extern__ pthread_key_t __CFTSDKey = (pthread_key_t)NULL; |
| #elif DEPLOYMENT_TARGET_WINDOWS |
| __private_extern__ DWORD __CFTSDKey = 0xFFFFFFFF; |
| #endif |
| |
| extern void _CFRunLoop1(void); |
| |
| // Called for each thread as it exits |
| __private_extern__ void __CFFinalizeThreadData(void *arg) { |
| #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD |
| __CFThreadSpecificData *tsd = (__CFThreadSpecificData *)arg; |
| #elif DEPLOYMENT_TARGET_WINDOWS |
| __CFThreadSpecificData *tsd = (__CFThreadSpecificData*)TlsGetValue(__CFTSDKey); |
| TlsSetValue(__CFTSDKey, NULL); |
| #endif |
| if (NULL == tsd) return; |
| if (tsd->_allocator) CFRelease(tsd->_allocator); |
| #if DEPLOYMENT_TARGET_MACOSX |
| _CFRunLoop1(); |
| #endif |
| #if DEPLOYMENT_TARGET_WINDOWS || 0 |
| |
| if (tsd->_messageHook) UnhookWindowsHookEx(tsd->_messageHook); |
| |
| #endif |
| |
| CFAllocatorDeallocate(kCFAllocatorSystemDefault, tsd); |
| } |
| |
| __private_extern__ __CFThreadSpecificData *__CFGetThreadSpecificData(void) { |
| #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD |
| __CFThreadSpecificData *data; |
| data = (__CFThreadSpecificData*)pthread_getspecific(__CFTSDKey); |
| if (data) { |
| return data; |
| } |
| data =(__CFThreadSpecificData*)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFThreadSpecificData), 0); |
| if (__CFOASafe) __CFSetLastAllocationEventName(data, "CFUtilities (thread-data)"); |
| memset(data, 0, sizeof(__CFThreadSpecificData)); |
| pthread_setspecific(__CFTSDKey, data); |
| return data; |
| #elif DEPLOYMENT_TARGET_WINDOWS |
| __CFThreadSpecificData *data; |
| data = (__CFThreadSpecificData *)TlsGetValue(__CFTSDKey); |
| if (data) { |
| return data; |
| } |
| data = (__CFThreadSpecificData *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFThreadSpecificData), 0); |
| if (__CFOASafe) __CFSetLastAllocationEventName(data, "CFUtilities (thread-data)"); |
| memset(data, 0, sizeof(__CFThreadSpecificData)); |
| TlsSetValue(__CFTSDKey, data); |
| return data; |
| #endif |
| } |
| |
| __private_extern__ void __CFBaseInitialize(void) { |
| #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD |
| pthread_key_create(&__CFTSDKey, __CFFinalizeThreadData); |
| #elif DEPLOYMENT_TARGET_WINDOWS || 0 |
| __CFTSDKey = TlsAlloc(); |
| #endif |
| } |
| |
| #if DEPLOYMENT_TARGET_WINDOWS || 0 |
| __private_extern__ void __CFBaseCleanup(void) { |
| TlsFree(__CFTSDKey); |
| } |
| #endif |
| |
| |
| static CFBadErrorCallBack __CFOutOfMemoryCallBack = NULL; |
| |
| CFBadErrorCallBack _CFGetOutOfMemoryErrorCallBack(void) { |
| return __CFOutOfMemoryCallBack; |
| } |
| |
| void _CFSetOutOfMemoryErrorCallBack(CFBadErrorCallBack callBack) { |
| __CFOutOfMemoryCallBack = callBack; |
| } |
| |
| |
| 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("<CFNull %p [%p]>"), 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) { } |
| |
| |
| static int hasCFM = 0; |
| |
| void _CFRuntimeSetCFMPresent(void *addr) { |
| hasCFM = 1; |
| } |
| |
| #if (DEPLOYMENT_TARGET_MACOSX) && defined(__ppc__) |
| |
| /* 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 { |
| static CFMutableDictionaryRef cache = NULL; |
| static CFSpinLock_t lock = CFSpinLockInit; |
| uintptr_t known = ~0; |
| __CFSpinLock(&lock); |
| if (!cache || !CFDictionaryGetValueIfPresent(cache, (const void *)p, (const void **)&known)) { |
| if (!cache) { |
| cache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); |
| } |
| Dl_info info; |
| known = dladdr((void *)p, &info); |
| CFDictionarySetValue(cache, (const void *)p, (const void *)known); |
| } |
| __CFSpinUnlock(&lock); |
| *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); |
| |
| #if defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) |
| __asm__ ( |
| ".text\n" |
| " .align 2\n" |
| #if DEPLOYMENT_TARGET_MACOSX |
| ".private_extern ___HALT\n" |
| "___HALT:\n" |
| #elif DEPLOYMENT_TARGET_LINUX |
| ".globl __HALT\n" |
| "__HALT:\n" |
| #else |
| ".globl ___HALT\n" |
| "___HALT:\n" |
| #endif |
| " trap\n" |
| ); |
| #endif |
| |
| #if defined(__i386__) || defined(__x86_64__) |
| #if defined(_MSC_VER) |
| void __HALT() { |
| __asm int 3; |
| } |
| #else |
| __asm__ ( |
| ".text\n" |
| " .align 2, 0x90\n" |
| #if DEPLOYMENT_TARGET_MACOSX |
| ".private_extern ___HALT\n" |
| "___HALT:\n" |
| #elif DEPLOYMENT_TARGET_LINUX |
| ".globl __HALT\n" |
| "__HALT:\n" |
| #else |
| ".globl ___HALT\n" |
| "___HALT:\n" |
| #endif |
| " int3\n" |
| ); |
| #endif |
| #endif |
| |
| #if defined(__arm__) |
| __asm__ ( |
| ".text\n" |
| " .align 2\n" |
| #if DEPLOYMENT_TARGET_MACOSX |
| ".private_extern ___HALT\n" |
| "___HALT:\n" |
| #elif DEPLOYMENT_TARGET_LINUX |
| ".globl __HALT\n" |
| "__HALT:\n" |
| #else |
| ".globl ___HALT\n" |
| "___HALT:\n" |
| #endif |
| " bkpt\n" |
| ); |
| #endif /* defined(__arm__) */ |
| |
| #if defined(__aarch64__) |
| __asm__ ( |
| ".text\n" |
| " .align 2\n" |
| #if DEPLOYMENT_TARGET_MACOSX |
| ".private_extern ___HALT\n" |
| "___HALT:\n" |
| #elif DEPLOYMENT_TARGET_LINUX |
| ".globl __HALT\n" |
| "__HALT:\n" |
| #else |
| ".globl ___HALT\n" |
| "___HALT:\n" |
| #endif |
| " brk #0000\n" |
| ); |
| #endif /* defined(__aarch64__) */ |