2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 Copyright 1998-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
28 #include <CoreFoundation/CFBase.h>
29 #include "CFInternal.h"
30 #if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
35 #if defined(__WIN32__)
39 #include <malloc/malloc.h>
40 extern size_t malloc_good_size(size_t size
);
41 #include <mach/mach.h>
47 #if defined(__CYGWIN32__) || defined (D__CYGWIN_)
48 #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.
51 // -------- -------- -------- -------- -------- -------- -------- --------
54 // CFAllocator structure must match struct _malloc_zone_t!
55 // The first two reserved fields in struct _malloc_zone_t are for us with CFRuntimeBase
57 struct __CFAllocator
{
60 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 */
61 void *(*malloc
)(struct _malloc_zone_t
*zone
, size_t size
);
62 void *(*calloc
)(struct _malloc_zone_t
*zone
, size_t num_items
, size_t size
); /* same as malloc, but block returned is set to zero */
63 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 */
64 void (*free
)(struct _malloc_zone_t
*zone
, void *ptr
);
65 void *(*realloc
)(struct _malloc_zone_t
*zone
, void *ptr
, size_t size
);
66 void (*destroy
)(struct _malloc_zone_t
*zone
); /* zone is destroyed and all memory reclaimed */
67 const char *zone_name
;
68 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) */
69 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 */
70 struct malloc_introspection_t
*introspect
;
73 CFAllocatorRef _allocator
;
74 CFAllocatorContext _context
;
77 CF_INLINE CFAllocatorRetainCallBack
__CFAllocatorGetRetainFunction(const CFAllocatorContext
*context
) {
78 CFAllocatorRetainCallBack retval
= NULL
;
79 retval
= context
->retain
;
83 CF_INLINE CFAllocatorReleaseCallBack
__CFAllocatorGetReleaseFunction(const CFAllocatorContext
*context
) {
84 CFAllocatorReleaseCallBack retval
= NULL
;
85 retval
= context
->release
;
89 CF_INLINE CFAllocatorCopyDescriptionCallBack
__CFAllocatorGetCopyDescriptionFunction(const CFAllocatorContext
*context
) {
90 CFAllocatorCopyDescriptionCallBack retval
= NULL
;
91 retval
= context
->copyDescription
;
95 CF_INLINE CFAllocatorAllocateCallBack
__CFAllocatorGetAllocateFunction(const CFAllocatorContext
*context
) {
96 CFAllocatorAllocateCallBack retval
= NULL
;
97 retval
= context
->allocate
;
101 CF_INLINE CFAllocatorReallocateCallBack
__CFAllocatorGetReallocateFunction(const CFAllocatorContext
*context
) {
102 CFAllocatorReallocateCallBack retval
= NULL
;
103 retval
= context
->reallocate
;
107 CF_INLINE CFAllocatorDeallocateCallBack
__CFAllocatorGetDeallocateFunction(const CFAllocatorContext
*context
) {
108 CFAllocatorDeallocateCallBack retval
= NULL
;
109 retval
= context
->deallocate
;
113 CF_INLINE CFAllocatorPreferredSizeCallBack
__CFAllocatorGetPreferredSizeFunction(const CFAllocatorContext
*context
) {
114 CFAllocatorPreferredSizeCallBack retval
= NULL
;
115 retval
= context
->preferredSize
;
119 #if defined(__MACH__)
121 __private_extern__
void __CFAllocatorDeallocate(CFTypeRef cf
);
123 static kern_return_t
__CFAllocatorZoneIntrospectNoOp(void) {
127 static boolean_t
__CFAllocatorZoneIntrospectTrue(void) {
131 static size_t __CFAllocatorCustomSize(malloc_zone_t
*zone
, const void *ptr
) {
134 // The only way to implement this with a version 0 allocator would be
135 // for CFAllocator to keep track of all blocks allocated itself, which
136 // could be done, but would be bad for performance, so we don't do it.
137 // size_t (*size)(struct _malloc_zone_t *zone, const void *ptr);
138 /* returns the size of a block or 0 if not in this zone;
139 * must be fast, especially for negative answers */
142 static void *__CFAllocatorCustomMalloc(malloc_zone_t
*zone
, size_t size
) {
143 CFAllocatorRef allocator
= (CFAllocatorRef
)zone
;
144 return CFAllocatorAllocate(allocator
, size
, 0);
147 static void *__CFAllocatorCustomCalloc(malloc_zone_t
*zone
, size_t num_items
, size_t size
) {
148 CFAllocatorRef allocator
= (CFAllocatorRef
)zone
;
149 void *newptr
= CFAllocatorAllocate(allocator
, size
, 0);
150 if (newptr
) memset(newptr
, 0, size
);
154 static void *__CFAllocatorCustomValloc(malloc_zone_t
*zone
, size_t size
) {
155 CFAllocatorRef allocator
= (CFAllocatorRef
)zone
;
156 void *newptr
= CFAllocatorAllocate(allocator
, size
+ vm_page_size
, 0);
157 newptr
= (void *)round_page((unsigned)newptr
);
161 static void __CFAllocatorCustomFree(malloc_zone_t
*zone
, void *ptr
) {
162 CFAllocatorRef allocator
= (CFAllocatorRef
)zone
;
163 CFAllocatorDeallocate(allocator
, ptr
);
166 static void *__CFAllocatorCustomRealloc(malloc_zone_t
*zone
, void *ptr
, size_t size
) {
167 CFAllocatorRef allocator
= (CFAllocatorRef
)zone
;
168 return CFAllocatorReallocate(allocator
, ptr
, size
, 0);
171 static void __CFAllocatorCustomDestroy(malloc_zone_t
*zone
) {
172 CFAllocatorRef allocator
= (CFAllocatorRef
)zone
;
173 // !!! we do it, and caller of malloc_destroy_zone() assumes
174 // COMPLETE responsibility for the result; NO Apple library
175 // code should be modified as a result of discovering that
176 // some activity results in inconveniences to developers
177 // trying to use malloc_destroy_zone() with a CFAllocatorRef;
178 // that's just too bad for them.
179 __CFAllocatorDeallocate(allocator
);
182 static size_t __CFAllocatorCustomGoodSize(malloc_zone_t
*zone
, size_t size
) {
183 CFAllocatorRef allocator
= (CFAllocatorRef
)zone
;
184 return CFAllocatorGetPreferredSizeForSize(allocator
, size
, 0);
187 static struct malloc_introspection_t __CFAllocatorZoneIntrospect
= {
188 (void *)__CFAllocatorZoneIntrospectNoOp
,
189 (void *)__CFAllocatorCustomGoodSize
,
190 (void *)__CFAllocatorZoneIntrospectTrue
,
191 (void *)__CFAllocatorZoneIntrospectNoOp
,
192 (void *)__CFAllocatorZoneIntrospectNoOp
,
193 (void *)__CFAllocatorZoneIntrospectNoOp
,
194 (void *)__CFAllocatorZoneIntrospectNoOp
,
195 (void *)__CFAllocatorZoneIntrospectNoOp
198 static size_t __CFAllocatorNullSize(malloc_zone_t
*zone
, const void *ptr
) {
202 static void * __CFAllocatorNullMalloc(malloc_zone_t
*zone
, size_t size
) {
206 static void * __CFAllocatorNullCalloc(malloc_zone_t
*zone
, size_t num_items
, size_t size
) {
210 static void * __CFAllocatorNullValloc(malloc_zone_t
*zone
, size_t size
) {
214 static void __CFAllocatorNullFree(malloc_zone_t
*zone
, void *ptr
) {
217 static void * __CFAllocatorNullRealloc(malloc_zone_t
*zone
, void *ptr
, size_t size
) {
221 static void __CFAllocatorNullDestroy(malloc_zone_t
*zone
) {
224 static size_t __CFAllocatorNullGoodSize(malloc_zone_t
*zone
, size_t size
) {
228 static struct malloc_introspection_t __CFAllocatorNullZoneIntrospect
= {
229 (void *)__CFAllocatorZoneIntrospectNoOp
,
230 (void *)__CFAllocatorNullGoodSize
,
231 (void *)__CFAllocatorZoneIntrospectTrue
,
232 (void *)__CFAllocatorZoneIntrospectNoOp
,
233 (void *)__CFAllocatorZoneIntrospectNoOp
,
234 (void *)__CFAllocatorZoneIntrospectNoOp
,
235 (void *)__CFAllocatorZoneIntrospectNoOp
,
236 (void *)__CFAllocatorZoneIntrospectNoOp
239 static void *__CFAllocatorSystemAllocate(CFIndex size
, CFOptionFlags hint
, void *info
) {
240 return malloc_zone_malloc(info
, size
);
243 static void *__CFAllocatorSystemReallocate(void *ptr
, CFIndex newsize
, CFOptionFlags hint
, void *info
) {
244 return malloc_zone_realloc(info
, ptr
, newsize
);
247 static void __CFAllocatorSystemDeallocate(void *ptr
, void *info
) {
249 size_t size
= malloc_size(ptr
);
250 if (size
) memset(ptr
, 0xCC, size
);
252 malloc_zone_free(info
, ptr
);
257 #if defined(__WIN32__) || defined(__LINUX__) || defined(__FREEBSD__)
258 static void *__CFAllocatorSystemAllocate(CFIndex size
, CFOptionFlags hint
, void *info
) {
262 static void *__CFAllocatorSystemReallocate(void *ptr
, CFIndex newsize
, CFOptionFlags hint
, void *info
) {
263 return realloc(ptr
, newsize
);
266 static void __CFAllocatorSystemDeallocate(void *ptr
, void *info
) {
271 static void *__CFAllocatorNullAllocate(CFIndex size
, CFOptionFlags hint
, void *info
) {
275 static void *__CFAllocatorNullReallocate(void *ptr
, CFIndex newsize
, CFOptionFlags hint
, void *info
) {
279 static struct __CFAllocator __kCFAllocatorMalloc
= {
281 #if defined(__MACH__)
282 __CFAllocatorCustomSize
,
283 __CFAllocatorCustomMalloc
,
284 __CFAllocatorCustomCalloc
,
285 __CFAllocatorCustomValloc
,
286 __CFAllocatorCustomFree
,
287 __CFAllocatorCustomRealloc
,
288 __CFAllocatorNullDestroy
,
289 "kCFAllocatorMalloc",
292 &__CFAllocatorZoneIntrospect
,
296 // Using the malloc functions directly is a total cheat, but works (in C)
297 // because the function signatures match in their common prefix of arguments.
298 // This saves us one hop through an adaptor function.
299 {0, NULL
, NULL
, NULL
, NULL
, (void *)malloc
, (void *)realloc
, (void *)free
, NULL
}
302 static struct __CFAllocator __kCFAllocatorMallocZone
= {
304 #if defined(__MACH__)
305 __CFAllocatorCustomSize
,
306 __CFAllocatorCustomMalloc
,
307 __CFAllocatorCustomCalloc
,
308 __CFAllocatorCustomValloc
,
309 __CFAllocatorCustomFree
,
310 __CFAllocatorCustomRealloc
,
311 __CFAllocatorNullDestroy
,
312 "kCFAllocatorMallocZone",
315 &__CFAllocatorZoneIntrospect
,
319 {0, NULL
, NULL
, NULL
, NULL
, __CFAllocatorSystemAllocate
, __CFAllocatorSystemReallocate
, __CFAllocatorSystemDeallocate
, NULL
}
322 static struct __CFAllocator __kCFAllocatorSystemDefault
= {
324 #if defined(__MACH__)
325 __CFAllocatorCustomSize
,
326 __CFAllocatorCustomMalloc
,
327 __CFAllocatorCustomCalloc
,
328 __CFAllocatorCustomValloc
,
329 __CFAllocatorCustomFree
,
330 __CFAllocatorCustomRealloc
,
331 __CFAllocatorNullDestroy
,
332 "kCFAllocatorSystemDefault",
335 &__CFAllocatorZoneIntrospect
,
339 {0, NULL
, NULL
, NULL
, NULL
, __CFAllocatorSystemAllocate
, __CFAllocatorSystemReallocate
, __CFAllocatorSystemDeallocate
, NULL
}
342 static struct __CFAllocator __kCFAllocatorNull
= {
344 #if defined(__MACH__)
345 __CFAllocatorNullSize
,
346 __CFAllocatorNullMalloc
,
347 __CFAllocatorNullCalloc
,
348 __CFAllocatorNullValloc
,
349 __CFAllocatorNullFree
,
350 __CFAllocatorNullRealloc
,
351 __CFAllocatorNullDestroy
,
355 &__CFAllocatorNullZoneIntrospect
,
359 {0, NULL
, NULL
, NULL
, NULL
, __CFAllocatorNullAllocate
, __CFAllocatorNullReallocate
, NULL
, NULL
}
362 const CFAllocatorRef kCFAllocatorDefault
= NULL
;
363 const CFAllocatorRef kCFAllocatorSystemDefault
= &__kCFAllocatorSystemDefault
;
364 const CFAllocatorRef kCFAllocatorMalloc
= &__kCFAllocatorMalloc
;
365 const CFAllocatorRef kCFAllocatorMallocZone
= &__kCFAllocatorMallocZone
;
366 const CFAllocatorRef kCFAllocatorNull
= &__kCFAllocatorNull
;
367 const CFAllocatorRef kCFAllocatorUseContext
= (CFAllocatorRef
)0x0227;
369 bool kCFUseCollectableAllocator
= false;
371 static CFStringRef
__CFAllocatorCopyDescription(CFTypeRef cf
) {
372 CFAllocatorRef self
= cf
;
373 CFAllocatorRef allocator
= (kCFAllocatorUseContext
== self
->_allocator
) ? self
: self
->_allocator
;
374 return CFStringCreateWithFormat(allocator
, NULL
, CFSTR("<CFAllocator 0x%x [0x%x]>{info = 0x%x}"), (UInt32
)cf
, (UInt32
)allocator
, self
->_context
.info
);
375 // CF: should use copyDescription function here to describe info field
376 // remember to release value returned from copydescr function when this happens
379 __private_extern__ CFAllocatorRef
__CFAllocatorGetAllocator(CFTypeRef cf
) {
380 CFAllocatorRef allocator
= cf
;
381 return (kCFAllocatorUseContext
== allocator
->_allocator
) ? allocator
: allocator
->_allocator
;
384 __private_extern__
void __CFAllocatorDeallocate(CFTypeRef cf
) {
385 CFAllocatorRef self
= cf
;
386 CFAllocatorRef allocator
= self
->_allocator
;
387 CFAllocatorReleaseCallBack releaseFunc
= __CFAllocatorGetReleaseFunction(&self
->_context
);
388 if (kCFAllocatorUseContext
== allocator
) {
389 /* Rather a chicken and egg problem here, so we do things
390 in the reverse order from what was done at create time. */
391 CFAllocatorDeallocateCallBack deallocateFunc
= __CFAllocatorGetDeallocateFunction(&self
->_context
);
392 void *info
= self
->_context
.info
;
393 if (NULL
!= deallocateFunc
) {
394 INVOKE_CALLBACK2(deallocateFunc
, (void *)self
, info
);
396 if (NULL
!= releaseFunc
) {
397 INVOKE_CALLBACK1(releaseFunc
, info
);
400 if (NULL
!= releaseFunc
) {
401 INVOKE_CALLBACK1(releaseFunc
, self
->_context
.info
);
403 CFAllocatorDeallocate(allocator
, (void *)self
);
407 static CFTypeID __kCFAllocatorTypeID
= _kCFRuntimeNotATypeID
;
409 static const CFRuntimeClass __CFAllocatorClass
= {
414 __CFAllocatorDeallocate
,
418 __CFAllocatorCopyDescription
421 __private_extern__
void __CFAllocatorInitialize(void) {
422 __kCFAllocatorTypeID
= _CFRuntimeRegisterClass(&__CFAllocatorClass
);
424 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorSystemDefault
, __kCFAllocatorTypeID
);
425 __kCFAllocatorSystemDefault
._base
._isa
= __CFISAForTypeID(__kCFAllocatorTypeID
);
426 #if defined(__MACH__)
427 __kCFAllocatorSystemDefault
._context
.info
= (CF_USING_COLLECTABLE_MEMORY
? __CFCollectableZone
: malloc_default_zone());
428 memset(malloc_default_zone(), 0, 8);
430 __kCFAllocatorSystemDefault
._allocator
= kCFAllocatorSystemDefault
;
432 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMalloc
, __kCFAllocatorTypeID
);
433 __kCFAllocatorMalloc
._base
._isa
= __CFISAForTypeID(__kCFAllocatorTypeID
);
434 __kCFAllocatorMalloc
._allocator
= kCFAllocatorSystemDefault
;
436 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMallocZone
, __kCFAllocatorTypeID
);
437 __kCFAllocatorMallocZone
._base
._isa
= __CFISAForTypeID(__kCFAllocatorTypeID
);
438 __kCFAllocatorMallocZone
._allocator
= kCFAllocatorSystemDefault
;
439 __kCFAllocatorMallocZone
._context
.info
= malloc_default_zone();
441 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorNull
, __kCFAllocatorTypeID
);
442 __kCFAllocatorNull
._base
._isa
= __CFISAForTypeID(__kCFAllocatorTypeID
);
443 __kCFAllocatorNull
._allocator
= kCFAllocatorSystemDefault
;
447 CFTypeID
CFAllocatorGetTypeID(void) {
448 return __kCFAllocatorTypeID
;
451 CFAllocatorRef
CFAllocatorGetDefault(void) {
452 CFAllocatorRef allocator
= __CFGetThreadSpecificData_inline()->_allocator
;
453 if (NULL
== allocator
) {
454 allocator
= kCFAllocatorSystemDefault
;
459 void CFAllocatorSetDefault(CFAllocatorRef allocator
) {
460 CFAllocatorRef current
= __CFGetThreadSpecificData_inline()->_allocator
;
462 if (NULL
!= allocator
) {
463 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
466 #if defined(__MACH__)
467 if (allocator
&& allocator
->_base
._isa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
468 return; // require allocator to this function to be an allocator
471 if (NULL
!= allocator
&& allocator
!= current
) {
472 if (current
) CFRelease(current
);
474 // We retain an extra time so that anything set as the default
475 // allocator never goes away.
477 __CFGetThreadSpecificData_inline()->_allocator
= (void *)allocator
;
481 static CFAllocatorRef
__CFAllocatorCreate(CFAllocatorRef allocator
, CFAllocatorContext
*context
) {
482 struct __CFAllocator
*memory
= NULL
;
483 CFAllocatorRetainCallBack retainFunc
;
484 CFAllocatorAllocateCallBack allocateFunc
;
486 #if defined(__MACH__)
487 if (allocator
&& kCFAllocatorUseContext
!= allocator
&& allocator
->_base
._isa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
488 return NULL
; // require allocator to this function to be an allocator
491 retainFunc
= context
->retain
;
492 FAULT_CALLBACK((void **)&retainFunc
);
493 allocateFunc
= context
->allocate
;
494 FAULT_CALLBACK((void **)&allocateFunc
);
495 if (NULL
!= retainFunc
) {
496 retainedInfo
= (void *)INVOKE_CALLBACK1(retainFunc
, context
->info
);
498 retainedInfo
= context
->info
;
500 // We don't use _CFRuntimeCreateInstance()
501 if (kCFAllocatorUseContext
== allocator
) {
504 memory
= (void *)INVOKE_CALLBACK3(allocateFunc
, sizeof(struct __CFAllocator
), 0, retainedInfo
);
506 if (NULL
== memory
) {
510 allocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : allocator
;
511 memory
= CFAllocatorAllocate(allocator
, sizeof(struct __CFAllocator
), 0);
512 if (__CFOASafe
) __CFSetLastAllocationEventName(memory
, "CFAllocator");
513 if (NULL
== memory
) {
517 memory
->_base
._isa
= 0;
518 memory
->_base
._rc
= 1;
519 memory
->_base
._info
= 0;
520 _CFRuntimeSetInstanceTypeID(memory
, __kCFAllocatorTypeID
);
521 memory
->_base
._isa
= __CFISAForTypeID(__kCFAllocatorTypeID
);
522 #if defined(__MACH__)
523 memory
->size
= __CFAllocatorCustomSize
;
524 memory
->malloc
= __CFAllocatorCustomMalloc
;
525 memory
->calloc
= __CFAllocatorCustomCalloc
;
526 memory
->valloc
= __CFAllocatorCustomValloc
;
527 memory
->free
= __CFAllocatorCustomFree
;
528 memory
->realloc
= __CFAllocatorCustomRealloc
;
529 memory
->destroy
= __CFAllocatorCustomDestroy
;
530 memory
->zone_name
= "Custom CFAllocator";
531 memory
->batch_malloc
= NULL
;
532 memory
->batch_free
= NULL
;
533 memory
->introspect
= &__CFAllocatorZoneIntrospect
;
534 memory
->reserved5
= NULL
;
536 memory
->_allocator
= allocator
;
537 memory
->_context
.version
= context
->version
;
538 memory
->_context
.info
= retainedInfo
;
539 memory
->_context
.retain
= retainFunc
;
540 memory
->_context
.release
= context
->release
;
541 FAULT_CALLBACK((void **)&(memory
->_context
.release
));
542 memory
->_context
.copyDescription
= context
->copyDescription
;
543 FAULT_CALLBACK((void **)&(memory
->_context
.copyDescription
));
544 memory
->_context
.allocate
= allocateFunc
;
545 memory
->_context
.reallocate
= context
->reallocate
;
546 FAULT_CALLBACK((void **)&(memory
->_context
.reallocate
));
547 memory
->_context
.deallocate
= context
->deallocate
;
548 FAULT_CALLBACK((void **)&(memory
->_context
.deallocate
));
549 memory
->_context
.preferredSize
= context
->preferredSize
;
550 FAULT_CALLBACK((void **)&(memory
->_context
.preferredSize
));
555 CFAllocatorRef
CFAllocatorCreate(CFAllocatorRef allocator
, CFAllocatorContext
*context
) {
556 CFAssert1(!CF_USING_COLLECTABLE_MEMORY
, __kCFLogAssertion
, "%s(): Shouldn't be called when GC is enabled!", __PRETTY_FUNCTION__
);
558 if (CF_USING_COLLECTABLE_MEMORY
)
561 return __CFAllocatorCreate(allocator
, context
);
564 CFAllocatorRef
_CFAllocatorCreateGC(CFAllocatorRef allocator
, CFAllocatorContext
*context
) {
565 return __CFAllocatorCreate(allocator
, context
);
568 void *CFAllocatorAllocate(CFAllocatorRef allocator
, CFIndex size
, CFOptionFlags hint
) {
569 CFAllocatorAllocateCallBack allocateFunc
;
571 allocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : allocator
;
572 #if defined(__MACH__) && defined(DEBUG)
573 if (allocator
->_base
._isa
== __CFISAForTypeID(__kCFAllocatorTypeID
)) {
574 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
577 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
579 if (0 == size
) return NULL
;
580 #if defined(__MACH__)
581 if (allocator
->_base
._isa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
582 return malloc_zone_malloc((malloc_zone_t
*)allocator
, size
);
585 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
586 newptr
= auto_zone_allocate_object((auto_zone_t
*)allocator
->_context
.info
, size
, (auto_memory_type_t
)hint
, true, false);
589 allocateFunc
= __CFAllocatorGetAllocateFunction(&allocator
->_context
);
591 newptr
= (void *)INVOKE_CALLBACK3(allocateFunc
, size
, hint
, allocator
->_context
.info
);
597 void *CFAllocatorReallocate(CFAllocatorRef allocator
, void *ptr
, CFIndex newsize
, CFOptionFlags hint
) {
598 CFAllocatorAllocateCallBack allocateFunc
;
599 CFAllocatorReallocateCallBack reallocateFunc
;
600 CFAllocatorDeallocateCallBack deallocateFunc
;
602 allocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : allocator
;
603 #if defined(__MACH__) && defined(DEBUG)
604 if (allocator
->_base
._isa
== __CFISAForTypeID(__kCFAllocatorTypeID
)) {
605 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
608 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
610 if (NULL
== ptr
&& 0 < newsize
) {
611 #if defined(__MACH__)
612 if (allocator
->_base
._isa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
613 return malloc_zone_malloc((malloc_zone_t
*)allocator
, newsize
);
617 allocateFunc
= __CFAllocatorGetAllocateFunction(&allocator
->_context
);
619 newptr
= (void *)INVOKE_CALLBACK3(allocateFunc
, newsize
, hint
, allocator
->_context
.info
);
623 if (NULL
!= ptr
&& 0 == newsize
) {
624 #if defined(__MACH__)
625 if (allocator
->_base
._isa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
627 size_t size
= malloc_size(ptr
);
628 if (size
) memset(ptr
, 0xCC, size
);
630 malloc_zone_free((malloc_zone_t
*)allocator
, ptr
);
634 deallocateFunc
= __CFAllocatorGetDeallocateFunction(&allocator
->_context
);
635 if (NULL
!= deallocateFunc
) {
636 INVOKE_CALLBACK2(deallocateFunc
, ptr
, allocator
->_context
.info
);
640 if (NULL
== ptr
&& 0 == newsize
) return NULL
;
641 #if defined(__MACH__)
642 if (allocator
->_base
._isa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
643 return malloc_zone_realloc((malloc_zone_t
*)allocator
, ptr
, newsize
);
646 reallocateFunc
= __CFAllocatorGetReallocateFunction(&allocator
->_context
);
647 if (NULL
== reallocateFunc
) return NULL
;
648 newptr
= (void *)INVOKE_CALLBACK4(reallocateFunc
, ptr
, newsize
, hint
, allocator
->_context
.info
);
652 void CFAllocatorDeallocate(CFAllocatorRef allocator
, void *ptr
) {
653 CFAllocatorDeallocateCallBack deallocateFunc
;
654 allocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : allocator
;
655 #if defined(__MACH__) && defined(DEBUG)
656 if (allocator
->_base
._isa
== __CFISAForTypeID(__kCFAllocatorTypeID
)) {
657 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
660 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
662 #if defined(__MACH__)
663 if (allocator
->_base
._isa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
665 size_t size
= malloc_size(ptr
);
666 if (size
) memset(ptr
, 0xCC, size
);
668 return malloc_zone_free((malloc_zone_t
*)allocator
, ptr
);
671 deallocateFunc
= __CFAllocatorGetDeallocateFunction(&allocator
->_context
);
672 if (NULL
!= ptr
&& NULL
!= deallocateFunc
) {
673 INVOKE_CALLBACK2(deallocateFunc
, ptr
, allocator
->_context
.info
);
677 CFIndex
CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator
, CFIndex size
, CFOptionFlags hint
) {
678 CFAllocatorPreferredSizeCallBack prefFunc
;
680 allocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : allocator
;
681 #if defined(__MACH__) && defined(DEBUG)
682 if (allocator
->_base
._isa
== __CFISAForTypeID(__kCFAllocatorTypeID
)) {
683 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
686 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
688 #if defined(__MACH__)
689 if (allocator
->_base
._isa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
690 return malloc_good_size(size
);
693 prefFunc
= __CFAllocatorGetPreferredSizeFunction(&allocator
->_context
);
694 if (0 < size
&& NULL
!= prefFunc
) {
695 newsize
= (CFIndex
)(INVOKE_CALLBACK3(prefFunc
, size
, hint
, allocator
->_context
.info
));
697 if (newsize
< size
) newsize
= size
;
701 void CFAllocatorGetContext(CFAllocatorRef allocator
, CFAllocatorContext
*context
) {
702 allocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : allocator
;
703 #if defined(__MACH__) && defined(DEBUG)
704 if (allocator
->_base
._isa
== __CFISAForTypeID(__kCFAllocatorTypeID
)) {
705 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
708 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
710 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
711 #if defined(__MACH__)
712 if (allocator
->_base
._isa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
716 context
->version
= 0;
717 context
->info
= allocator
->_context
.info
;
718 context
->retain
= __CFAllocatorGetRetainFunction(&allocator
->_context
);
719 context
->release
= __CFAllocatorGetReleaseFunction(&allocator
->_context
);
720 context
->copyDescription
= __CFAllocatorGetCopyDescriptionFunction(&allocator
->_context
);
721 context
->allocate
= __CFAllocatorGetAllocateFunction(&allocator
->_context
);
722 context
->reallocate
= __CFAllocatorGetReallocateFunction(&allocator
->_context
);
723 context
->deallocate
= __CFAllocatorGetDeallocateFunction(&allocator
->_context
);
724 context
->preferredSize
= __CFAllocatorGetPreferredSizeFunction(&allocator
->_context
);
726 context
->retain
= (void *)((uintptr_t)context
->retain
& ~0x3);
727 context
->release
= (void *)((uintptr_t)context
->release
& ~0x3);
728 context
->copyDescription
= (void *)((uintptr_t)context
->copyDescription
& ~0x3);
729 context
->allocate
= (void *)((uintptr_t)context
->allocate
& ~0x3);
730 context
->reallocate
= (void *)((uintptr_t)context
->reallocate
& ~0x3);
731 context
->deallocate
= (void *)((uintptr_t)context
->deallocate
& ~0x3);
732 context
->preferredSize
= (void *)((uintptr_t)context
->preferredSize
& ~0x3);
736 void *_CFAllocatorAllocateGC(CFAllocatorRef allocator
, CFIndex size
, CFOptionFlags hint
)
738 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
))
739 return auto_zone_allocate_object((auto_zone_t
*)kCFAllocatorSystemDefault
->_context
.info
, size
, (auto_memory_type_t
)hint
, false, false);
741 return CFAllocatorAllocate(allocator
, size
, hint
);
744 void *_CFAllocatorReallocateGC(CFAllocatorRef allocator
, void *ptr
, CFIndex newsize
, CFOptionFlags hint
)
746 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
747 if (ptr
&& (newsize
== 0)) {
748 return NULL
; // equivalent to _CFAllocatorDeallocateGC.
751 return auto_zone_allocate_object((auto_zone_t
*)kCFAllocatorSystemDefault
->_context
.info
, newsize
, (auto_memory_type_t
)hint
, false, false); // eq. to _CFAllocator
754 // otherwise, auto_realloc() now preserves layout type and refCount.
755 return CFAllocatorReallocate(allocator
, ptr
, newsize
, hint
);
758 void _CFAllocatorDeallocateGC(CFAllocatorRef allocator
, void *ptr
)
760 // when running GC, don't deallocate.
761 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) CFAllocatorDeallocate(allocator
, ptr
);
764 // -------- -------- -------- -------- -------- -------- -------- --------
766 #if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
767 __private_extern__ pthread_key_t __CFTSDKey
= (pthread_key_t
)NULL
;
769 #if defined(__WIN32__)
770 __private_extern__ DWORD __CFTSDKey
= 0xFFFFFFFF;
773 // Called for each thread as it exits
774 __private_extern__
void __CFFinalizeThreadData(void *arg
) {
775 #if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
776 __CFThreadSpecificData
*tsd
= (__CFThreadSpecificData
*)arg
;
777 #elif defined(__WIN32)
778 __CFThreadSpecificData
*tsd
= TlsGetValue(__CFTSDKey
);
779 TlsSetValue(__CFTSDKey
, NULL
);
781 if (NULL
== tsd
) return;
782 if (tsd
->_allocator
) CFRelease(tsd
->_allocator
);
783 if (tsd
->_runLoop
) CFRelease(tsd
->_runLoop
);
784 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, tsd
);
787 __private_extern__ __CFThreadSpecificData
*__CFGetThreadSpecificData(void) {
788 #if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
789 __CFThreadSpecificData
*data
;
790 data
= pthread_getspecific(__CFTSDKey
);
794 data
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(__CFThreadSpecificData
), 0);
795 if (__CFOASafe
) __CFSetLastAllocationEventName(data
, "CFUtilities (thread-data)");
796 memset(data
, 0, sizeof(__CFThreadSpecificData
));
797 pthread_setspecific(__CFTSDKey
, data
);
799 #elif defined(__WIN32__)
800 __CFThreadSpecificData
*data
;
801 data
= TlsGetValue(__CFTSDKey
);
805 data
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(__CFThreadSpecificData
), 0);
806 if (__CFOASafe
) __CFSetLastAllocationEventName(data
, "CFUtilities (thread-data)");
807 memset(data
, 0, sizeof(__CFThreadSpecificData
));
808 TlsSetValue(__CFTSDKey
, data
);
813 __private_extern__
void __CFBaseInitialize(void) {
814 #if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
815 pthread_key_create(&__CFTSDKey
, __CFFinalizeThreadData
);
817 #if defined(__WIN32__)
818 __CFTSDKey
= TlsAlloc();
820 //kCFUseCollectableAllocator = objc_collecting_enabled();
823 #if defined(__WIN32__)
824 __private_extern__
void __CFBaseCleanup(void) {
830 CFRange
__CFRangeMake(CFIndex loc
, CFIndex len
) {
832 range
.location
= loc
;
837 __private_extern__
const void *__CFTypeCollectionRetain(CFAllocatorRef allocator
, const void *ptr
) {
838 return (const void *)CFRetain(ptr
);
841 __private_extern__
void __CFTypeCollectionRelease(CFAllocatorRef allocator
, const void *ptr
) {
850 static struct __CFNull __kCFNull
= {
851 INIT_CFRUNTIME_BASE(NULL
, 0, 0x0080)
853 const CFNullRef kCFNull
= &__kCFNull
;
855 static CFStringRef
__CFNullCopyDescription(CFTypeRef cf
) {
856 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<CFNull %p [%p]>"), cf
, CFGetAllocator(cf
));
859 static CFStringRef
__CFNullCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
860 return CFRetain(CFSTR("null"));
863 static void __CFNullDeallocate(CFTypeRef cf
) {
864 CFAssert(false, __kCFLogAssertion
, "Deallocated CFNull!");
867 static CFTypeID __kCFNullTypeID
= _kCFRuntimeNotATypeID
;
869 static const CFRuntimeClass __CFNullClass
= {
877 __CFNullCopyFormattingDescription
,
878 __CFNullCopyDescription
881 __private_extern__
void __CFNullInitialize(void) {
882 __kCFNullTypeID
= _CFRuntimeRegisterClass(&__CFNullClass
);
883 _CFRuntimeSetInstanceTypeID(&__kCFNull
, __kCFNullTypeID
);
884 __kCFNull
._base
._isa
= __CFISAForTypeID(__kCFNullTypeID
);
887 CFTypeID
CFNullGetTypeID(void) {
888 return __kCFNullTypeID
;
892 static int hasCFM
= 0;
894 void _CFRuntimeSetCFMPresent(void *addr
) {
898 #if defined(__MACH__) && defined(__ppc__)
900 /* See comments below */
901 __private_extern__
void __CF_FAULT_CALLBACK(void **ptr
) {
902 uintptr_t p
= (uintptr_t)*ptr
;
903 if ((0 == p
) || (p
& 0x1)) return;
904 // warning: revisit this address check in Chablis, and for 64-bit
905 if (0 == hasCFM
|| (0x90000000 <= p
&& p
< 0xA0000000)) {
906 *ptr
= (void *)(p
| 0x1);
909 int __known
= dladdr(p
, &info
);
910 *ptr
= (void *)(p
| (__known
? 0x1 : 0x3));
915 Jump to callback function. r2 is not saved and restored
916 in the jump-to-CFM case, since we assume that dyld code
917 never uses that register and that CF is dyld.
919 There are three states for (ptr & 0x3):
920 0b00: check not yet done (or not going to be done, and is a dyld func ptr)
921 0b01: check done, dyld function pointer
922 0b11: check done, CFM tvector pointer
923 (but a NULL callback just stays NULL)
925 There may be up to 5 word-sized arguments. Floating point
926 arguments can be done, but count as two word arguments.
927 Return value can be integral or real.
930 /* Keep this assembly at the bottom of the source file! */
935 ".private_extern ___CF_INVOKE_CALLBACK\n"
936 "___CF_INVOKE_CALLBACK:\n"
937 "rlwinm r12,r3,0,0,29\n"
947 "Lcall: mtspr ctr,r12\n"
953 // void __HALT(void);
955 #if defined(__ppc__) || defined(__ppc64__)
959 #if defined(__MACH__)
960 ".private_extern ___HALT\n"
969 #if defined(__i386__)
970 #if defined(_MSC_VER) || defined(__MWERKS__)
971 __private_extern__
void __HALT()
979 #if defined(__MACH__)
980 ".private_extern ___HALT\n"