]> git.saurik.com Git - apple/cf.git/blob - CFBase.c
CF-550.19.tar.gz
[apple/cf.git] / CFBase.c
1 /*
2 * Copyright (c) 2010 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-2009, 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_LINUX || DEPLOYMENT_TARGET_FREEBSD
32 #include <pthread.h>
33 #endif
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>
38 #include <dlfcn.h>
39 #endif
40 #include <stdlib.h>
41 #include <string.h>
42
43 // -------- -------- -------- -------- -------- -------- -------- --------
44
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
48 #endif
49
50
51 struct __CFAllocator {
52
53
54 CFRuntimeBase _base;
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;
67 void *reserved5;
68 #endif
69 CFAllocatorRef _allocator;
70 CFAllocatorContext _context;
71 };
72
73 CF_INLINE CFAllocatorRetainCallBack __CFAllocatorGetRetainFunction(const CFAllocatorContext *context) {
74 CFAllocatorRetainCallBack retval = NULL;
75 retval = context->retain;
76 return retval;
77 }
78
79 CF_INLINE CFAllocatorReleaseCallBack __CFAllocatorGetReleaseFunction(const CFAllocatorContext *context) {
80 CFAllocatorReleaseCallBack retval = NULL;
81 retval = context->release;
82 return retval;
83 }
84
85 CF_INLINE CFAllocatorCopyDescriptionCallBack __CFAllocatorGetCopyDescriptionFunction(const CFAllocatorContext *context) {
86 CFAllocatorCopyDescriptionCallBack retval = NULL;
87 retval = context->copyDescription;
88 return retval;
89 }
90
91 CF_INLINE CFAllocatorAllocateCallBack __CFAllocatorGetAllocateFunction(const CFAllocatorContext *context) {
92 CFAllocatorAllocateCallBack retval = NULL;
93 retval = context->allocate;
94 return retval;
95 }
96
97 CF_INLINE CFAllocatorReallocateCallBack __CFAllocatorGetReallocateFunction(const CFAllocatorContext *context) {
98 CFAllocatorReallocateCallBack retval = NULL;
99 retval = context->reallocate;
100 return retval;
101 }
102
103 CF_INLINE CFAllocatorDeallocateCallBack __CFAllocatorGetDeallocateFunction(const CFAllocatorContext *context) {
104 CFAllocatorDeallocateCallBack retval = NULL;
105 retval = context->deallocate;
106 return retval;
107 }
108
109 CF_INLINE CFAllocatorPreferredSizeCallBack __CFAllocatorGetPreferredSizeFunction(const CFAllocatorContext *context) {
110 CFAllocatorPreferredSizeCallBack retval = NULL;
111 retval = context->preferredSize;
112 return retval;
113 }
114
115 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
116
117 __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf);
118
119 static kern_return_t __CFAllocatorZoneIntrospectNoOp(void) {
120 return 0;
121 }
122
123 static boolean_t __CFAllocatorZoneIntrospectTrue(void) {
124 return 1;
125 }
126
127 static size_t __CFAllocatorCustomSize(malloc_zone_t *zone, const void *ptr) {
128 return 0;
129
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 */
136 }
137
138 static void *__CFAllocatorCustomMalloc(malloc_zone_t *zone, size_t size) {
139 CFAllocatorRef allocator = (CFAllocatorRef)zone;
140 return CFAllocatorAllocate(allocator, size, 0);
141 }
142
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);
147 return newptr;
148 }
149
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);
154 return newptr;
155 }
156
157 static void __CFAllocatorCustomFree(malloc_zone_t *zone, void *ptr) {
158 CFAllocatorRef allocator = (CFAllocatorRef)zone;
159 CFAllocatorDeallocate(allocator, ptr);
160 }
161
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);
165 }
166
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);
176 }
177
178 static size_t __CFAllocatorCustomGoodSize(malloc_zone_t *zone, size_t size) {
179 CFAllocatorRef allocator = (CFAllocatorRef)zone;
180 return CFAllocatorGetPreferredSizeForSize(allocator, size, 0);
181 }
182
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
192 };
193
194 static size_t __CFAllocatorNullSize(malloc_zone_t *zone, const void *ptr) {
195 return 0;
196 }
197
198 static void * __CFAllocatorNullMalloc(malloc_zone_t *zone, size_t size) {
199 return NULL;
200 }
201
202 static void * __CFAllocatorNullCalloc(malloc_zone_t *zone, size_t num_items, size_t size) {
203 return NULL;
204 }
205
206 static void * __CFAllocatorNullValloc(malloc_zone_t *zone, size_t size) {
207 return NULL;
208 }
209
210 static void __CFAllocatorNullFree(malloc_zone_t *zone, void *ptr) {
211 }
212
213 static void * __CFAllocatorNullRealloc(malloc_zone_t *zone, void *ptr, size_t size) {
214 return NULL;
215 }
216
217 static void __CFAllocatorNullDestroy(malloc_zone_t *zone) {
218 }
219
220 static size_t __CFAllocatorNullGoodSize(malloc_zone_t *zone, size_t size) {
221 return size;
222 }
223
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
233 };
234
235 static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) {
236 return malloc_zone_malloc(info, size);
237 }
238
239 static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
240 return malloc_zone_realloc(info, ptr, newsize);
241 }
242
243 static void __CFAllocatorSystemDeallocate(void *ptr, void *info) {
244 #if defined(DEBUG)
245 size_t size = malloc_size(ptr);
246 if (size) memset(ptr, 0xCC, size);
247 #endif
248 malloc_zone_free(info, ptr);
249 }
250
251 #endif
252
253 #if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
254 static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) {
255 return malloc(size);
256 }
257
258 static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
259 return realloc(ptr, newsize);
260 }
261
262 static void __CFAllocatorSystemDeallocate(void *ptr, void *info) {
263 free(ptr);
264 }
265 #endif
266
267 static void *__CFAllocatorNullAllocate(CFIndex size, CFOptionFlags hint, void *info) {
268 return NULL;
269 }
270
271 static void *__CFAllocatorNullReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
272 return NULL;
273 }
274
275 #if defined (__cplusplus)
276 static void * __CFAllocatorCPPMalloc(CFIndex allocSize, CFOptionFlags hint, void *info)
277 {
278 return malloc(allocSize);
279 }
280 static void * __CFAllocatorCPPReAlloc(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info)
281 {
282 return realloc(ptr, newsize);
283 }
284 static void __CFAllocatorCPPFree(void *ptr, void *info)
285 {
286 free(ptr);
287 }
288 #endif // C++
289
290
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",
302 NULL,
303 NULL,
304 &__CFAllocatorZoneIntrospect,
305 NULL,
306 #endif
307 NULL, // _allocator
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}
313 #else
314 {0, NULL, NULL, NULL, NULL, __CFAllocatorCPPMalloc,__CFAllocatorCPPReAlloc, __CFAllocatorCPPFree, NULL}
315 #endif // __cplusplus
316 };
317
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",
329 NULL,
330 NULL,
331 &__CFAllocatorZoneIntrospect,
332 NULL,
333 #endif
334 NULL, // _allocator
335 {0, NULL, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL}
336 };
337
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",
349 NULL,
350 NULL,
351 &__CFAllocatorZoneIntrospect,
352 NULL,
353 #endif
354 NULL, // _allocator
355 {0, NULL, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL}
356 };
357
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,
368 "kCFAllocatorNull",
369 NULL,
370 NULL,
371 &__CFAllocatorNullZoneIntrospect,
372 NULL,
373 #endif
374 NULL, // _allocator
375 {0, NULL, NULL, NULL, NULL, __CFAllocatorNullAllocate, __CFAllocatorNullReallocate, NULL, NULL}
376 };
377
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;
384
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
391 }
392
393 __private_extern__ CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef cf) {
394 CFAllocatorRef allocator = (CFAllocatorRef)cf;
395 return (kCFAllocatorUseContext == allocator->_allocator) ? allocator : allocator->_allocator;
396 }
397
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);
409 }
410 if (NULL != releaseFunc) {
411 INVOKE_CALLBACK1(releaseFunc, info);
412 }
413 } else {
414 if (NULL != releaseFunc) {
415 INVOKE_CALLBACK1(releaseFunc, self->_context.info);
416 }
417 _CFAllocatorDeallocateGC(allocator, (void *)self);
418 }
419 }
420
421 static CFTypeID __kCFAllocatorTypeID = _kCFRuntimeNotATypeID;
422
423 static const CFRuntimeClass __CFAllocatorClass = {
424 0,
425 "CFAllocator",
426 NULL, // init
427 NULL, // copy
428 NULL,
429 NULL, // equal
430 NULL, // hash
431 NULL, //
432 __CFAllocatorCopyDescription
433 };
434
435 __private_extern__ void __CFAllocatorInitialize(void) {
436 __kCFAllocatorTypeID = _CFRuntimeRegisterClass(&__CFAllocatorClass);
437
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 *));
443 #endif
444 __kCFAllocatorSystemDefault._allocator = kCFAllocatorSystemDefault;
445
446 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMalloc, __kCFAllocatorTypeID);
447 __kCFAllocatorMalloc._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID);
448 __kCFAllocatorMalloc._allocator = kCFAllocatorSystemDefault;
449
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();
455 #endif
456
457 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorNull, __kCFAllocatorTypeID);
458 __kCFAllocatorNull._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID);
459 __kCFAllocatorNull._allocator = kCFAllocatorSystemDefault;
460
461 }
462
463 CFTypeID CFAllocatorGetTypeID(void) {
464 return __kCFAllocatorTypeID;
465 }
466
467 CFAllocatorRef CFAllocatorGetDefault(void) {
468 return __CFGetDefaultAllocator();
469 }
470
471 void CFAllocatorSetDefault(CFAllocatorRef allocator) {
472 CFAllocatorRef current = __CFGetDefaultAllocator();
473 #if defined(DEBUG)
474 if (NULL != allocator) {
475 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
476 }
477 #endif
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
481 }
482 #endif
483 if (NULL != allocator && allocator != current) {
484 if (current) CFRelease(current);
485 CFRetain(allocator);
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);
489 #else
490 // We retain an extra time so that anything set as the default
491 // allocator never goes away.
492 CFRetain(allocator);
493 __CFGetThreadSpecificData_inline()->_allocator = (void *)allocator;
494 #endif
495 }
496 }
497
498 static CFAllocatorRef __CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) {
499 struct __CFAllocator *memory = NULL;
500 CFAllocatorRetainCallBack retainFunc;
501 CFAllocatorAllocateCallBack allocateFunc;
502 void *retainedInfo;
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
506 }
507 #endif
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);
514 } else {
515 retainedInfo = context->info;
516 }
517 // We don't use _CFRuntimeCreateInstance()
518 if (kCFAllocatorUseContext == allocator) {
519 memory = NULL;
520 if (allocateFunc) {
521 memory = (struct __CFAllocator *)INVOKE_CALLBACK3(allocateFunc, sizeof(struct __CFAllocator), 0, retainedInfo);
522 }
523 if (NULL == memory) {
524 return NULL;
525 }
526 } else {
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) {
531 return NULL;
532 }
533 }
534 memory->_base._cfisa = 0;
535 #if __LP64__
536 memory->_base._rc = 1;
537 #else
538 memory->_base._cfinfo[CF_RC_BITS] = 1;
539 #endif
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;
556 #endif
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));
572
573 return memory;
574 }
575
576 CFAllocatorRef CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) {
577 return __CFAllocatorCreate(allocator, context);
578 }
579
580 void *CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) {
581 CFAllocatorAllocateCallBack allocateFunc;
582 void *newptr = NULL;
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);
587 }
588 #else
589 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
590 #endif
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);
595 }
596 #endif
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);
599 } else {
600 newptr = NULL;
601 allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context);
602 if (allocateFunc) {
603 newptr = (void *)INVOKE_CALLBACK3(allocateFunc, size, hint, allocator->_context.info);
604 }
605 }
606 return newptr;
607 }
608
609 void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint) {
610 CFAllocatorAllocateCallBack allocateFunc;
611 CFAllocatorReallocateCallBack reallocateFunc;
612 CFAllocatorDeallocateCallBack deallocateFunc;
613 void *newptr;
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);
618 }
619 #else
620 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
621 #endif
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);
626 }
627 #endif
628 newptr = NULL;
629 allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context);
630 if (allocateFunc) {
631 newptr = (void *)INVOKE_CALLBACK3(allocateFunc, newsize, hint, allocator->_context.info);
632 }
633 return newptr;
634 }
635 if (NULL != ptr && 0 == newsize) {
636 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
637 if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
638 #if defined(DEBUG)
639 size_t size = malloc_size(ptr);
640 if (size) memset(ptr, 0xCC, size);
641 #endif
642 malloc_zone_free((malloc_zone_t *)allocator, ptr);
643 return NULL;
644 }
645 #endif
646 deallocateFunc = __CFAllocatorGetDeallocateFunction(&allocator->_context);
647 if (NULL != deallocateFunc) {
648 INVOKE_CALLBACK2(deallocateFunc, ptr, allocator->_context.info);
649 }
650 return NULL;
651 }
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);
656 }
657 #endif
658 reallocateFunc = __CFAllocatorGetReallocateFunction(&allocator->_context);
659 if (NULL == reallocateFunc) return NULL;
660 newptr = (void *)INVOKE_CALLBACK4(reallocateFunc, ptr, newsize, hint, allocator->_context.info);
661 return newptr;
662 }
663
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);
670 }
671 #else
672 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
673 #endif
674 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
675 if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
676 #if defined(DEBUG)
677 size_t size = malloc_size(ptr);
678 if (size) memset(ptr, 0xCC, size);
679 #endif
680 return malloc_zone_free((malloc_zone_t *)allocator, ptr);
681 }
682 #endif
683 deallocateFunc = __CFAllocatorGetDeallocateFunction(&allocator->_context);
684 if (NULL != ptr && NULL != deallocateFunc) {
685 INVOKE_CALLBACK2(deallocateFunc, ptr, allocator->_context.info);
686 }
687 }
688
689 CFIndex CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) {
690 CFAllocatorPreferredSizeCallBack prefFunc;
691 CFIndex newsize = 0;
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);
696 }
697 #else
698 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
699 #endif
700 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
701 if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
702 return malloc_good_size(size);
703 }
704 #endif
705 prefFunc = __CFAllocatorGetPreferredSizeFunction(&allocator->_context);
706 if (0 < size && NULL != prefFunc) {
707 newsize = (CFIndex)(INVOKE_CALLBACK3(prefFunc, size, hint, allocator->_context.info));
708 }
709 if (newsize < size) newsize = size;
710 return newsize;
711 }
712
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);
718 }
719 #else
720 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
721 #endif
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 *
725 return;
726 }
727 #endif
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);
745 #endif
746 }
747
748 __private_extern__ void *_CFAllocatorAllocateGC(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint)
749 {
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);
752 else
753 return CFAllocatorAllocate(allocator, size, hint);
754 }
755
756 __private_extern__ void *_CFAllocatorReallocateGC(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint)
757 {
758 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
759 if (ptr && (newsize == 0)) {
760 return NULL; // equivalent to _CFAllocatorDeallocateGC.
761 }
762 if (ptr == NULL) {
763 return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, newsize, CF_GET_GC_MEMORY_TYPE(hint), false, false); // eq. to _CFAllocator
764 }
765 }
766 // otherwise, auto_realloc() now preserves layout type and refCount.
767 return CFAllocatorReallocate(allocator, ptr, newsize, hint);
768 }
769
770 __private_extern__ void _CFAllocatorDeallocateGC(CFAllocatorRef allocator, void *ptr)
771 {
772 // when running GC, don't deallocate.
773 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) CFAllocatorDeallocate(allocator, ptr);
774 }
775
776 // -------- -------- -------- -------- -------- -------- -------- --------
777
778 #if DEPLOYMENT_TARGET_WINDOWS
779 __private_extern__ DWORD __CFTSDKey = 0xFFFFFFFF;
780 #endif
781
782 #if DEPLOYMENT_TARGET_WINDOWS
783 extern void __CFStringEncodingICUThreadDataCleaner(void *);
784
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);
794 }
795
796 __private_extern__ __CFThreadSpecificData *__CFGetThreadSpecificData(void) {
797 __CFThreadSpecificData *data;
798 data = (__CFThreadSpecificData *)TlsGetValue(__CFTSDKey);
799 if (data) {
800 return data;
801 }
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);
806 return data;
807 }
808 #endif
809
810 __private_extern__ void __CFBaseInitialize(void) {
811 #if DEPLOYMENT_TARGET_WINDOWS
812 __CFTSDKey = TlsAlloc();
813 #endif
814 }
815
816 #if DEPLOYMENT_TARGET_WINDOWS
817 __private_extern__ void __CFBaseCleanup(void) {
818 TlsFree(__CFTSDKey);
819 }
820 #endif
821
822
823 CFRange __CFRangeMake(CFIndex loc, CFIndex len) {
824 CFRange range;
825 range.location = loc;
826 range.length = len;
827 return range;
828 }
829
830
831 struct __CFNull {
832 CFRuntimeBase _base;
833 };
834
835 static struct __CFNull __kCFNull = {
836 INIT_CFRUNTIME_BASE()
837 };
838 const CFNullRef kCFNull = &__kCFNull;
839
840 static CFStringRef __CFNullCopyDescription(CFTypeRef cf) {
841 return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFNull %p [%p]>"), cf, CFGetAllocator(cf));
842 }
843
844 static CFStringRef __CFNullCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
845 return (CFStringRef)CFRetain(CFSTR("null"));
846 }
847
848 static void __CFNullDeallocate(CFTypeRef cf) {
849 CFAssert(false, __kCFLogAssertion, "Deallocated CFNull!");
850 }
851
852 static CFTypeID __kCFNullTypeID = _kCFRuntimeNotATypeID;
853
854 static const CFRuntimeClass __CFNullClass = {
855 0,
856 "CFNull",
857 NULL, // init
858 NULL, // copy
859 __CFNullDeallocate,
860 NULL,
861 NULL,
862 __CFNullCopyFormattingDescription,
863 __CFNullCopyDescription
864 };
865
866 __private_extern__ void __CFNullInitialize(void) {
867 __kCFNullTypeID = _CFRuntimeRegisterClass(&__CFNullClass);
868 _CFRuntimeSetInstanceTypeID(&__kCFNull, __kCFNullTypeID);
869 __kCFNull._base._cfisa = __CFISAForTypeID(__kCFNullTypeID);
870 }
871
872 CFTypeID CFNullGetTypeID(void) {
873 return __kCFNullTypeID;
874 }
875
876 void CFCollection_non_gc_storage_error(void) { }
877
878
879 static int hasCFM = 0;
880
881 void _CFRuntimeSetCFMPresent(void *addr) {
882 hasCFM = 1;
883 }
884
885 #if DEPLOYMENT_TARGET_MACOSX && defined(__ppc__)
886
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);
893 } else {
894 static CFMutableDictionaryRef cache = NULL;
895 static CFSpinLock_t lock = CFSpinLockInit;
896 uintptr_t known = ~0;
897 __CFSpinLock(&lock);
898 if (!cache || !CFDictionaryGetValueIfPresent(cache, (const void *)p, (const void **)&known)) {
899 if (!cache) {
900 cache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
901 }
902 Dl_info info;
903 known = dladdr((void *)p, &info);
904 CFDictionarySetValue(cache, (const void *)p, (const void *)known);
905 }
906 __CFSpinUnlock(&lock);
907 *ptr = (void *)(p | (known ? 0x1 : 0x3));
908 }
909 }
910
911 /*
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.
915
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)
921
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.
925 */
926
927 /* Keep this assembly at the bottom of the source file! */
928
929 __asm__ (
930 ".text\n"
931 " .align 2\n"
932 ".private_extern ___CF_INVOKE_CALLBACK\n"
933 "___CF_INVOKE_CALLBACK:\n"
934 "rlwinm r12,r3,0,0,29\n"
935 "andi. r0,r3,0x2\n"
936 "or r3,r4,r4\n"
937 "or r4,r5,r5\n"
938 "or r5,r6,r6\n"
939 "or r6,r7,r7\n"
940 "or r7,r8,r8\n"
941 "beq- Lcall\n"
942 "lwz r2,0x4(r12)\n"
943 "lwz r12,0x0(r12)\n"
944 "Lcall: mtspr ctr,r12\n"
945 "bctr\n");
946
947 #endif
948
949
950 // void __HALT(void);
951
952 #if defined(__ppc__)
953 __asm__ (
954 ".text\n"
955 " .align 2\n"
956 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
957 ".private_extern ___HALT\n"
958 #else
959 ".globl ___HALT\n"
960 #endif
961 "___HALT:\n"
962 " trap\n"
963 );
964 #endif
965
966 #if defined(__i386__) || defined(__x86_64__)
967 #if defined(_MSC_VER)
968 void __HALT() {
969 __asm int 3;
970 }
971 #else
972 __asm__ (
973 ".text\n"
974 " .align 2, 0x90\n"
975 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
976 ".private_extern ___HALT\n"
977 #else
978 ".globl ___HALT\n"
979 #endif
980 "___HALT:\n"
981 " int3\n"
982 );
983 #endif
984 #endif
985
986