]> git.saurik.com Git - apple/cf.git/blob - Base.subproj/CFBase.c
CF-299.35.tar.gz
[apple/cf.git] / Base.subproj / CFBase.c
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /* CFBase.c
26 Copyright 1998-2002, Apple, Inc. All rights reserved.
27 Responsibility: Christopher Kane
28 */
29
30 #include <CoreFoundation/CFBase.h>
31 #include "CFInternal.h"
32 #if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
33 #include <pthread.h>
34 #endif
35 #if defined(__MACH__)
36 #endif
37 #if defined(__WIN32__)
38 #include <windows.h>
39 #endif
40 #if defined(__MACH__)
41 #include <mach-o/dyld.h>
42 #include <malloc/malloc.h>
43 #include <mach/mach.h>
44 #endif
45 #include <stdlib.h>
46 #include <string.h>
47
48 extern size_t malloc_good_size(size_t size);
49
50 // -------- -------- -------- -------- -------- -------- -------- --------
51
52 #if defined(__MACH__)
53 // CFAllocator structure must match struct _malloc_zone_t!
54 // The first two reserved fields in struct _malloc_zone_t are for us with CFRuntimeBase
55 #endif
56 struct __CFAllocator {
57 CFRuntimeBase _base;
58 #if defined(__MACH__)
59 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 */
60 void *(*malloc)(struct _malloc_zone_t *zone, size_t size);
61 void *(*calloc)(struct _malloc_zone_t *zone, size_t num_items, size_t size); /* same as malloc, but block returned is set to zero */
62 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 */
63 void (*free)(struct _malloc_zone_t *zone, void *ptr);
64 void *(*realloc)(struct _malloc_zone_t *zone, void *ptr, size_t size);
65 void (*destroy)(struct _malloc_zone_t *zone); /* zone is destroyed and all memory reclaimed */
66 const char *zone_name;
67 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) */
68 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 */
69 struct malloc_introspection_t *introspect;
70 void *reserved5;
71 #endif
72 CFAllocatorRef _allocator;
73 CFAllocatorContext _context;
74 };
75
76 CF_INLINE CFAllocatorRetainCallBack __CFAllocatorGetRetainFunction(const CFAllocatorContext *context) {
77 CFAllocatorRetainCallBack retval = NULL;
78 retval = context->retain;
79 return retval;
80 }
81
82 CF_INLINE CFAllocatorReleaseCallBack __CFAllocatorGetReleaseFunction(const CFAllocatorContext *context) {
83 CFAllocatorReleaseCallBack retval = NULL;
84 retval = context->release;
85 return retval;
86 }
87
88 CF_INLINE CFAllocatorCopyDescriptionCallBack __CFAllocatorGetCopyDescriptionFunction(const CFAllocatorContext *context) {
89 CFAllocatorCopyDescriptionCallBack retval = NULL;
90 retval = context->copyDescription;
91 return retval;
92 }
93
94 CF_INLINE CFAllocatorAllocateCallBack __CFAllocatorGetAllocateFunction(const CFAllocatorContext *context) {
95 CFAllocatorAllocateCallBack retval = NULL;
96 retval = context->allocate;
97 return retval;
98 }
99
100 CF_INLINE CFAllocatorReallocateCallBack __CFAllocatorGetReallocateFunction(const CFAllocatorContext *context) {
101 CFAllocatorReallocateCallBack retval = NULL;
102 retval = context->reallocate;
103 return retval;
104 }
105
106 CF_INLINE CFAllocatorDeallocateCallBack __CFAllocatorGetDeallocateFunction(const CFAllocatorContext *context) {
107 CFAllocatorDeallocateCallBack retval = NULL;
108 retval = context->deallocate;
109 return retval;
110 }
111
112 CF_INLINE CFAllocatorPreferredSizeCallBack __CFAllocatorGetPreferredSizeFunction(const CFAllocatorContext *context) {
113 CFAllocatorPreferredSizeCallBack retval = NULL;
114 retval = context->preferredSize;
115 return retval;
116 }
117
118 #if defined(__MACH__)
119
120 __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf);
121
122 static kern_return_t __CFAllocatorZoneIntrospectNoOp(void) {
123 return 0;
124 }
125
126 static boolean_t __CFAllocatorZoneIntrospectTrue(void) {
127 return 1;
128 }
129
130 static size_t __CFAllocatorCustomSize(malloc_zone_t *zone, const void *ptr) {
131 return 0;
132
133 // The only way to implement this with a version 0 allocator would be
134 // for CFAllocator to keep track of all blocks allocated itself, which
135 // could be done, but would be bad for performance, so we don't do it.
136 // size_t (*size)(struct _malloc_zone_t *zone, const void *ptr);
137 /* returns the size of a block or 0 if not in this zone;
138 * must be fast, especially for negative answers */
139 }
140
141 static void *__CFAllocatorCustomMalloc(malloc_zone_t *zone, size_t size) {
142 CFAllocatorRef allocator = (CFAllocatorRef)zone;
143 return CFAllocatorAllocate(allocator, size, 0);
144 }
145
146 static void *__CFAllocatorCustomCalloc(malloc_zone_t *zone, size_t num_items, size_t size) {
147 CFAllocatorRef allocator = (CFAllocatorRef)zone;
148 void *newptr = CFAllocatorAllocate(allocator, size, 0);
149 if (newptr) memset(newptr, 0, size);
150 return newptr;
151 }
152
153 static void *__CFAllocatorCustomValloc(malloc_zone_t *zone, size_t size) {
154 CFAllocatorRef allocator = (CFAllocatorRef)zone;
155 void *newptr = CFAllocatorAllocate(allocator, size + vm_page_size, 0);
156 newptr = (void *)round_page((unsigned)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 malloc_zone_free(info, ptr);
248 }
249
250 #endif
251
252 #if defined(__WIN32__) || defined(__LINUX__) || defined(__FREEBSD__)
253 static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) {
254 return malloc(size);
255 }
256
257 static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
258 return realloc(ptr, newsize);
259 }
260
261 static void __CFAllocatorSystemDeallocate(void *ptr, void *info) {
262 free(ptr);
263 }
264 #endif
265
266 static void *__CFAllocatorNullAllocate(CFIndex size, CFOptionFlags hint, void *info) {
267 return NULL;
268 }
269
270 static void *__CFAllocatorNullReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
271 return NULL;
272 }
273
274 static struct __CFAllocator __kCFAllocatorMalloc = {
275 {NULL, 0, 0x0080},
276 #if defined(__MACH__)
277 __CFAllocatorCustomSize,
278 __CFAllocatorCustomMalloc,
279 __CFAllocatorCustomCalloc,
280 __CFAllocatorCustomValloc,
281 __CFAllocatorCustomFree,
282 __CFAllocatorCustomRealloc,
283 __CFAllocatorNullDestroy,
284 "kCFAllocatorMalloc",
285 NULL,
286 NULL,
287 &__CFAllocatorZoneIntrospect,
288 NULL,
289 #endif
290 NULL, // _allocator
291 // Using the malloc functions directly is a total cheat, but works (in C)
292 // because the function signatures match in their common prefix of arguments.
293 // This saves us one hop through an adaptor function.
294 {0, NULL, NULL, NULL, NULL, (void *)malloc, (void *)realloc, (void *)free, NULL}
295 };
296
297 static struct __CFAllocator __kCFAllocatorSystemDefault = {
298 {NULL, 0, 0x0080},
299 #if defined(__MACH__)
300 __CFAllocatorCustomSize,
301 __CFAllocatorCustomMalloc,
302 __CFAllocatorCustomCalloc,
303 __CFAllocatorCustomValloc,
304 __CFAllocatorCustomFree,
305 __CFAllocatorCustomRealloc,
306 __CFAllocatorNullDestroy,
307 "kCFAllocatorSystemDefault",
308 NULL,
309 NULL,
310 &__CFAllocatorZoneIntrospect,
311 NULL,
312 #endif
313 NULL, // _allocator
314 {0, NULL, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL}
315 };
316
317 static struct __CFAllocator __kCFAllocatorNull = {
318 {NULL, 0, 0x0080},
319 #if defined(__MACH__)
320 __CFAllocatorNullSize,
321 __CFAllocatorNullMalloc,
322 __CFAllocatorNullCalloc,
323 __CFAllocatorNullValloc,
324 __CFAllocatorNullFree,
325 __CFAllocatorNullRealloc,
326 __CFAllocatorNullDestroy,
327 "kCFAllocatorNull",
328 NULL,
329 NULL,
330 &__CFAllocatorNullZoneIntrospect,
331 NULL,
332 #endif
333 NULL, // _allocator
334 {0, NULL, NULL, NULL, NULL, __CFAllocatorNullAllocate, __CFAllocatorNullReallocate, NULL, NULL}
335 };
336
337 const CFAllocatorRef kCFAllocatorDefault = NULL;
338 const CFAllocatorRef kCFAllocatorSystemDefault = &__kCFAllocatorSystemDefault;
339 const CFAllocatorRef kCFAllocatorMalloc = &__kCFAllocatorMalloc;
340 const CFAllocatorRef kCFAllocatorNull = &__kCFAllocatorNull;
341 const CFAllocatorRef kCFAllocatorUseContext = (CFAllocatorRef)0x0227;
342
343 static CFStringRef __CFAllocatorCopyDescription(CFTypeRef cf) {
344 CFAllocatorRef self = cf;
345 CFAllocatorRef allocator = (kCFAllocatorUseContext == self->_allocator) ? self : self->_allocator;
346 return CFStringCreateWithFormat(allocator, NULL, CFSTR("<CFAllocator 0x%x [0x%x]>{info = 0x%x}"), (UInt32)cf, (UInt32)allocator, self->_context.info);
347 // CF: should use copyDescription function here to describe info field
348 // remember to release value returned from copydescr function when this happens
349 }
350
351 __private_extern__ CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef cf) {
352 CFAllocatorRef allocator = cf;
353 return (kCFAllocatorUseContext == allocator->_allocator) ? allocator : allocator->_allocator;
354 }
355
356 __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf) {
357 CFAllocatorRef self = cf;
358 CFAllocatorRef allocator = self->_allocator;
359 CFAllocatorReleaseCallBack releaseFunc = __CFAllocatorGetReleaseFunction(&self->_context);
360 if (kCFAllocatorUseContext == allocator) {
361 /* Rather a chicken and egg problem here, so we do things
362 in the reverse order from what was done at create time. */
363 CFAllocatorDeallocateCallBack deallocateFunc = __CFAllocatorGetDeallocateFunction(&self->_context);
364 void *info = self->_context.info;
365 if (NULL != deallocateFunc) {
366 INVOKE_CALLBACK2(deallocateFunc, (void *)self, info);
367 }
368 if (NULL != releaseFunc) {
369 INVOKE_CALLBACK1(releaseFunc, info);
370 }
371 } else {
372 if (NULL != releaseFunc) {
373 INVOKE_CALLBACK1(releaseFunc, self->_context.info);
374 }
375 CFAllocatorDeallocate(allocator, (void *)self);
376 }
377 }
378
379 static CFTypeID __kCFAllocatorTypeID = _kCFRuntimeNotATypeID;
380
381 static const CFRuntimeClass __CFAllocatorClass = {
382 0,
383 "CFAllocator",
384 NULL, // init
385 NULL, // copy
386 __CFAllocatorDeallocate,
387 NULL, // equal
388 NULL, // hash
389 NULL, //
390 __CFAllocatorCopyDescription
391 };
392
393 __private_extern__ void __CFAllocatorInitialize(void) {
394 __kCFAllocatorTypeID = _CFRuntimeRegisterClass(&__CFAllocatorClass);
395
396 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorSystemDefault, __kCFAllocatorTypeID);
397 __kCFAllocatorSystemDefault._base._isa = __CFISAForTypeID(__kCFAllocatorTypeID);
398 #if defined(__MACH__)
399 __kCFAllocatorSystemDefault._context.info = malloc_default_zone();
400 #endif
401 __kCFAllocatorSystemDefault._allocator = kCFAllocatorSystemDefault;
402 memset(malloc_default_zone(), 0, 8);
403
404 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMalloc, __kCFAllocatorTypeID);
405 __kCFAllocatorMalloc._base._isa = __CFISAForTypeID(__kCFAllocatorTypeID);
406 __kCFAllocatorMalloc._allocator = kCFAllocatorSystemDefault;
407
408 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorNull, __kCFAllocatorTypeID);
409 __kCFAllocatorNull._base._isa = __CFISAForTypeID(__kCFAllocatorTypeID);
410 __kCFAllocatorNull._allocator = kCFAllocatorSystemDefault;
411
412 }
413
414 CFTypeID CFAllocatorGetTypeID(void) {
415 return __kCFAllocatorTypeID;
416 }
417
418 CFAllocatorRef CFAllocatorGetDefault(void) {
419 CFAllocatorRef allocator = __CFGetThreadSpecificData_inline()->_allocator;
420 if (NULL == allocator) {
421 allocator = kCFAllocatorSystemDefault;
422 }
423 return allocator;
424 }
425
426 void CFAllocatorSetDefault(CFAllocatorRef allocator) {
427 CFAllocatorRef current = __CFGetThreadSpecificData_inline()->_allocator;
428 #if defined(DEBUG)
429 if (NULL != allocator) {
430 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
431 }
432 #endif
433 #if defined(__MACH__)
434 if (allocator && allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
435 return; // require allocator to this function to be an allocator
436 }
437 #endif
438 if (NULL != allocator && allocator != current) {
439 if (current) CFRelease(current);
440 CFRetain(allocator);
441 // We retain an extra time so that anything set as the default
442 // allocator never goes away.
443 CFRetain(allocator);
444 __CFGetThreadSpecificData_inline()->_allocator = (void *)allocator;
445 }
446 }
447
448 CFAllocatorRef CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) {
449 struct __CFAllocator *memory;
450 CFAllocatorRetainCallBack retainFunc;
451 CFAllocatorAllocateCallBack allocateFunc;
452 void *retainedInfo;
453 #if defined(DEBUG)
454 if (NULL == context->allocate) {
455 HALT;
456 }
457 #endif
458 #if defined(__MACH__)
459 if (allocator && kCFAllocatorUseContext != allocator && allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
460 return NULL; // require allocator to this function to be an allocator
461 }
462 #endif
463 retainFunc = context->retain;
464 FAULT_CALLBACK((void **)&retainFunc);
465 allocateFunc = context->allocate;
466 FAULT_CALLBACK((void **)&allocateFunc);
467 if (NULL != retainFunc) {
468 retainedInfo = (void *)INVOKE_CALLBACK1(retainFunc, context->info);
469 } else {
470 retainedInfo = context->info;
471 }
472 // We don't use _CFRuntimeCreateInstance()
473 if (kCFAllocatorUseContext == allocator) {
474 memory = (void *)INVOKE_CALLBACK3(allocateFunc, sizeof(struct __CFAllocator), 0, retainedInfo);
475 if (NULL == memory) {
476 return NULL;
477 }
478 } else {
479 allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
480 memory = CFAllocatorAllocate(allocator, sizeof(struct __CFAllocator), 0);
481 if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFAllocator");
482 if (NULL == memory) {
483 return NULL;
484 }
485 }
486 memory->_base._isa = 0;
487 memory->_base._rc = 1;
488 memory->_base._info = 0;
489 _CFRuntimeSetInstanceTypeID(memory, __kCFAllocatorTypeID);
490 memory->_base._isa = __CFISAForTypeID(__kCFAllocatorTypeID);
491 #if defined(__MACH__)
492 memory->size = __CFAllocatorCustomSize;
493 memory->malloc = __CFAllocatorCustomMalloc;
494 memory->calloc = __CFAllocatorCustomCalloc;
495 memory->valloc = __CFAllocatorCustomValloc;
496 memory->free = __CFAllocatorCustomFree;
497 memory->realloc = __CFAllocatorCustomRealloc;
498 memory->destroy = __CFAllocatorCustomDestroy;
499 memory->zone_name = "Custom CFAllocator";
500 memory->batch_malloc = NULL;
501 memory->batch_free = NULL;
502 memory->introspect = &__CFAllocatorZoneIntrospect;
503 memory->reserved5 = NULL;
504 #endif
505 memory->_allocator = allocator;
506 memory->_context.version = context->version;
507 memory->_context.info = retainedInfo;
508 memory->_context.retain = retainFunc;
509 memory->_context.release = context->release;
510 FAULT_CALLBACK((void **)&(memory->_context.release));
511 memory->_context.copyDescription = context->copyDescription;
512 FAULT_CALLBACK((void **)&(memory->_context.copyDescription));
513 memory->_context.allocate = allocateFunc;
514 memory->_context.reallocate = context->reallocate;
515 FAULT_CALLBACK((void **)&(memory->_context.reallocate));
516 memory->_context.deallocate = context->deallocate;
517 FAULT_CALLBACK((void **)&(memory->_context.deallocate));
518 memory->_context.preferredSize = context->preferredSize;
519 FAULT_CALLBACK((void **)&(memory->_context.preferredSize));
520
521 return memory;
522 }
523
524 void *CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) {
525 CFAllocatorAllocateCallBack allocateFunc;
526 void *newptr;
527 allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
528 #if defined(__MACH__) && defined(DEBUG)
529 if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
530 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
531 }
532 #else
533 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
534 #endif
535 if (0 == size) return NULL;
536 #if defined(__MACH__)
537 if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
538 return malloc_zone_malloc((malloc_zone_t *)allocator, size);
539 }
540 #endif
541 allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context);
542 newptr = (void *)INVOKE_CALLBACK3(allocateFunc, size, hint, allocator->_context.info);
543 return newptr;
544 }
545
546 void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint) {
547 CFAllocatorAllocateCallBack allocateFunc;
548 CFAllocatorReallocateCallBack reallocateFunc;
549 CFAllocatorDeallocateCallBack deallocateFunc;
550 void *newptr;
551 allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
552 #if defined(__MACH__) && defined(DEBUG)
553 if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
554 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
555 }
556 #else
557 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
558 #endif
559 if (NULL == ptr && 0 < newsize) {
560 #if defined(__MACH__)
561 if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
562 return malloc_zone_malloc((malloc_zone_t *)allocator, newsize);
563 }
564 #endif
565 allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context);
566 newptr = (void *)INVOKE_CALLBACK3(allocateFunc, newsize, hint, allocator->_context.info);
567 return newptr;
568 }
569 if (NULL != ptr && 0 == newsize) {
570 #if defined(__MACH__)
571 if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
572 malloc_zone_free((malloc_zone_t *)allocator, ptr);
573 return NULL;
574 }
575 #endif
576 deallocateFunc = __CFAllocatorGetDeallocateFunction(&allocator->_context);
577 if (NULL != deallocateFunc) {
578 INVOKE_CALLBACK2(deallocateFunc, ptr, allocator->_context.info);
579 }
580 return NULL;
581 }
582 if (NULL == ptr && 0 == newsize) return NULL;
583 #if defined(__MACH__)
584 if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
585 return malloc_zone_realloc((malloc_zone_t *)allocator, ptr, newsize);
586 }
587 #endif
588 reallocateFunc = __CFAllocatorGetReallocateFunction(&allocator->_context);
589 if (NULL == reallocateFunc) return NULL;
590 newptr = (void *)INVOKE_CALLBACK4(reallocateFunc, ptr, newsize, hint, allocator->_context.info);
591 return newptr;
592 }
593
594 void CFAllocatorDeallocate(CFAllocatorRef allocator, void *ptr) {
595 CFAllocatorDeallocateCallBack deallocateFunc;
596 allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
597 #if defined(__MACH__) && defined(DEBUG)
598 if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
599 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
600 }
601 #else
602 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
603 #endif
604 #if defined(__MACH__)
605 if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
606 return malloc_zone_free((malloc_zone_t *)allocator, ptr);
607 }
608 #endif
609 deallocateFunc = __CFAllocatorGetDeallocateFunction(&allocator->_context);
610 if (NULL != ptr && NULL != deallocateFunc) {
611 INVOKE_CALLBACK2(deallocateFunc, ptr, allocator->_context.info);
612 }
613 }
614
615 CFIndex CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) {
616 CFAllocatorPreferredSizeCallBack prefFunc;
617 CFIndex newsize = 0;
618 allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
619 #if defined(__MACH__) && defined(DEBUG)
620 if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
621 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
622 }
623 #else
624 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
625 #endif
626 #if defined(__MACH__)
627 if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
628 return malloc_good_size(size);
629 }
630 #endif
631 prefFunc = __CFAllocatorGetPreferredSizeFunction(&allocator->_context);
632 if (0 < size && NULL != prefFunc) {
633 newsize = (CFIndex)(INVOKE_CALLBACK3(prefFunc, size, hint, allocator->_context.info));
634 }
635 if (newsize < size) newsize = size;
636 return newsize;
637 }
638
639 void CFAllocatorGetContext(CFAllocatorRef allocator, CFAllocatorContext *context) {
640 allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
641 #if defined(__MACH__) && defined(DEBUG)
642 if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
643 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
644 }
645 #else
646 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
647 #endif
648 CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
649 #if defined(__MACH__)
650 if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
651 return;
652 }
653 #endif
654 context->version = 0;
655 context->info = allocator->_context.info;
656 context->retain = __CFAllocatorGetRetainFunction(&allocator->_context);
657 context->release = __CFAllocatorGetReleaseFunction(&allocator->_context);
658 context->copyDescription = __CFAllocatorGetCopyDescriptionFunction(&allocator->_context);
659 context->allocate = __CFAllocatorGetAllocateFunction(&allocator->_context);
660 context->reallocate = __CFAllocatorGetReallocateFunction(&allocator->_context);
661 context->deallocate = __CFAllocatorGetDeallocateFunction(&allocator->_context);
662 context->preferredSize = __CFAllocatorGetPreferredSizeFunction(&allocator->_context);
663 context->retain = (void *)((uintptr_t)context->retain & ~0x3);
664 context->release = (void *)((uintptr_t)context->release & ~0x3);
665 context->copyDescription = (void *)((uintptr_t)context->copyDescription & ~0x3);
666 context->allocate = (void *)((uintptr_t)context->allocate & ~0x3);
667 context->reallocate = (void *)((uintptr_t)context->reallocate & ~0x3);
668 context->deallocate = (void *)((uintptr_t)context->deallocate & ~0x3);
669 context->preferredSize = (void *)((uintptr_t)context->preferredSize & ~0x3);
670 }
671
672 // -------- -------- -------- -------- -------- -------- -------- --------
673
674 #if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
675 __private_extern__ pthread_key_t __CFTSDKey = (pthread_key_t)NULL;
676 #endif
677 #if defined(__WIN32__)
678 __private_extern__ DWORD __CFTSDKey = 0xFFFFFFFF;
679 #endif
680
681 // Called for each thread as it exits
682 static void __CFFinalizeThreadData(void *arg) {
683 __CFThreadSpecificData *tsd = (__CFThreadSpecificData *)arg;
684 if (NULL == tsd) return;
685 if (tsd->_allocator) CFRelease(tsd->_allocator);
686 if (tsd->_runLoop) CFRelease(tsd->_runLoop);
687 CFAllocatorDeallocate(kCFAllocatorSystemDefault, tsd);
688 }
689
690 __private_extern__ __CFThreadSpecificData *__CFGetThreadSpecificData(void) {
691 #if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
692 __CFThreadSpecificData *data;
693 data = pthread_getspecific(__CFTSDKey);
694 if (data) {
695 return data;
696 }
697 data = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFThreadSpecificData), 0);
698 if (__CFOASafe) __CFSetLastAllocationEventName(data, "CFUtilities (thread-data)");
699 memset(data, 0, sizeof(__CFThreadSpecificData));
700 pthread_setspecific(__CFTSDKey, data);
701 return data;
702 #elif defined(__WIN32__)
703 __CFThreadSpecificData *data;
704 data = TlsGetValue(__CFTSDKey);
705 if (data) {
706 return data;
707 }
708 data = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFThreadSpecificData), 0);
709 if (__CFOASafe) __CFSetLastAllocationEventName(data, "CFUtilities (thread-data)");
710 memset(data, 0, sizeof(__CFThreadSpecificData));
711 TlsSetValue(__CFTSDKey, data);
712 return data;
713 #endif
714 }
715
716 __private_extern__ void __CFBaseInitialize(void) {
717 #if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
718 pthread_key_create(&__CFTSDKey, __CFFinalizeThreadData);
719 #endif
720 #if defined(__WIN32__)
721 __CFTSDKey = TlsAlloc();
722 #endif
723 }
724
725
726 CFRange __CFRangeMake(CFIndex loc, CFIndex len) {
727 CFRange range;
728 range.location = loc;
729 range.length = len;
730 return range;
731 }
732
733 __private_extern__ const void *__CFTypeCollectionRetain(CFAllocatorRef allocator, const void *ptr) {
734 return (const void *)CFRetain(ptr);
735 }
736
737 __private_extern__ void __CFTypeCollectionRelease(CFAllocatorRef allocator, const void *ptr) {
738 CFRelease(ptr);
739 }
740
741
742 struct __CFNull {
743 CFRuntimeBase _base;
744 };
745
746 static struct __CFNull __kCFNull = {
747 {NULL, 0, 0x0080}
748 };
749 const CFNullRef kCFNull = &__kCFNull;
750
751 static CFStringRef __CFNullCopyDescription(CFTypeRef cf) {
752 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<CFNull %p [%p]>"), cf, CFGetAllocator(cf));
753 }
754
755 static CFStringRef __CFNullCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
756 return CFRetain(CFSTR("null"));
757 }
758
759 static void __CFNullDeallocate(CFTypeRef cf) {
760 CFAssert(false, __kCFLogAssertion, "Deallocated CFNull!");
761 }
762
763 static CFTypeID __kCFNullTypeID = _kCFRuntimeNotATypeID;
764
765 static const CFRuntimeClass __CFNullClass = {
766 0,
767 "CFNull",
768 NULL, // init
769 NULL, // copy
770 __CFNullDeallocate,
771 NULL,
772 NULL,
773 __CFNullCopyFormattingDescription,
774 __CFNullCopyDescription
775 };
776
777 __private_extern__ void __CFNullInitialize(void) {
778 __kCFNullTypeID = _CFRuntimeRegisterClass(&__CFNullClass);
779 _CFRuntimeSetInstanceTypeID(&__kCFNull, __kCFNullTypeID);
780 __kCFNull._base._isa = __CFISAForTypeID(__kCFNullTypeID);
781 }
782
783 CFTypeID CFNullGetTypeID(void) {
784 return __kCFNullTypeID;
785 }
786
787
788 static int hasCFM = 0;
789
790 void _CFRuntimeSetCFMPresent(int a) {
791 hasCFM = 1;
792 }
793
794 #if defined(__MACH__) && defined(__ppc__)
795
796 /* See comments below */
797 __private_extern__ void __CF_FAULT_CALLBACK(void **ptr) {
798 uintptr_t p = (uintptr_t)*ptr;
799 if ((0 == p) || (p & 0x1)) return;
800 if (0 == hasCFM) {
801 *ptr = (void *)(p | 0x1);
802 } else {
803 int __known = _dyld_image_containing_address(p);
804 *ptr = (void *)(p | (__known ? 0x1 : 0x3));
805 }
806 }
807
808 /*
809 Jump to callback function. r2 is not saved and restored
810 in the jump-to-CFM case, since we assume that dyld code
811 never uses that register and that CF is dyld.
812
813 There are three states for (ptr & 0x3):
814 0b00: check not yet done (or not going to be done, and is a dyld func ptr)
815 0b01: check done, dyld function pointer
816 0b11: check done, CFM tvector pointer
817 (but a NULL callback just stays NULL)
818
819 There may be up to 5 word-sized arguments. Floating point
820 arguments can be done, but count as two word arguments.
821 Return value can be integral or real.
822 */
823
824 /* Keep this assembly at the bottom of the source file! */
825
826 __asm__ (
827 ".text\n"
828 " .align 2\n"
829 ".private_extern ___CF_INVOKE_CALLBACK\n"
830 "___CF_INVOKE_CALLBACK:\n"
831 "rlwinm r12,r3,0,0,29\n"
832 "andi. r0,r3,0x2\n"
833 "or r3,r4,r4\n"
834 "or r4,r5,r5\n"
835 "or r5,r6,r6\n"
836 "or r6,r7,r7\n"
837 "or r7,r8,r8\n"
838 "beq- Lcall\n"
839 "lwz r2,0x4(r12)\n"
840 "lwz r12,0x0(r12)\n"
841 "Lcall: mtspr ctr,r12\n"
842 "bctr\n");
843
844 #endif
845
846
847 // void __HALT(void);
848
849 #if defined(__ppc__)
850 __asm__ (
851 ".text\n"
852 " .align 2\n"
853 #if defined(__MACH__)
854 ".private_extern ___HALT\n"
855 #else
856 ".globl ___HALT\n"
857 #endif
858 "___HALT:\n"
859 " trap\n"
860 );
861 #endif
862
863 #if defined(__i386__)
864 __asm__ (
865 ".text\n"
866 " .align 2, 0x90\n"
867 #if defined(__MACH__)
868 ".private_extern ___HALT\n"
869 #else
870 ".globl ___HALT\n"
871 #endif
872 "___HALT:\n"
873 " int3\n"
874 );
875 #endif
876