2 * Copyright (c) 2010 Apple 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@
25 Copyright (c) 1998-2009, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
29 #include <CoreFoundation/CFBase.h>
30 #include "CFInternal.h"
31 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
34 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
35 #include <malloc/malloc.h>
36 extern size_t malloc_good_size(size_t size
);
37 #include <mach/mach.h>
43 // -------- -------- -------- -------- -------- -------- -------- --------
45 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
46 // CFAllocator structure must match struct _malloc_zone_t!
47 // The first two reserved fields in struct _malloc_zone_t are for us with CFRuntimeBase
51 struct __CFAllocator
{
55 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
56 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 */
57 void *(*malloc
)(struct _malloc_zone_t
*zone
, size_t size
);
58 void *(*calloc
)(struct _malloc_zone_t
*zone
, size_t num_items
, size_t size
); /* same as malloc, but block returned is set to zero */
59 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 */
60 void (*free
)(struct _malloc_zone_t
*zone
, void *ptr
);
61 void *(*realloc
)(struct _malloc_zone_t
*zone
, void *ptr
, size_t size
);
62 void (*destroy
)(struct _malloc_zone_t
*zone
); /* zone is destroyed and all memory reclaimed */
63 const char *zone_name
;
64 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) */
65 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 */
66 struct malloc_introspection_t
*introspect
;
69 CFAllocatorRef _allocator
;
70 CFAllocatorContext _context
;
73 CF_INLINE CFAllocatorRetainCallBack
__CFAllocatorGetRetainFunction(const CFAllocatorContext
*context
) {
74 CFAllocatorRetainCallBack retval
= NULL
;
75 retval
= context
->retain
;
79 CF_INLINE CFAllocatorReleaseCallBack
__CFAllocatorGetReleaseFunction(const CFAllocatorContext
*context
) {
80 CFAllocatorReleaseCallBack retval
= NULL
;
81 retval
= context
->release
;
85 CF_INLINE CFAllocatorCopyDescriptionCallBack
__CFAllocatorGetCopyDescriptionFunction(const CFAllocatorContext
*context
) {
86 CFAllocatorCopyDescriptionCallBack retval
= NULL
;
87 retval
= context
->copyDescription
;
91 CF_INLINE CFAllocatorAllocateCallBack
__CFAllocatorGetAllocateFunction(const CFAllocatorContext
*context
) {
92 CFAllocatorAllocateCallBack retval
= NULL
;
93 retval
= context
->allocate
;
97 CF_INLINE CFAllocatorReallocateCallBack
__CFAllocatorGetReallocateFunction(const CFAllocatorContext
*context
) {
98 CFAllocatorReallocateCallBack retval
= NULL
;
99 retval
= context
->reallocate
;
103 CF_INLINE CFAllocatorDeallocateCallBack
__CFAllocatorGetDeallocateFunction(const CFAllocatorContext
*context
) {
104 CFAllocatorDeallocateCallBack retval
= NULL
;
105 retval
= context
->deallocate
;
109 CF_INLINE CFAllocatorPreferredSizeCallBack
__CFAllocatorGetPreferredSizeFunction(const CFAllocatorContext
*context
) {
110 CFAllocatorPreferredSizeCallBack retval
= NULL
;
111 retval
= context
->preferredSize
;
115 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
117 __private_extern__
void __CFAllocatorDeallocate(CFTypeRef cf
);
119 static kern_return_t
__CFAllocatorZoneIntrospectNoOp(void) {
123 static boolean_t
__CFAllocatorZoneIntrospectTrue(void) {
127 static size_t __CFAllocatorCustomSize(malloc_zone_t
*zone
, const void *ptr
) {
130 // The only way to implement this with a version 0 allocator would be
131 // for CFAllocator to keep track of all blocks allocated itself, which
132 // could be done, but would be bad for performance, so we don't do it.
133 // size_t (*size)(struct _malloc_zone_t *zone, const void *ptr);
134 /* returns the size of a block or 0 if not in this zone;
135 * must be fast, especially for negative answers */
138 static void *__CFAllocatorCustomMalloc(malloc_zone_t
*zone
, size_t size
) {
139 CFAllocatorRef allocator
= (CFAllocatorRef
)zone
;
140 return CFAllocatorAllocate(allocator
, size
, 0);
143 static void *__CFAllocatorCustomCalloc(malloc_zone_t
*zone
, size_t num_items
, size_t size
) {
144 CFAllocatorRef allocator
= (CFAllocatorRef
)zone
;
145 void *newptr
= CFAllocatorAllocate(allocator
, size
, 0);
146 if (newptr
) memset(newptr
, 0, size
);
150 static void *__CFAllocatorCustomValloc(malloc_zone_t
*zone
, size_t size
) {
151 CFAllocatorRef allocator
= (CFAllocatorRef
)zone
;
152 void *newptr
= CFAllocatorAllocate(allocator
, size
+ vm_page_size
, 0);
153 newptr
= (void *)round_page((uintptr_t)newptr
);
157 static void __CFAllocatorCustomFree(malloc_zone_t
*zone
, void *ptr
) {
158 CFAllocatorRef allocator
= (CFAllocatorRef
)zone
;
159 CFAllocatorDeallocate(allocator
, ptr
);
162 static void *__CFAllocatorCustomRealloc(malloc_zone_t
*zone
, void *ptr
, size_t size
) {
163 CFAllocatorRef allocator
= (CFAllocatorRef
)zone
;
164 return CFAllocatorReallocate(allocator
, ptr
, size
, 0);
167 static void __CFAllocatorCustomDestroy(malloc_zone_t
*zone
) {
168 CFAllocatorRef allocator
= (CFAllocatorRef
)zone
;
169 // !!! we do it, and caller of malloc_destroy_zone() assumes
170 // COMPLETE responsibility for the result; NO Apple library
171 // code should be modified as a result of discovering that
172 // some activity results in inconveniences to developers
173 // trying to use malloc_destroy_zone() with a CFAllocatorRef;
174 // that's just too bad for them.
175 __CFAllocatorDeallocate(allocator
);
178 static size_t __CFAllocatorCustomGoodSize(malloc_zone_t
*zone
, size_t size
) {
179 CFAllocatorRef allocator
= (CFAllocatorRef
)zone
;
180 return CFAllocatorGetPreferredSizeForSize(allocator
, size
, 0);
183 static struct malloc_introspection_t __CFAllocatorZoneIntrospect
= {
184 (void *)__CFAllocatorZoneIntrospectNoOp
,
185 (void *)__CFAllocatorCustomGoodSize
,
186 (void *)__CFAllocatorZoneIntrospectTrue
,
187 (void *)__CFAllocatorZoneIntrospectNoOp
,
188 (void *)__CFAllocatorZoneIntrospectNoOp
,
189 (void *)__CFAllocatorZoneIntrospectNoOp
,
190 (void *)__CFAllocatorZoneIntrospectNoOp
,
191 (void *)__CFAllocatorZoneIntrospectNoOp
194 static size_t __CFAllocatorNullSize(malloc_zone_t
*zone
, const void *ptr
) {
198 static void * __CFAllocatorNullMalloc(malloc_zone_t
*zone
, size_t size
) {
202 static void * __CFAllocatorNullCalloc(malloc_zone_t
*zone
, size_t num_items
, size_t size
) {
206 static void * __CFAllocatorNullValloc(malloc_zone_t
*zone
, size_t size
) {
210 static void __CFAllocatorNullFree(malloc_zone_t
*zone
, void *ptr
) {
213 static void * __CFAllocatorNullRealloc(malloc_zone_t
*zone
, void *ptr
, size_t size
) {
217 static void __CFAllocatorNullDestroy(malloc_zone_t
*zone
) {
220 static size_t __CFAllocatorNullGoodSize(malloc_zone_t
*zone
, size_t size
) {
224 static struct malloc_introspection_t __CFAllocatorNullZoneIntrospect
= {
225 (void *)__CFAllocatorZoneIntrospectNoOp
,
226 (void *)__CFAllocatorNullGoodSize
,
227 (void *)__CFAllocatorZoneIntrospectTrue
,
228 (void *)__CFAllocatorZoneIntrospectNoOp
,
229 (void *)__CFAllocatorZoneIntrospectNoOp
,
230 (void *)__CFAllocatorZoneIntrospectNoOp
,
231 (void *)__CFAllocatorZoneIntrospectNoOp
,
232 (void *)__CFAllocatorZoneIntrospectNoOp
235 static void *__CFAllocatorSystemAllocate(CFIndex size
, CFOptionFlags hint
, void *info
) {
236 return malloc_zone_malloc(info
, size
);
239 static void *__CFAllocatorSystemReallocate(void *ptr
, CFIndex newsize
, CFOptionFlags hint
, void *info
) {
240 return malloc_zone_realloc(info
, ptr
, newsize
);
243 static void __CFAllocatorSystemDeallocate(void *ptr
, void *info
) {
245 size_t size
= malloc_size(ptr
);
246 if (size
) memset(ptr
, 0xCC, size
);
248 malloc_zone_free(info
, ptr
);
253 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
254 static void *__CFAllocatorSystemAllocate(CFIndex size
, CFOptionFlags hint
, void *info
) {
258 static void *__CFAllocatorSystemReallocate(void *ptr
, CFIndex newsize
, CFOptionFlags hint
, void *info
) {
259 return realloc(ptr
, newsize
);
262 static void __CFAllocatorSystemDeallocate(void *ptr
, void *info
) {
267 static void *__CFAllocatorNullAllocate(CFIndex size
, CFOptionFlags hint
, void *info
) {
271 static void *__CFAllocatorNullReallocate(void *ptr
, CFIndex newsize
, CFOptionFlags hint
, void *info
) {
275 #if defined (__cplusplus)
276 static void * __CFAllocatorCPPMalloc(CFIndex allocSize
, CFOptionFlags hint
, void *info
)
278 return malloc(allocSize
);
280 static void * __CFAllocatorCPPReAlloc(void *ptr
, CFIndex newsize
, CFOptionFlags hint
, void *info
)
282 return realloc(ptr
, newsize
);
284 static void __CFAllocatorCPPFree(void *ptr
, void *info
)
291 static struct __CFAllocator __kCFAllocatorMalloc
= {
292 INIT_CFRUNTIME_BASE(),
293 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
294 __CFAllocatorCustomSize
,
295 __CFAllocatorCustomMalloc
,
296 __CFAllocatorCustomCalloc
,
297 __CFAllocatorCustomValloc
,
298 __CFAllocatorCustomFree
,
299 __CFAllocatorCustomRealloc
,
300 __CFAllocatorNullDestroy
,
301 "kCFAllocatorMalloc",
304 &__CFAllocatorZoneIntrospect
,
308 // Using the malloc functions directly is a total cheat, but works (in C)
309 // because the function signatures match in their common prefix of arguments.
310 // This saves us one hop through an adaptor function.
311 #if !defined (__cplusplus)
312 {0, NULL
, NULL
, NULL
, NULL
, (void *)malloc
, (void *)realloc
, (void *)free
, NULL
}
314 {0, NULL
, NULL
, NULL
, NULL
, __CFAllocatorCPPMalloc
,__CFAllocatorCPPReAlloc
, __CFAllocatorCPPFree
, NULL
}
315 #endif // __cplusplus
318 static struct __CFAllocator __kCFAllocatorMallocZone
= {
319 INIT_CFRUNTIME_BASE(),
320 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
321 __CFAllocatorCustomSize
,
322 __CFAllocatorCustomMalloc
,
323 __CFAllocatorCustomCalloc
,
324 __CFAllocatorCustomValloc
,
325 __CFAllocatorCustomFree
,
326 __CFAllocatorCustomRealloc
,
327 __CFAllocatorNullDestroy
,
328 "kCFAllocatorMallocZone",
331 &__CFAllocatorZoneIntrospect
,
335 {0, NULL
, NULL
, NULL
, NULL
, __CFAllocatorSystemAllocate
, __CFAllocatorSystemReallocate
, __CFAllocatorSystemDeallocate
, NULL
}
338 static struct __CFAllocator __kCFAllocatorSystemDefault
= {
339 INIT_CFRUNTIME_BASE(),
340 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
341 __CFAllocatorCustomSize
,
342 __CFAllocatorCustomMalloc
,
343 __CFAllocatorCustomCalloc
,
344 __CFAllocatorCustomValloc
,
345 __CFAllocatorCustomFree
,
346 __CFAllocatorCustomRealloc
,
347 __CFAllocatorNullDestroy
,
348 "kCFAllocatorSystemDefault",
351 &__CFAllocatorZoneIntrospect
,
355 {0, NULL
, NULL
, NULL
, NULL
, __CFAllocatorSystemAllocate
, __CFAllocatorSystemReallocate
, __CFAllocatorSystemDeallocate
, NULL
}
358 static struct __CFAllocator __kCFAllocatorNull
= {
359 INIT_CFRUNTIME_BASE(),
360 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
361 __CFAllocatorNullSize
,
362 __CFAllocatorNullMalloc
,
363 __CFAllocatorNullCalloc
,
364 __CFAllocatorNullValloc
,
365 __CFAllocatorNullFree
,
366 __CFAllocatorNullRealloc
,
367 __CFAllocatorNullDestroy
,
371 &__CFAllocatorNullZoneIntrospect
,
375 {0, NULL
, NULL
, NULL
, NULL
, __CFAllocatorNullAllocate
, __CFAllocatorNullReallocate
, NULL
, NULL
}
378 const CFAllocatorRef kCFAllocatorDefault
= NULL
;
379 const CFAllocatorRef kCFAllocatorSystemDefault
= &__kCFAllocatorSystemDefault
;
380 const CFAllocatorRef kCFAllocatorMalloc
= &__kCFAllocatorMalloc
;
381 const CFAllocatorRef kCFAllocatorMallocZone
= &__kCFAllocatorMallocZone
;
382 const CFAllocatorRef kCFAllocatorNull
= &__kCFAllocatorNull
;
383 const CFAllocatorRef kCFAllocatorUseContext
= (CFAllocatorRef
)0x0257;
385 static CFStringRef
__CFAllocatorCopyDescription(CFTypeRef cf
) {
386 CFAllocatorRef self
= (CFAllocatorRef
)cf
;
387 CFAllocatorRef allocator
= (kCFAllocatorUseContext
== self
->_allocator
) ? self
: self
->_allocator
;
388 return CFStringCreateWithFormat(allocator
, NULL
, CFSTR("<CFAllocator %p [%p]>{info = %p}"), cf
, allocator
, self
->_context
.info
);
389 // CF: should use copyDescription function here to describe info field
390 // remember to release value returned from copydescr function when this happens
393 __private_extern__ CFAllocatorRef
__CFAllocatorGetAllocator(CFTypeRef cf
) {
394 CFAllocatorRef allocator
= (CFAllocatorRef
)cf
;
395 return (kCFAllocatorUseContext
== allocator
->_allocator
) ? allocator
: allocator
->_allocator
;
398 __private_extern__
void __CFAllocatorDeallocate(CFTypeRef cf
) {
399 CFAllocatorRef self
= (CFAllocatorRef
)cf
;
400 CFAllocatorRef allocator
= self
->_allocator
;
401 CFAllocatorReleaseCallBack releaseFunc
= __CFAllocatorGetReleaseFunction(&self
->_context
);
402 if (kCFAllocatorUseContext
== allocator
) {
403 /* Rather a chicken and egg problem here, so we do things
404 in the reverse order from what was done at create time. */
405 CFAllocatorDeallocateCallBack deallocateFunc
= __CFAllocatorGetDeallocateFunction(&self
->_context
);
406 void *info
= self
->_context
.info
;
407 if (NULL
!= deallocateFunc
) {
408 INVOKE_CALLBACK2(deallocateFunc
, (void *)self
, info
);
410 if (NULL
!= releaseFunc
) {
411 INVOKE_CALLBACK1(releaseFunc
, info
);
414 if (NULL
!= releaseFunc
) {
415 INVOKE_CALLBACK1(releaseFunc
, self
->_context
.info
);
417 _CFAllocatorDeallocateGC(allocator
, (void *)self
);
421 static CFTypeID __kCFAllocatorTypeID
= _kCFRuntimeNotATypeID
;
423 static const CFRuntimeClass __CFAllocatorClass
= {
432 __CFAllocatorCopyDescription
435 __private_extern__
void __CFAllocatorInitialize(void) {
436 __kCFAllocatorTypeID
= _CFRuntimeRegisterClass(&__CFAllocatorClass
);
438 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorSystemDefault
, __kCFAllocatorTypeID
);
439 __kCFAllocatorSystemDefault
._base
._cfisa
= __CFISAForTypeID(__kCFAllocatorTypeID
);
440 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
441 __kCFAllocatorSystemDefault
._context
.info
= (kCFUseCollectableAllocator
? auto_zone() : malloc_default_zone());
442 memset(malloc_default_zone(), 0, 2 * sizeof(void *));
444 __kCFAllocatorSystemDefault
._allocator
= kCFAllocatorSystemDefault
;
446 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMalloc
, __kCFAllocatorTypeID
);
447 __kCFAllocatorMalloc
._base
._cfisa
= __CFISAForTypeID(__kCFAllocatorTypeID
);
448 __kCFAllocatorMalloc
._allocator
= kCFAllocatorSystemDefault
;
450 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
451 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMallocZone
, __kCFAllocatorTypeID
);
452 __kCFAllocatorMallocZone
._base
._cfisa
= __CFISAForTypeID(__kCFAllocatorTypeID
);
453 __kCFAllocatorMallocZone
._allocator
= kCFAllocatorSystemDefault
;
454 __kCFAllocatorMallocZone
._context
.info
= malloc_default_zone();
457 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorNull
, __kCFAllocatorTypeID
);
458 __kCFAllocatorNull
._base
._cfisa
= __CFISAForTypeID(__kCFAllocatorTypeID
);
459 __kCFAllocatorNull
._allocator
= kCFAllocatorSystemDefault
;
463 CFTypeID
CFAllocatorGetTypeID(void) {
464 return __kCFAllocatorTypeID
;
467 CFAllocatorRef
CFAllocatorGetDefault(void) {
468 return __CFGetDefaultAllocator();
471 void CFAllocatorSetDefault(CFAllocatorRef allocator
) {
472 CFAllocatorRef current
= __CFGetDefaultAllocator();
474 if (NULL
!= allocator
) {
475 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
478 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
479 if (allocator
&& allocator
->_base
._cfisa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
480 return; // require allocator to this function to be an allocator
483 if (NULL
!= allocator
&& allocator
!= current
) {
484 if (current
) CFRelease(current
);
486 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
487 // extra retain not needed here, since we never attempt cleanup of this key
488 pthread_setspecific(__CFTSDKeyAllocator
, allocator
);
490 // We retain an extra time so that anything set as the default
491 // allocator never goes away.
493 __CFGetThreadSpecificData_inline()->_allocator
= (void *)allocator
;
498 static CFAllocatorRef
__CFAllocatorCreate(CFAllocatorRef allocator
, CFAllocatorContext
*context
) {
499 struct __CFAllocator
*memory
= NULL
;
500 CFAllocatorRetainCallBack retainFunc
;
501 CFAllocatorAllocateCallBack allocateFunc
;
503 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
504 if (allocator
&& kCFAllocatorUseContext
!= allocator
&& allocator
->_base
._cfisa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
505 return NULL
; // require allocator to this function to be an allocator
508 retainFunc
= context
->retain
;
509 FAULT_CALLBACK((void **)&retainFunc
);
510 allocateFunc
= context
->allocate
;
511 FAULT_CALLBACK((void **)&allocateFunc
);
512 if (NULL
!= retainFunc
) {
513 retainedInfo
= (void *)INVOKE_CALLBACK1(retainFunc
, context
->info
);
515 retainedInfo
= context
->info
;
517 // We don't use _CFRuntimeCreateInstance()
518 if (kCFAllocatorUseContext
== allocator
) {
521 memory
= (struct __CFAllocator
*)INVOKE_CALLBACK3(allocateFunc
, sizeof(struct __CFAllocator
), 0, retainedInfo
);
523 if (NULL
== memory
) {
527 allocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : allocator
;
528 memory
= (struct __CFAllocator
*)CFAllocatorAllocate(allocator
, sizeof(struct __CFAllocator
), __kCFAllocatorGCObjectMemory
);
529 if (__CFOASafe
) __CFSetLastAllocationEventName(memory
, "CFAllocator");
530 if (NULL
== memory
) {
534 memory
->_base
._cfisa
= 0;
536 memory
->_base
._rc
= 1;
538 memory
->_base
._cfinfo
[CF_RC_BITS
] = 1;
540 memory
->_base
._cfinfo
[CF_INFO_BITS
] = 0;
541 _CFRuntimeSetInstanceTypeID(memory
, __kCFAllocatorTypeID
);
542 memory
->_base
._cfisa
= __CFISAForTypeID(__kCFAllocatorTypeID
);
543 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
544 memory
->size
= __CFAllocatorCustomSize
;
545 memory
->malloc
= __CFAllocatorCustomMalloc
;
546 memory
->calloc
= __CFAllocatorCustomCalloc
;
547 memory
->valloc
= __CFAllocatorCustomValloc
;
548 memory
->free
= __CFAllocatorCustomFree
;
549 memory
->realloc
= __CFAllocatorCustomRealloc
;
550 memory
->destroy
= __CFAllocatorCustomDestroy
;
551 memory
->zone_name
= "Custom CFAllocator";
552 memory
->batch_malloc
= NULL
;
553 memory
->batch_free
= NULL
;
554 memory
->introspect
= &__CFAllocatorZoneIntrospect
;
555 memory
->reserved5
= NULL
;
557 memory
->_allocator
= allocator
;
558 memory
->_context
.version
= context
->version
;
559 memory
->_context
.info
= retainedInfo
;
560 memory
->_context
.retain
= retainFunc
;
561 memory
->_context
.release
= context
->release
;
562 FAULT_CALLBACK((void **)&(memory
->_context
.release
));
563 memory
->_context
.copyDescription
= context
->copyDescription
;
564 FAULT_CALLBACK((void **)&(memory
->_context
.copyDescription
));
565 memory
->_context
.allocate
= allocateFunc
;
566 memory
->_context
.reallocate
= context
->reallocate
;
567 FAULT_CALLBACK((void **)&(memory
->_context
.reallocate
));
568 memory
->_context
.deallocate
= context
->deallocate
;
569 FAULT_CALLBACK((void **)&(memory
->_context
.deallocate
));
570 memory
->_context
.preferredSize
= context
->preferredSize
;
571 FAULT_CALLBACK((void **)&(memory
->_context
.preferredSize
));
576 CFAllocatorRef
CFAllocatorCreate(CFAllocatorRef allocator
, CFAllocatorContext
*context
) {
577 return __CFAllocatorCreate(allocator
, context
);
580 void *CFAllocatorAllocate(CFAllocatorRef allocator
, CFIndex size
, CFOptionFlags hint
) {
581 CFAllocatorAllocateCallBack allocateFunc
;
583 allocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : allocator
;
584 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED)
585 if (allocator
->_base
._cfisa
== __CFISAForTypeID(__kCFAllocatorTypeID
)) {
586 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
589 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
591 if (0 == size
) return NULL
;
592 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
593 if (allocator
->_base
._cfisa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
594 return malloc_zone_malloc((malloc_zone_t
*)allocator
, size
);
597 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
598 newptr
= auto_zone_allocate_object((auto_zone_t
*)allocator
->_context
.info
, size
, CF_GET_GC_MEMORY_TYPE(hint
), true, false);
601 allocateFunc
= __CFAllocatorGetAllocateFunction(&allocator
->_context
);
603 newptr
= (void *)INVOKE_CALLBACK3(allocateFunc
, size
, hint
, allocator
->_context
.info
);
609 void *CFAllocatorReallocate(CFAllocatorRef allocator
, void *ptr
, CFIndex newsize
, CFOptionFlags hint
) {
610 CFAllocatorAllocateCallBack allocateFunc
;
611 CFAllocatorReallocateCallBack reallocateFunc
;
612 CFAllocatorDeallocateCallBack deallocateFunc
;
614 allocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : allocator
;
615 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED)
616 if (allocator
->_base
._cfisa
== __CFISAForTypeID(__kCFAllocatorTypeID
)) {
617 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
620 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
622 if (NULL
== ptr
&& 0 < newsize
) {
623 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
624 if (allocator
->_base
._cfisa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
625 return malloc_zone_malloc((malloc_zone_t
*)allocator
, newsize
);
629 allocateFunc
= __CFAllocatorGetAllocateFunction(&allocator
->_context
);
631 newptr
= (void *)INVOKE_CALLBACK3(allocateFunc
, newsize
, hint
, allocator
->_context
.info
);
635 if (NULL
!= ptr
&& 0 == newsize
) {
636 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
637 if (allocator
->_base
._cfisa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
639 size_t size
= malloc_size(ptr
);
640 if (size
) memset(ptr
, 0xCC, size
);
642 malloc_zone_free((malloc_zone_t
*)allocator
, ptr
);
646 deallocateFunc
= __CFAllocatorGetDeallocateFunction(&allocator
->_context
);
647 if (NULL
!= deallocateFunc
) {
648 INVOKE_CALLBACK2(deallocateFunc
, ptr
, allocator
->_context
.info
);
652 if (NULL
== ptr
&& 0 == newsize
) return NULL
;
653 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
654 if (allocator
->_base
._cfisa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
655 return malloc_zone_realloc((malloc_zone_t
*)allocator
, ptr
, newsize
);
658 reallocateFunc
= __CFAllocatorGetReallocateFunction(&allocator
->_context
);
659 if (NULL
== reallocateFunc
) return NULL
;
660 newptr
= (void *)INVOKE_CALLBACK4(reallocateFunc
, ptr
, newsize
, hint
, allocator
->_context
.info
);
664 void CFAllocatorDeallocate(CFAllocatorRef allocator
, void *ptr
) {
665 CFAllocatorDeallocateCallBack deallocateFunc
;
666 allocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : allocator
;
667 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED)
668 if (allocator
->_base
._cfisa
== __CFISAForTypeID(__kCFAllocatorTypeID
)) {
669 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
672 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
674 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
675 if (allocator
->_base
._cfisa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
677 size_t size
= malloc_size(ptr
);
678 if (size
) memset(ptr
, 0xCC, size
);
680 return malloc_zone_free((malloc_zone_t
*)allocator
, ptr
);
683 deallocateFunc
= __CFAllocatorGetDeallocateFunction(&allocator
->_context
);
684 if (NULL
!= ptr
&& NULL
!= deallocateFunc
) {
685 INVOKE_CALLBACK2(deallocateFunc
, ptr
, allocator
->_context
.info
);
689 CFIndex
CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator
, CFIndex size
, CFOptionFlags hint
) {
690 CFAllocatorPreferredSizeCallBack prefFunc
;
692 allocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : allocator
;
693 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED)
694 if (allocator
->_base
._cfisa
== __CFISAForTypeID(__kCFAllocatorTypeID
)) {
695 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
698 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
700 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
701 if (allocator
->_base
._cfisa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
702 return malloc_good_size(size
);
705 prefFunc
= __CFAllocatorGetPreferredSizeFunction(&allocator
->_context
);
706 if (0 < size
&& NULL
!= prefFunc
) {
707 newsize
= (CFIndex
)(INVOKE_CALLBACK3(prefFunc
, size
, hint
, allocator
->_context
.info
));
709 if (newsize
< size
) newsize
= size
;
713 void CFAllocatorGetContext(CFAllocatorRef allocator
, CFAllocatorContext
*context
) {
714 allocator
= (NULL
== allocator
) ? __CFGetDefaultAllocator() : allocator
;
715 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED)
716 if (allocator
->_base
._cfisa
== __CFISAForTypeID(__kCFAllocatorTypeID
)) {
717 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
720 __CFGenericValidateType(allocator
, __kCFAllocatorTypeID
);
722 CFAssert1(0 == context
->version
, __kCFLogAssertion
, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__
);
723 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
724 if (allocator
->_base
._cfisa
!= __CFISAForTypeID(__kCFAllocatorTypeID
)) { // malloc_zone_t *
728 context
->version
= 0;
729 context
->info
= allocator
->_context
.info
;
730 context
->retain
= __CFAllocatorGetRetainFunction(&allocator
->_context
);
731 context
->release
= __CFAllocatorGetReleaseFunction(&allocator
->_context
);
732 context
->copyDescription
= __CFAllocatorGetCopyDescriptionFunction(&allocator
->_context
);
733 context
->allocate
= __CFAllocatorGetAllocateFunction(&allocator
->_context
);
734 context
->reallocate
= __CFAllocatorGetReallocateFunction(&allocator
->_context
);
735 context
->deallocate
= __CFAllocatorGetDeallocateFunction(&allocator
->_context
);
736 context
->preferredSize
= __CFAllocatorGetPreferredSizeFunction(&allocator
->_context
);
737 #if DEPLOYMENT_TARGET_MACOSX && defined(__ppc__)
738 context
->retain
= (void *)((uintptr_t)context
->retain
& ~0x3);
739 context
->release
= (void *)((uintptr_t)context
->release
& ~0x3);
740 context
->copyDescription
= (void *)((uintptr_t)context
->copyDescription
& ~0x3);
741 context
->allocate
= (void *)((uintptr_t)context
->allocate
& ~0x3);
742 context
->reallocate
= (void *)((uintptr_t)context
->reallocate
& ~0x3);
743 context
->deallocate
= (void *)((uintptr_t)context
->deallocate
& ~0x3);
744 context
->preferredSize
= (void *)((uintptr_t)context
->preferredSize
& ~0x3);
748 __private_extern__
void *_CFAllocatorAllocateGC(CFAllocatorRef allocator
, CFIndex size
, CFOptionFlags hint
)
750 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
))
751 return auto_zone_allocate_object((auto_zone_t
*)kCFAllocatorSystemDefault
->_context
.info
, size
, CF_GET_GC_MEMORY_TYPE(hint
), false, false);
753 return CFAllocatorAllocate(allocator
, size
, hint
);
756 __private_extern__
void *_CFAllocatorReallocateGC(CFAllocatorRef allocator
, void *ptr
, CFIndex newsize
, CFOptionFlags hint
)
758 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) {
759 if (ptr
&& (newsize
== 0)) {
760 return NULL
; // equivalent to _CFAllocatorDeallocateGC.
763 return auto_zone_allocate_object((auto_zone_t
*)kCFAllocatorSystemDefault
->_context
.info
, newsize
, CF_GET_GC_MEMORY_TYPE(hint
), false, false); // eq. to _CFAllocator
766 // otherwise, auto_realloc() now preserves layout type and refCount.
767 return CFAllocatorReallocate(allocator
, ptr
, newsize
, hint
);
770 __private_extern__
void _CFAllocatorDeallocateGC(CFAllocatorRef allocator
, void *ptr
)
772 // when running GC, don't deallocate.
773 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator
)) CFAllocatorDeallocate(allocator
, ptr
);
776 // -------- -------- -------- -------- -------- -------- -------- --------
778 #if DEPLOYMENT_TARGET_WINDOWS
779 __private_extern__ DWORD __CFTSDKey
= 0xFFFFFFFF;
782 #if DEPLOYMENT_TARGET_WINDOWS
783 extern void __CFStringEncodingICUThreadDataCleaner(void *);
785 // Called for each thread as it exits
786 __private_extern__
void __CFFinalizeThreadData(void *arg
) {
787 __CFThreadSpecificData
*tsd
= (__CFThreadSpecificData
*)TlsGetValue(__CFTSDKey
);
788 TlsSetValue(__CFTSDKey
, NULL
);
789 if (NULL
== tsd
) return;
790 if (tsd
->_allocator
) CFRelease(tsd
->_allocator
);
791 if (tsd
->_messageHook
) UnhookWindowsHookEx(tsd
->_messageHook
);
792 if (tsd
->_icuThreadData
) __CFStringEncodingICUThreadDataCleaner(tsd
->_icuThreadData
);
793 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, tsd
);
796 __private_extern__ __CFThreadSpecificData
*__CFGetThreadSpecificData(void) {
797 __CFThreadSpecificData
*data
;
798 data
= (__CFThreadSpecificData
*)TlsGetValue(__CFTSDKey
);
802 data
= (__CFThreadSpecificData
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(__CFThreadSpecificData
), 0);
803 if (__CFOASafe
) __CFSetLastAllocationEventName(data
, "CFUtilities (thread-data)");
804 memset(data
, 0, sizeof(__CFThreadSpecificData
));
805 TlsSetValue(__CFTSDKey
, data
);
810 __private_extern__
void __CFBaseInitialize(void) {
811 #if DEPLOYMENT_TARGET_WINDOWS
812 __CFTSDKey
= TlsAlloc();
816 #if DEPLOYMENT_TARGET_WINDOWS
817 __private_extern__
void __CFBaseCleanup(void) {
823 CFRange
__CFRangeMake(CFIndex loc
, CFIndex len
) {
825 range
.location
= loc
;
835 static struct __CFNull __kCFNull
= {
836 INIT_CFRUNTIME_BASE()
838 const CFNullRef kCFNull
= &__kCFNull
;
840 static CFStringRef
__CFNullCopyDescription(CFTypeRef cf
) {
841 return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFNull %p [%p]>"), cf
, CFGetAllocator(cf
));
844 static CFStringRef
__CFNullCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
845 return (CFStringRef
)CFRetain(CFSTR("null"));
848 static void __CFNullDeallocate(CFTypeRef cf
) {
849 CFAssert(false, __kCFLogAssertion
, "Deallocated CFNull!");
852 static CFTypeID __kCFNullTypeID
= _kCFRuntimeNotATypeID
;
854 static const CFRuntimeClass __CFNullClass
= {
862 __CFNullCopyFormattingDescription
,
863 __CFNullCopyDescription
866 __private_extern__
void __CFNullInitialize(void) {
867 __kCFNullTypeID
= _CFRuntimeRegisterClass(&__CFNullClass
);
868 _CFRuntimeSetInstanceTypeID(&__kCFNull
, __kCFNullTypeID
);
869 __kCFNull
._base
._cfisa
= __CFISAForTypeID(__kCFNullTypeID
);
872 CFTypeID
CFNullGetTypeID(void) {
873 return __kCFNullTypeID
;
876 void CFCollection_non_gc_storage_error(void) { }
879 static int hasCFM
= 0;
881 void _CFRuntimeSetCFMPresent(void *addr
) {
885 #if DEPLOYMENT_TARGET_MACOSX && defined(__ppc__)
887 /* See comments below */
888 __private_extern__
void __CF_FAULT_CALLBACK(void **ptr
) {
889 uintptr_t p
= (uintptr_t)*ptr
;
890 if ((0 == p
) || (p
& 0x1)) return;
891 if (0 == hasCFM
|| (0x90000000 <= p
&& p
< 0xA0000000)) {
892 *ptr
= (void *)(p
| 0x1);
894 static CFMutableDictionaryRef cache
= NULL
;
895 static CFSpinLock_t lock
= CFSpinLockInit
;
896 uintptr_t known
= ~0;
898 if (!cache
|| !CFDictionaryGetValueIfPresent(cache
, (const void *)p
, (const void **)&known
)) {
900 cache
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, NULL
, NULL
);
903 known
= dladdr((void *)p
, &info
);
904 CFDictionarySetValue(cache
, (const void *)p
, (const void *)known
);
906 __CFSpinUnlock(&lock
);
907 *ptr
= (void *)(p
| (known
? 0x1 : 0x3));
912 Jump to callback function. r2 is not saved and restored
913 in the jump-to-CFM case, since we assume that dyld code
914 never uses that register and that CF is dyld.
916 There are three states for (ptr & 0x3):
917 0b00: check not yet done (or not going to be done, and is a dyld func ptr)
918 0b01: check done, dyld function pointer
919 0b11: check done, CFM tvector pointer
920 (but a NULL callback just stays NULL)
922 There may be up to 5 word-sized arguments. Floating point
923 arguments can be done, but count as two word arguments.
924 Return value can be integral or real.
927 /* Keep this assembly at the bottom of the source file! */
932 ".private_extern ___CF_INVOKE_CALLBACK\n"
933 "___CF_INVOKE_CALLBACK:\n"
934 "rlwinm r12,r3,0,0,29\n"
944 "Lcall: mtspr ctr,r12\n"
950 // void __HALT(void);
956 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
957 ".private_extern ___HALT\n"
966 #if defined(__i386__) || defined(__x86_64__)
967 #if defined(_MSC_VER)
975 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
976 ".private_extern ___HALT\n"