]> git.saurik.com Git - apple/cf.git/blob - CFBase.c
CF-744.12.tar.gz
[apple/cf.git] / CFBase.c
1 /*
2 * Copyright (c) 2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /* CFBase.c
25 Copyright (c) 1998-2012, Apple Inc. All rights reserved.
26 Responsibility: Christopher Kane
27 */
28
29 #include <CoreFoundation/CFBase.h>
30 #include "CFInternal.h"
31 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
32 #include <pthread.h>
33 #endif
34 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
35 #include <malloc/malloc.h>
36 #include <mach/mach.h>
37 #include <dlfcn.h>
38 #endif
39 #include <stdlib.h>
40 #include <string.h>
41
42 // -------- -------- -------- -------- -------- -------- -------- --------
43
44 struct __CFAllocator {
45 CFRuntimeBase _base;
46 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
47 // CFAllocator structure must match struct _malloc_zone_t!
48 // The first two reserved fields in struct _malloc_zone_t are for us with CFRuntimeBase
49 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 */
50 void *(*malloc)(struct _malloc_zone_t *zone, size_t size);
51 void *(*calloc)(struct _malloc_zone_t *zone, size_t num_items, size_t size); /* same as malloc, but block returned is set to zero */
52 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 */
53 void (*free)(struct _malloc_zone_t *zone, void *ptr);
54 void *(*realloc)(struct _malloc_zone_t *zone, void *ptr, size_t size);
55 void (*destroy)(struct _malloc_zone_t *zone); /* zone is destroyed and all memory reclaimed */
56 const char *zone_name;
57
58 /* Optional batch callbacks; these may be NULL */
59 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) */
60 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 */
61
62 struct malloc_introspection_t *introspect;
63 unsigned version;
64
65 /* aligned memory allocation. The callback may be NULL. */
66 void *(*memalign)(struct _malloc_zone_t *zone, size_t alignment, size_t size);
67
68 /* free a pointer known to be in zone and known to have the given size. The callback may be NULL. */
69 void (*free_definite_size)(struct _malloc_zone_t *zone, void *ptr, size_t size);
70 #endif
71 CFAllocatorRef _allocator;
72 CFAllocatorContext _context;
73 };
74
75 CF_INLINE CFAllocatorRetainCallBack __CFAllocatorGetRetainFunction(const CFAllocatorContext *context) {
76 CFAllocatorRetainCallBack retval = NULL;
77 retval = context->retain;
78 return retval;
79 }
80
81 CF_INLINE CFAllocatorReleaseCallBack __CFAllocatorGetReleaseFunction(const CFAllocatorContext *context) {
82 CFAllocatorReleaseCallBack retval = NULL;
83 retval = context->release;
84 return retval;
85 }
86
87 CF_INLINE CFAllocatorCopyDescriptionCallBack __CFAllocatorGetCopyDescriptionFunction(const CFAllocatorContext *context) {
88 CFAllocatorCopyDescriptionCallBack retval = NULL;
89 retval = context->copyDescription;
90 return retval;
91 }
92
93 CF_INLINE CFAllocatorAllocateCallBack __CFAllocatorGetAllocateFunction(const CFAllocatorContext *context) {
94 CFAllocatorAllocateCallBack retval = NULL;
95 retval = context->allocate;
96 return retval;
97 }
98
99 CF_INLINE CFAllocatorReallocateCallBack __CFAllocatorGetReallocateFunction(const CFAllocatorContext *context) {
100 CFAllocatorReallocateCallBack retval = NULL;
101 retval = context->reallocate;
102 return retval;
103 }
104
105 CF_INLINE CFAllocatorDeallocateCallBack __CFAllocatorGetDeallocateFunction(const CFAllocatorContext *context) {
106 CFAllocatorDeallocateCallBack retval = NULL;
107 retval = context->deallocate;
108 return retval;
109 }
110
111 CF_INLINE CFAllocatorPreferredSizeCallBack __CFAllocatorGetPreferredSizeFunction(const CFAllocatorContext *context) {
112 CFAllocatorPreferredSizeCallBack retval = NULL;
113 retval = context->preferredSize;
114 return retval;
115 }
116
117 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
118
119 __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf);
120
121 static kern_return_t __CFAllocatorZoneIntrospectNoOp(void) {
122 return 0;
123 }
124
125 static boolean_t __CFAllocatorZoneIntrospectTrue(void) {
126 return 1;
127 }
128
129 static size_t __CFAllocatorCustomSize(malloc_zone_t *zone, const void *ptr) {
130 return 0;
131
132 // The only way to implement this with a version 0 allocator would be
133 // for CFAllocator to keep track of all blocks allocated itself, which
134 // could be done, but would be bad for performance, so we don't do it.
135 // size_t (*size)(struct _malloc_zone_t *zone, const void *ptr);
136 /* returns the size of a block or 0 if not in this zone;
137 * must be fast, especially for negative answers */
138 }
139
140 static void *__CFAllocatorCustomMalloc(malloc_zone_t *zone, size_t size) {
141 CFAllocatorRef allocator = (CFAllocatorRef)zone;
142 return CFAllocatorAllocate(allocator, size, 0);
143 }
144
145 static void *__CFAllocatorCustomCalloc(malloc_zone_t *zone, size_t num_items, size_t size) {
146 CFAllocatorRef allocator = (CFAllocatorRef)zone;
147 void *newptr = CFAllocatorAllocate(allocator, size, 0);
148 if (newptr) memset(newptr, 0, size);
149 return newptr;
150 }
151
152 static void *__CFAllocatorCustomValloc(malloc_zone_t *zone, size_t size) {
153 CFAllocatorRef allocator = (CFAllocatorRef)zone;
154 if (size >= ULONG_MAX - 2 * vm_page_size) return NULL; // avoid integer overflow plus don't allow all pages to be allocated either
155 void *newptr = CFAllocatorAllocate(allocator, size + vm_page_size, 0);
156 newptr = (void *)round_page((uintptr_t)newptr);
157 return newptr;
158 }
159
160 static void __CFAllocatorCustomFree(malloc_zone_t *zone, void *ptr) {
161 CFAllocatorRef allocator = (CFAllocatorRef)zone;
162 CFAllocatorDeallocate(allocator, ptr);
163 }
164
165 static void *__CFAllocatorCustomRealloc(malloc_zone_t *zone, void *ptr, size_t size) {
166 CFAllocatorRef allocator = (CFAllocatorRef)zone;
167 return CFAllocatorReallocate(allocator, ptr, size, 0);
168 }
169
170 static void __CFAllocatorCustomDestroy(malloc_zone_t *zone) {
171 CFAllocatorRef allocator = (CFAllocatorRef)zone;
172 // !!! we do it, and caller of malloc_destroy_zone() assumes
173 // COMPLETE responsibility for the result; NO Apple library
174 // code should be modified as a result of discovering that
175 // some activity results in inconveniences to developers
176 // trying to use malloc_destroy_zone() with a CFAllocatorRef;
177 // that's just too bad for them.
178 __CFAllocatorDeallocate(allocator);
179 }
180
181 static size_t __CFAllocatorCustomGoodSize(malloc_zone_t *zone, size_t size) {
182 CFAllocatorRef allocator = (CFAllocatorRef)zone;
183 return CFAllocatorGetPreferredSizeForSize(allocator, size, 0);
184 }
185
186 static struct malloc_introspection_t __CFAllocatorZoneIntrospect = {
187 (void *)__CFAllocatorZoneIntrospectNoOp,
188 (void *)__CFAllocatorCustomGoodSize,
189 (void *)__CFAllocatorZoneIntrospectTrue,
190 (void *)__CFAllocatorZoneIntrospectNoOp,
191 (void *)__CFAllocatorZoneIntrospectNoOp,
192 (void *)__CFAllocatorZoneIntrospectNoOp,
193 (void *)__CFAllocatorZoneIntrospectNoOp,
194 (void *)__CFAllocatorZoneIntrospectNoOp
195 };
196
197 static size_t __CFAllocatorNullSize(malloc_zone_t *zone, const void *ptr) {
198 return 0;
199 }
200
201 static void * __CFAllocatorNullMalloc(malloc_zone_t *zone, size_t size) {
202 return NULL;
203 }
204
205 static void * __CFAllocatorNullCalloc(malloc_zone_t *zone, size_t num_items, size_t size) {
206 return NULL;
207 }
208
209 static void * __CFAllocatorNullValloc(malloc_zone_t *zone, size_t size) {
210 return NULL;
211 }
212
213 static void __CFAllocatorNullFree(malloc_zone_t *zone, void *ptr) {
214 }
215
216 static void * __CFAllocatorNullRealloc(malloc_zone_t *zone, void *ptr, size_t size) {
217 return NULL;
218 }
219
220 static void __CFAllocatorNullDestroy(malloc_zone_t *zone) {
221 }
222
223 static size_t __CFAllocatorNullGoodSize(malloc_zone_t *zone, size_t size) {
224 return size;
225 }
226
227 static struct malloc_introspection_t __CFAllocatorNullZoneIntrospect = {
228 (void *)__CFAllocatorZoneIntrospectNoOp,
229 (void *)__CFAllocatorNullGoodSize,
230 (void *)__CFAllocatorZoneIntrospectTrue,
231 (void *)__CFAllocatorZoneIntrospectNoOp,
232 (void *)__CFAllocatorZoneIntrospectNoOp,
233 (void *)__CFAllocatorZoneIntrospectNoOp,
234 (void *)__CFAllocatorZoneIntrospectNoOp,
235 (void *)__CFAllocatorZoneIntrospectNoOp
236 };
237
238 static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) {
239 return malloc_zone_malloc(info, size);
240 }
241
242 static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
243 return malloc_zone_realloc(info, ptr, newsize);
244 }
245
246 static void __CFAllocatorSystemDeallocate(void *ptr, void *info) {
247 #if defined(DEBUG)
248 size_t size = malloc_size(ptr);
249 if (size) memset(ptr, 0xCC, size);
250 #endif
251 malloc_zone_free(info, ptr);
252 }
253
254 #else
255
256 static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) {
257 return malloc(size);
258 }
259
260 static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
261 return realloc(ptr, newsize);
262 }
263
264 static void __CFAllocatorSystemDeallocate(void *ptr, void *info) {
265 free(ptr);
266 }
267 #endif
268
269 static void *__CFAllocatorNullAllocate(CFIndex size, CFOptionFlags hint, void *info) {
270 return NULL;
271 }
272
273 static void *__CFAllocatorNullReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
274 return NULL;
275 }
276
277 #if defined (__cplusplus)
278 static void * __CFAllocatorCPPMalloc(CFIndex allocSize, CFOptionFlags hint, void *info)
279 {
280 return malloc(allocSize);
281 }
282 static void * __CFAllocatorCPPReAlloc(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info)
283 {
284 return realloc(ptr, newsize);
285 }
286 static void __CFAllocatorCPPFree(void *ptr, void *info)
287 {
288 free(ptr);
289 }
290 #endif // C++
291
292
293 static struct __CFAllocator __kCFAllocatorMalloc = {
294 INIT_CFRUNTIME_BASE(),
295 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
296 __CFAllocatorCustomSize,
297 __CFAllocatorCustomMalloc,
298 __CFAllocatorCustomCalloc,
299 __CFAllocatorCustomValloc,
300 __CFAllocatorCustomFree,
301 __CFAllocatorCustomRealloc,
302 __CFAllocatorNullDestroy,
303 "kCFAllocatorMalloc",
304 NULL,
305 NULL,
306 &__CFAllocatorZoneIntrospect,
307 6,
308 NULL,
309 NULL,
310 #endif
311 NULL, // _allocator
312 // Using the malloc functions directly is a total cheat, but works (in C)
313 // because the function signatures match in their common prefix of arguments.
314 // This saves us one hop through an adaptor function.
315 #if !defined (__cplusplus)
316 {0, NULL, NULL, NULL, NULL, (void *)malloc, (void *)realloc, (void *)free, NULL}
317 #else
318 {0, NULL, NULL, NULL, NULL, __CFAllocatorCPPMalloc,__CFAllocatorCPPReAlloc, __CFAllocatorCPPFree, NULL}
319 #endif // __cplusplus
320 };
321
322 static struct __CFAllocator __kCFAllocatorMallocZone = {
323 INIT_CFRUNTIME_BASE(),
324 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
325 __CFAllocatorCustomSize,
326 __CFAllocatorCustomMalloc,
327 __CFAllocatorCustomCalloc,
328 __CFAllocatorCustomValloc,
329 __CFAllocatorCustomFree,
330 __CFAllocatorCustomRealloc,
331 __CFAllocatorNullDestroy,
332 "kCFAllocatorMallocZone",
333 NULL,
334 NULL,
335 &__CFAllocatorZoneIntrospect,
336 6,
337 NULL,
338 NULL,
339 #endif
340 NULL, // _allocator
341 {0, NULL, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL}
342 };
343
344 static struct __CFAllocator __kCFAllocatorSystemDefault = {
345 INIT_CFRUNTIME_BASE(),
346 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
347 __CFAllocatorCustomSize,
348 __CFAllocatorCustomMalloc,
349 __CFAllocatorCustomCalloc,
350 __CFAllocatorCustomValloc,
351 __CFAllocatorCustomFree,
352 __CFAllocatorCustomRealloc,
353 __CFAllocatorNullDestroy,
354 "kCFAllocatorSystemDefault",
355 NULL,
356 NULL,
357 &__CFAllocatorZoneIntrospect,
358 6,
359 NULL,
360 NULL,
361 #endif
362 NULL, // _allocator
363 {0, NULL, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL}
364 };
365
366 static struct __CFAllocator __kCFAllocatorNull = {
367 INIT_CFRUNTIME_BASE(),
368 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
369 __CFAllocatorNullSize,
370 __CFAllocatorNullMalloc,
371 __CFAllocatorNullCalloc,
372 __CFAllocatorNullValloc,
373 __CFAllocatorNullFree,
374 __CFAllocatorNullRealloc,
375 __CFAllocatorNullDestroy,
376 "kCFAllocatorNull",
377 NULL,
378 NULL,
379 &__CFAllocatorNullZoneIntrospect,
380 6,
381 NULL,
382 NULL,
383 #endif
384 NULL, // _allocator
385 {0, NULL, NULL, NULL, NULL, __CFAllocatorNullAllocate, __CFAllocatorNullReallocate, NULL, NULL}
386 };
387
388 const CFAllocatorRef kCFAllocatorDefault = NULL;
389 const CFAllocatorRef kCFAllocatorSystemDefault = &__kCFAllocatorSystemDefault;
390 const CFAllocatorRef kCFAllocatorMalloc = &__kCFAllocatorMalloc;
391 const CFAllocatorRef kCFAllocatorMallocZone = &__kCFAllocatorMallocZone;
392 const CFAllocatorRef kCFAllocatorNull = &__kCFAllocatorNull;
393 const CFAllocatorRef kCFAllocatorUseContext = (CFAllocatorRef)0x03ab;
394 #undef kCFAllocatorSystemDefaultGCRefZero
395 #undef kCFAllocatorDefaultGCRefZero
396 const CFAllocatorRef kCFAllocatorSystemDefaultGCRefZero = (CFAllocatorRef)0x03ad;
397 const CFAllocatorRef kCFAllocatorDefaultGCRefZero = (CFAllocatorRef)0x03af;
398
399 static CFStringRef __CFAllocatorCopyDescription(CFTypeRef cf) {
400 CFAllocatorRef self = (CFAllocatorRef)cf;
401 CFAllocatorRef allocator = (kCFAllocatorUseContext == self->_allocator) ? self : self->_allocator;
402 return CFStringCreateWithFormat(allocator, NULL, CFSTR("<CFAllocator %p [%p]>{info = %p}"), cf, allocator, self->_context.info);
403 // CF: should use copyDescription function here to describe info field
404 // remember to release value returned from copydescr function when this happens
405 }
406
407 __private_extern__ CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef cf) {
408 CFAllocatorRef allocator = (CFAllocatorRef)cf;
409 return (kCFAllocatorUseContext == allocator->_allocator) ? allocator : allocator->_allocator;
410 }
411
412 __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf) {
413 CFAllocatorRef self = (CFAllocatorRef)cf;
414 CFAllocatorRef allocator = self->_allocator;
415 CFAllocatorReleaseCallBack releaseFunc = __CFAllocatorGetReleaseFunction(&self->_context);
416 if (kCFAllocatorUseContext == allocator) {
417 /* Rather a chicken and egg problem here, so we do things
418 in the reverse order from what was done at create time. */
419 CFAllocatorDeallocateCallBack deallocateFunc = __CFAllocatorGetDeallocateFunction(&self->_context);
420 void *info = self->_context.info;
421 if (NULL != deallocateFunc) {
422 INVOKE_CALLBACK2(deallocateFunc, (void *)self, info);
423 }
424 if (NULL != releaseFunc) {
425 INVOKE_CALLBACK1(releaseFunc, info);
426 }
427 } else {
428 if (NULL != releaseFunc) {
429 INVOKE_CALLBACK1(releaseFunc, self->_context.info);
430 }
431 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) CFAllocatorDeallocate(allocator, (void *)self);
432 }
433 }
434
435 static CFTypeID __kCFAllocatorTypeID = _kCFRuntimeNotATypeID;
436
437 static const CFRuntimeClass __CFAllocatorClass = {
438 0,
439 "CFAllocator",
440 NULL, // init
441 NULL, // copy
442 NULL,
443 NULL, // equal
444 NULL, // hash
445 NULL, //
446 __CFAllocatorCopyDescription
447 };
448
449 __private_extern__ void __CFAllocatorInitialize(void) {
450 __kCFAllocatorTypeID = _CFRuntimeRegisterClass(&__CFAllocatorClass);
451
452 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorSystemDefault, __kCFAllocatorTypeID);
453 __kCFAllocatorSystemDefault._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID);
454 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
455 __kCFAllocatorSystemDefault._context.info = (kCFUseCollectableAllocator ? objc_collectableZone() : malloc_default_zone());
456 #endif
457 __kCFAllocatorSystemDefault._allocator = kCFAllocatorSystemDefault;
458
459 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMalloc, __kCFAllocatorTypeID);
460 __kCFAllocatorMalloc._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID);
461 __kCFAllocatorMalloc._allocator = kCFAllocatorSystemDefault;
462
463 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
464 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMallocZone, __kCFAllocatorTypeID);
465 __kCFAllocatorMallocZone._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID);
466 __kCFAllocatorMallocZone._allocator = kCFAllocatorSystemDefault;
467 __kCFAllocatorMallocZone._context.info = malloc_default_zone();
468 #endif
469
470 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorNull, __kCFAllocatorTypeID);
471 __kCFAllocatorNull._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID);
472 __kCFAllocatorNull._allocator = kCFAllocatorSystemDefault;
473
474 }
475
476 CFTypeID CFAllocatorGetTypeID(void) {
477 return __kCFAllocatorTypeID;
478 }
479
480 CFAllocatorRef CFAllocatorGetDefault(void) {
481 return __CFGetDefaultAllocator();
482 }
483
484 void CFAllocatorSetDefault(CFAllocatorRef allocator) {
485 if (kCFAllocatorSystemDefaultGCRefZero == allocator || kCFAllocatorDefaultGCRefZero == allocator) {
486 HALT;
487 }
488 CFAllocatorRef current = __CFGetDefaultAllocator();
489 #if defined(DEBUG)
490 if (NULL != allocator) {
491 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
492 }
493 #endif
494 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
495 if (allocator && allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
496 return; // require allocator to this function to be an allocator
497 }
498 #endif
499 if (NULL != allocator && allocator != current) {
500 if (current) CFRelease(current);
501 CFRetain(allocator);
502 // We retain an extra time so that anything set as the default
503 // allocator never goes away.
504 CFRetain(allocator);
505 _CFSetTSD(__CFTSDKeyAllocator, (void *)allocator, NULL);
506 }
507 }
508
509 static CFAllocatorRef __CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) {
510 struct __CFAllocator *memory = NULL;
511 CFAllocatorRetainCallBack retainFunc;
512 CFAllocatorAllocateCallBack allocateFunc;
513 void *retainedInfo;
514 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
515 if (allocator && kCFAllocatorUseContext != allocator && allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
516 return NULL; // require allocator to this function to be an allocator
517 }
518 #endif
519 retainFunc = context->retain;
520 FAULT_CALLBACK((void **)&retainFunc);
521 allocateFunc = context->allocate;
522 FAULT_CALLBACK((void **)&allocateFunc);
523 if (NULL != retainFunc) {
524 retainedInfo = (void *)INVOKE_CALLBACK1(retainFunc, context->info);
525 } else {
526 retainedInfo = context->info;
527 }
528 // We don't use _CFRuntimeCreateInstance()
529 if (kCFAllocatorUseContext == allocator) {
530 memory = NULL;
531 if (allocateFunc) {
532 memory = (struct __CFAllocator *)INVOKE_CALLBACK3(allocateFunc, sizeof(struct __CFAllocator), 0, retainedInfo);
533 }
534 if (NULL == memory) {
535 return NULL;
536 }
537 } else {
538 allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
539 memory = (struct __CFAllocator *)CFAllocatorAllocate(allocator, sizeof(struct __CFAllocator), __kCFAllocatorGCObjectMemory);
540 if (NULL == memory) {
541 return NULL;
542 }
543 if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFAllocator");
544 }
545 memset(memory, 0, sizeof(CFRuntimeBase));
546 memory->_base._cfisa = 0;
547 #if __LP64__
548 memory->_base._rc = 1;
549 #else
550 memory->_base._cfinfo[CF_RC_BITS] = 1;
551 #endif
552 memory->_base._cfinfo[CF_INFO_BITS] = 0;
553 _CFRuntimeSetInstanceTypeID(memory, __kCFAllocatorTypeID);
554 memory->_base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID);
555 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
556 memory->size = __CFAllocatorCustomSize;
557 memory->malloc = __CFAllocatorCustomMalloc;
558 memory->calloc = __CFAllocatorCustomCalloc;
559 memory->valloc = __CFAllocatorCustomValloc;
560 memory->free = __CFAllocatorCustomFree;
561 memory->realloc = __CFAllocatorCustomRealloc;
562 memory->destroy = __CFAllocatorCustomDestroy;
563 memory->zone_name = "Custom CFAllocator";
564 memory->batch_malloc = NULL;
565 memory->batch_free = NULL;
566 memory->introspect = &__CFAllocatorZoneIntrospect;
567 memory->version = 6;
568 memory->memalign = NULL;
569 memory->free_definite_size = NULL;
570 #endif
571 memory->_allocator = allocator;
572 memory->_context.version = context->version;
573 memory->_context.info = retainedInfo;
574 memory->_context.retain = retainFunc;
575 memory->_context.release = context->release;
576 FAULT_CALLBACK((void **)&(memory->_context.release));
577 memory->_context.copyDescription = context->copyDescription;
578 FAULT_CALLBACK((void **)&(memory->_context.copyDescription));
579 memory->_context.allocate = allocateFunc;
580 memory->_context.reallocate = context->reallocate;
581 FAULT_CALLBACK((void **)&(memory->_context.reallocate));
582 memory->_context.deallocate = context->deallocate;
583 FAULT_CALLBACK((void **)&(memory->_context.deallocate));
584 memory->_context.preferredSize = context->preferredSize;
585 FAULT_CALLBACK((void **)&(memory->_context.preferredSize));
586
587 return memory;
588 }
589
590 CFAllocatorRef CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) {
591 return __CFAllocatorCreate(allocator, context);
592 }
593
594 void *CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) {
595 CFAllocatorAllocateCallBack allocateFunc;
596 void *newptr = NULL;
597
598 Boolean initialRefcountOne = true;
599 if (kCFAllocatorSystemDefaultGCRefZero == allocator) {
600 allocator = kCFAllocatorSystemDefault;
601 initialRefcountOne = false;
602 } else if (kCFAllocatorDefaultGCRefZero == allocator) {
603 // Under GC, we can't use just any old allocator when the GCRefZero allocator was requested
604 allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator();
605 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) initialRefcountOne = false;
606 } else if (NULL == allocator) {
607 allocator = __CFGetDefaultAllocator();
608 }
609
610 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI)
611 if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
612 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
613 }
614 #else
615 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
616 #endif
617 if (0 == size) return NULL;
618 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
619 if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
620 return malloc_zone_malloc((malloc_zone_t *)allocator, size);
621 }
622 #endif
623 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
624 newptr = auto_zone_allocate_object((auto_zone_t*)allocator->_context.info, size, CF_GET_GC_MEMORY_TYPE(hint), initialRefcountOne, false);
625 } else {
626 newptr = NULL;
627 allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context);
628 if (allocateFunc) {
629 newptr = (void *)INVOKE_CALLBACK3(allocateFunc, size, hint, allocator->_context.info);
630 }
631 }
632 return newptr;
633 }
634
635 void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint) {
636 CFAllocatorAllocateCallBack allocateFunc;
637 CFAllocatorReallocateCallBack reallocateFunc;
638 CFAllocatorDeallocateCallBack deallocateFunc;
639 void *newptr;
640
641 if (kCFAllocatorSystemDefaultGCRefZero == allocator) {
642 allocator = kCFAllocatorSystemDefault;
643 } else if (kCFAllocatorDefaultGCRefZero == allocator) {
644 // Under GC, we can't use just any old allocator when the GCRefZero allocator was requested
645 allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator();
646 } else if (NULL == allocator) {
647 allocator = __CFGetDefaultAllocator();
648 }
649
650 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI)
651 if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
652 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
653 }
654 #else
655 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
656 #endif
657 if (NULL == ptr && 0 < newsize) {
658 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
659 if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
660 return malloc_zone_malloc((malloc_zone_t *)allocator, newsize);
661 }
662 #endif
663 newptr = NULL;
664 allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context);
665 if (allocateFunc) {
666 newptr = (void *)INVOKE_CALLBACK3(allocateFunc, newsize, hint, allocator->_context.info);
667 }
668 return newptr;
669 }
670 if (NULL != ptr && 0 == newsize) {
671 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
672 if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
673 #if defined(DEBUG)
674 size_t size = malloc_size(ptr);
675 if (size) memset(ptr, 0xCC, size);
676 #endif
677 malloc_zone_free((malloc_zone_t *)allocator, ptr);
678 return NULL;
679 }
680 #endif
681 deallocateFunc = __CFAllocatorGetDeallocateFunction(&allocator->_context);
682 if (NULL != deallocateFunc) {
683 INVOKE_CALLBACK2(deallocateFunc, ptr, allocator->_context.info);
684 }
685 return NULL;
686 }
687 if (NULL == ptr && 0 == newsize) return NULL;
688 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
689 if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
690 return malloc_zone_realloc((malloc_zone_t *)allocator, ptr, newsize);
691 }
692 #endif
693 reallocateFunc = __CFAllocatorGetReallocateFunction(&allocator->_context);
694 if (NULL == reallocateFunc) return NULL;
695 newptr = (void *)INVOKE_CALLBACK4(reallocateFunc, ptr, newsize, hint, allocator->_context.info);
696 return newptr;
697 }
698
699 void CFAllocatorDeallocate(CFAllocatorRef allocator, void *ptr) {
700 CFAllocatorDeallocateCallBack deallocateFunc;
701
702 if (kCFAllocatorSystemDefaultGCRefZero == allocator) {
703 if (_CFAllocatorIsGCRefZero(allocator)) return;
704 allocator = kCFAllocatorSystemDefault;
705 } else if (kCFAllocatorDefaultGCRefZero == allocator) {
706 // Under GC, we can't use just any old allocator when the GCRefZero allocator was requested
707 allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator();
708 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) return;
709 } else if (NULL == allocator) {
710 allocator = __CFGetDefaultAllocator();
711 }
712
713 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI)
714 if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
715 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
716 }
717 #else
718 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
719 #endif
720 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
721 if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
722 #if defined(DEBUG)
723 size_t size = malloc_size(ptr);
724 if (size) memset(ptr, 0xCC, size);
725 #endif
726 return malloc_zone_free((malloc_zone_t *)allocator, ptr);
727 }
728 #endif
729 deallocateFunc = __CFAllocatorGetDeallocateFunction(&allocator->_context);
730 if (NULL != ptr && NULL != deallocateFunc) {
731 INVOKE_CALLBACK2(deallocateFunc, ptr, allocator->_context.info);
732 }
733 }
734
735 CFIndex CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) {
736 CFAllocatorPreferredSizeCallBack prefFunc;
737 CFIndex newsize = 0;
738
739 if (kCFAllocatorSystemDefaultGCRefZero == allocator) {
740 allocator = kCFAllocatorSystemDefault;
741 } else if (kCFAllocatorDefaultGCRefZero == allocator) {
742 // Under GC, we can't use just any old allocator when the GCRefZero allocator was requested
743 allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator();
744 } else if (NULL == allocator) {
745 allocator = __CFGetDefaultAllocator();
746 }
747
748 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI)
749 if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
750 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
751 }
752 #else
753 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
754 #endif
755 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
756 if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
757 return malloc_good_size(size);
758 }
759 #endif
760 prefFunc = __CFAllocatorGetPreferredSizeFunction(&allocator->_context);
761 if (0 < size && NULL != prefFunc) {
762 newsize = (CFIndex)(INVOKE_CALLBACK3(prefFunc, size, hint, allocator->_context.info));
763 }
764 if (newsize < size) newsize = size;
765 return newsize;
766 }
767
768 void CFAllocatorGetContext(CFAllocatorRef allocator, CFAllocatorContext *context) {
769 if (kCFAllocatorSystemDefaultGCRefZero == allocator) {
770 allocator = kCFAllocatorSystemDefault;
771 } else if (kCFAllocatorDefaultGCRefZero == allocator) {
772 // Under GC, we can't use just any old allocator when the GCRefZero allocator was requested
773 allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator();
774 } else if (NULL == allocator) {
775 allocator = __CFGetDefaultAllocator();
776 }
777
778 #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI)
779 if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
780 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
781 }
782 #else
783 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
784 #endif
785 CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
786 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
787 if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
788 return;
789 }
790 #endif
791 context->version = 0;
792 context->info = allocator->_context.info;
793 context->retain = __CFAllocatorGetRetainFunction(&allocator->_context);
794 context->release = __CFAllocatorGetReleaseFunction(&allocator->_context);
795 context->copyDescription = __CFAllocatorGetCopyDescriptionFunction(&allocator->_context);
796 context->allocate = __CFAllocatorGetAllocateFunction(&allocator->_context);
797 context->reallocate = __CFAllocatorGetReallocateFunction(&allocator->_context);
798 context->deallocate = __CFAllocatorGetDeallocateFunction(&allocator->_context);
799 context->preferredSize = __CFAllocatorGetPreferredSizeFunction(&allocator->_context);
800 }
801
802 __private_extern__ void *_CFAllocatorAllocateGC(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint)
803 {
804 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator))
805 return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, size, CF_GET_GC_MEMORY_TYPE(hint), false, false);
806 else
807 return CFAllocatorAllocate(allocator, size, hint);
808 }
809
810 __private_extern__ void *_CFAllocatorReallocateGC(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint)
811 {
812 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
813 if (ptr && (newsize == 0)) {
814 return NULL; // equivalent to _CFAllocatorDeallocateGC.
815 }
816 if (ptr == NULL) {
817 return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, newsize, CF_GET_GC_MEMORY_TYPE(hint), false, false); // eq. to _CFAllocator
818 }
819 }
820 // otherwise, auto_realloc() now preserves layout type and refCount.
821 return CFAllocatorReallocate(allocator, ptr, newsize, hint);
822 }
823
824 __private_extern__ void _CFAllocatorDeallocateGC(CFAllocatorRef allocator, void *ptr)
825 {
826 // when running GC, don't deallocate.
827 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) CFAllocatorDeallocate(allocator, ptr);
828 }
829
830 // -------- -------- -------- -------- -------- -------- -------- --------
831
832
833 CFRange __CFRangeMake(CFIndex loc, CFIndex len) {
834 CFRange range;
835 range.location = loc;
836 range.length = len;
837 return range;
838 }
839
840
841 struct __CFNull {
842 CFRuntimeBase _base;
843 };
844
845 static struct __CFNull __kCFNull = {
846 INIT_CFRUNTIME_BASE()
847 };
848 const CFNullRef kCFNull = &__kCFNull;
849
850 static CFStringRef __CFNullCopyDescription(CFTypeRef cf) {
851 return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFNull %p [%p]>"), cf, CFGetAllocator(cf));
852 }
853
854 static CFStringRef __CFNullCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
855 return (CFStringRef)CFRetain(CFSTR("null"));
856 }
857
858 static void __CFNullDeallocate(CFTypeRef cf) {
859 CFAssert(false, __kCFLogAssertion, "Deallocated CFNull!");
860 }
861
862 static CFTypeID __kCFNullTypeID = _kCFRuntimeNotATypeID;
863
864 static const CFRuntimeClass __CFNullClass = {
865 0,
866 "CFNull",
867 NULL, // init
868 NULL, // copy
869 __CFNullDeallocate,
870 NULL,
871 NULL,
872 __CFNullCopyFormattingDescription,
873 __CFNullCopyDescription
874 };
875
876 __private_extern__ void __CFNullInitialize(void) {
877 __kCFNullTypeID = _CFRuntimeRegisterClass(&__CFNullClass);
878 _CFRuntimeSetInstanceTypeID(&__kCFNull, __kCFNullTypeID);
879 __kCFNull._base._cfisa = __CFISAForTypeID(__kCFNullTypeID);
880 }
881
882 CFTypeID CFNullGetTypeID(void) {
883 return __kCFNullTypeID;
884 }
885
886 void CFCollection_non_gc_storage_error(void) { }
887
888
889 void _CFRuntimeSetCFMPresent(void *addr) {
890 }
891
892
893 // void __HALT(void);
894
895 /* Keep this assembly at the bottom of the source file! */
896
897
898 extern void __HALT() {
899 #if defined(__ppc__)
900 __asm__("trap");
901 #elif defined(__i386__) || defined(__x86_64__)
902 #if defined(_MSC_VER)
903 __asm int 3;
904 #else
905 __asm__("int3");
906 #endif
907 #endif
908 }
909
910