]> git.saurik.com Git - apple/cf.git/blob - Base.subproj/CFBase.c
CF-368.18.tar.gz
[apple/cf.git] / Base.subproj / CFBase.c
1 /*
2 * Copyright (c) 2005 Apple Computer, 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 /* CFBase.c
24 Copyright 1998-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
26 */
27
28 #include <CoreFoundation/CFBase.h>
29 #include "CFInternal.h"
30 #if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
31 #include <pthread.h>
32 #endif
33 #if defined(__MACH__)
34 #endif
35 #if defined(__WIN32__)
36 #include <windows.h>
37 #endif
38 #if defined(__MACH__)
39 #include <malloc/malloc.h>
40 extern size_t malloc_good_size(size_t size);
41 #include <mach/mach.h>
42 #include <dlfcn.h>
43 #endif
44 #include <stdlib.h>
45 #include <string.h>
46
47 #if defined(__CYGWIN32__) || defined (D__CYGWIN_)
48 #error CoreFoundation is currently built with the Microsoft C Runtime, which is incompatible with the Cygwin DLL. You must either use the -mno-cygwin flag, or complete a port of CF to the Cygwin environment.
49 #endif
50
51 // -------- -------- -------- -------- -------- -------- -------- --------
52
53 #if defined(__MACH__)
54 // CFAllocator structure must match struct _malloc_zone_t!
55 // The first two reserved fields in struct _malloc_zone_t are for us with CFRuntimeBase
56 #endif
57 struct __CFAllocator {
58 CFRuntimeBase _base;
59 #if defined(__MACH__)
60 size_t (*size)(struct _malloc_zone_t *zone, const void *ptr); /* returns the size of a block or 0 if not in this zone; must be fast, especially for negative answers */
61 void *(*malloc)(struct _malloc_zone_t *zone, size_t size);
62 void *(*calloc)(struct _malloc_zone_t *zone, size_t num_items, size_t size); /* same as malloc, but block returned is set to zero */
63 void *(*valloc)(struct _malloc_zone_t *zone, size_t size); /* same as malloc, but block returned is set to zero and is guaranteed to be page aligned */
64 void (*free)(struct _malloc_zone_t *zone, void *ptr);
65 void *(*realloc)(struct _malloc_zone_t *zone, void *ptr, size_t size);
66 void (*destroy)(struct _malloc_zone_t *zone); /* zone is destroyed and all memory reclaimed */
67 const char *zone_name;
68 unsigned (*batch_malloc)(struct _malloc_zone_t *zone, size_t size, void **results, unsigned num_requested); /* given a size, returns pointers capable of holding that size; returns the number of pointers allocated (maybe 0 or less than num_requested) */
69 void (*batch_free)(struct _malloc_zone_t *zone, void **to_be_freed, unsigned num_to_be_freed); /* frees all the pointers in to_be_freed; note that to_be_freed may be overwritten during the process */
70 struct malloc_introspection_t *introspect;
71 void *reserved5;
72 #endif
73 CFAllocatorRef _allocator;
74 CFAllocatorContext _context;
75 };
76
77 CF_INLINE CFAllocatorRetainCallBack __CFAllocatorGetRetainFunction(const CFAllocatorContext *context) {
78 CFAllocatorRetainCallBack retval = NULL;
79 retval = context->retain;
80 return retval;
81 }
82
83 CF_INLINE CFAllocatorReleaseCallBack __CFAllocatorGetReleaseFunction(const CFAllocatorContext *context) {
84 CFAllocatorReleaseCallBack retval = NULL;
85 retval = context->release;
86 return retval;
87 }
88
89 CF_INLINE CFAllocatorCopyDescriptionCallBack __CFAllocatorGetCopyDescriptionFunction(const CFAllocatorContext *context) {
90 CFAllocatorCopyDescriptionCallBack retval = NULL;
91 retval = context->copyDescription;
92 return retval;
93 }
94
95 CF_INLINE CFAllocatorAllocateCallBack __CFAllocatorGetAllocateFunction(const CFAllocatorContext *context) {
96 CFAllocatorAllocateCallBack retval = NULL;
97 retval = context->allocate;
98 return retval;
99 }
100
101 CF_INLINE CFAllocatorReallocateCallBack __CFAllocatorGetReallocateFunction(const CFAllocatorContext *context) {
102 CFAllocatorReallocateCallBack retval = NULL;
103 retval = context->reallocate;
104 return retval;
105 }
106
107 CF_INLINE CFAllocatorDeallocateCallBack __CFAllocatorGetDeallocateFunction(const CFAllocatorContext *context) {
108 CFAllocatorDeallocateCallBack retval = NULL;
109 retval = context->deallocate;
110 return retval;
111 }
112
113 CF_INLINE CFAllocatorPreferredSizeCallBack __CFAllocatorGetPreferredSizeFunction(const CFAllocatorContext *context) {
114 CFAllocatorPreferredSizeCallBack retval = NULL;
115 retval = context->preferredSize;
116 return retval;
117 }
118
119 #if defined(__MACH__)
120
121 __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf);
122
123 static kern_return_t __CFAllocatorZoneIntrospectNoOp(void) {
124 return 0;
125 }
126
127 static boolean_t __CFAllocatorZoneIntrospectTrue(void) {
128 return 1;
129 }
130
131 static size_t __CFAllocatorCustomSize(malloc_zone_t *zone, const void *ptr) {
132 return 0;
133
134 // The only way to implement this with a version 0 allocator would be
135 // for CFAllocator to keep track of all blocks allocated itself, which
136 // could be done, but would be bad for performance, so we don't do it.
137 // size_t (*size)(struct _malloc_zone_t *zone, const void *ptr);
138 /* returns the size of a block or 0 if not in this zone;
139 * must be fast, especially for negative answers */
140 }
141
142 static void *__CFAllocatorCustomMalloc(malloc_zone_t *zone, size_t size) {
143 CFAllocatorRef allocator = (CFAllocatorRef)zone;
144 return CFAllocatorAllocate(allocator, size, 0);
145 }
146
147 static void *__CFAllocatorCustomCalloc(malloc_zone_t *zone, size_t num_items, size_t size) {
148 CFAllocatorRef allocator = (CFAllocatorRef)zone;
149 void *newptr = CFAllocatorAllocate(allocator, size, 0);
150 if (newptr) memset(newptr, 0, size);
151 return newptr;
152 }
153
154 static void *__CFAllocatorCustomValloc(malloc_zone_t *zone, size_t size) {
155 CFAllocatorRef allocator = (CFAllocatorRef)zone;
156 void *newptr = CFAllocatorAllocate(allocator, size + vm_page_size, 0);
157 newptr = (void *)round_page((unsigned)newptr);
158 return newptr;
159 }
160
161 static void __CFAllocatorCustomFree(malloc_zone_t *zone, void *ptr) {
162 CFAllocatorRef allocator = (CFAllocatorRef)zone;
163 CFAllocatorDeallocate(allocator, ptr);
164 }
165
166 static void *__CFAllocatorCustomRealloc(malloc_zone_t *zone, void *ptr, size_t size) {
167 CFAllocatorRef allocator = (CFAllocatorRef)zone;
168 return CFAllocatorReallocate(allocator, ptr, size, 0);
169 }
170
171 static void __CFAllocatorCustomDestroy(malloc_zone_t *zone) {
172 CFAllocatorRef allocator = (CFAllocatorRef)zone;
173 // !!! we do it, and caller of malloc_destroy_zone() assumes
174 // COMPLETE responsibility for the result; NO Apple library
175 // code should be modified as a result of discovering that
176 // some activity results in inconveniences to developers
177 // trying to use malloc_destroy_zone() with a CFAllocatorRef;
178 // that's just too bad for them.
179 __CFAllocatorDeallocate(allocator);
180 }
181
182 static size_t __CFAllocatorCustomGoodSize(malloc_zone_t *zone, size_t size) {
183 CFAllocatorRef allocator = (CFAllocatorRef)zone;
184 return CFAllocatorGetPreferredSizeForSize(allocator, size, 0);
185 }
186
187 static struct malloc_introspection_t __CFAllocatorZoneIntrospect = {
188 (void *)__CFAllocatorZoneIntrospectNoOp,
189 (void *)__CFAllocatorCustomGoodSize,
190 (void *)__CFAllocatorZoneIntrospectTrue,
191 (void *)__CFAllocatorZoneIntrospectNoOp,
192 (void *)__CFAllocatorZoneIntrospectNoOp,
193 (void *)__CFAllocatorZoneIntrospectNoOp,
194 (void *)__CFAllocatorZoneIntrospectNoOp,
195 (void *)__CFAllocatorZoneIntrospectNoOp
196 };
197
198 static size_t __CFAllocatorNullSize(malloc_zone_t *zone, const void *ptr) {
199 return 0;
200 }
201
202 static void * __CFAllocatorNullMalloc(malloc_zone_t *zone, size_t size) {
203 return NULL;
204 }
205
206 static void * __CFAllocatorNullCalloc(malloc_zone_t *zone, size_t num_items, size_t size) {
207 return NULL;
208 }
209
210 static void * __CFAllocatorNullValloc(malloc_zone_t *zone, size_t size) {
211 return NULL;
212 }
213
214 static void __CFAllocatorNullFree(malloc_zone_t *zone, void *ptr) {
215 }
216
217 static void * __CFAllocatorNullRealloc(malloc_zone_t *zone, void *ptr, size_t size) {
218 return NULL;
219 }
220
221 static void __CFAllocatorNullDestroy(malloc_zone_t *zone) {
222 }
223
224 static size_t __CFAllocatorNullGoodSize(malloc_zone_t *zone, size_t size) {
225 return size;
226 }
227
228 static struct malloc_introspection_t __CFAllocatorNullZoneIntrospect = {
229 (void *)__CFAllocatorZoneIntrospectNoOp,
230 (void *)__CFAllocatorNullGoodSize,
231 (void *)__CFAllocatorZoneIntrospectTrue,
232 (void *)__CFAllocatorZoneIntrospectNoOp,
233 (void *)__CFAllocatorZoneIntrospectNoOp,
234 (void *)__CFAllocatorZoneIntrospectNoOp,
235 (void *)__CFAllocatorZoneIntrospectNoOp,
236 (void *)__CFAllocatorZoneIntrospectNoOp
237 };
238
239 static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) {
240 return malloc_zone_malloc(info, size);
241 }
242
243 static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
244 return malloc_zone_realloc(info, ptr, newsize);
245 }
246
247 static void __CFAllocatorSystemDeallocate(void *ptr, void *info) {
248 #if defined(DEBUG)
249 size_t size = malloc_size(ptr);
250 if (size) memset(ptr, 0xCC, size);
251 #endif
252 malloc_zone_free(info, ptr);
253 }
254
255 #endif
256
257 #if defined(__WIN32__) || defined(__LINUX__) || defined(__FREEBSD__)
258 static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) {
259 return malloc(size);
260 }
261
262 static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
263 return realloc(ptr, newsize);
264 }
265
266 static void __CFAllocatorSystemDeallocate(void *ptr, void *info) {
267 free(ptr);
268 }
269 #endif
270
271 static void *__CFAllocatorNullAllocate(CFIndex size, CFOptionFlags hint, void *info) {
272 return NULL;
273 }
274
275 static void *__CFAllocatorNullReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
276 return NULL;
277 }
278
279 static struct __CFAllocator __kCFAllocatorMalloc = {
280 {NULL, 0, 0x0080},
281 #if defined(__MACH__)
282 __CFAllocatorCustomSize,
283 __CFAllocatorCustomMalloc,
284 __CFAllocatorCustomCalloc,
285 __CFAllocatorCustomValloc,
286 __CFAllocatorCustomFree,
287 __CFAllocatorCustomRealloc,
288 __CFAllocatorNullDestroy,
289 "kCFAllocatorMalloc",
290 NULL,
291 NULL,
292 &__CFAllocatorZoneIntrospect,
293 NULL,
294 #endif
295 NULL, // _allocator
296 // Using the malloc functions directly is a total cheat, but works (in C)
297 // because the function signatures match in their common prefix of arguments.
298 // This saves us one hop through an adaptor function.
299 {0, NULL, NULL, NULL, NULL, (void *)malloc, (void *)realloc, (void *)free, NULL}
300 };
301
302 static struct __CFAllocator __kCFAllocatorMallocZone = {
303 {NULL, 0, 0x0080},
304 #if defined(__MACH__)
305 __CFAllocatorCustomSize,
306 __CFAllocatorCustomMalloc,
307 __CFAllocatorCustomCalloc,
308 __CFAllocatorCustomValloc,
309 __CFAllocatorCustomFree,
310 __CFAllocatorCustomRealloc,
311 __CFAllocatorNullDestroy,
312 "kCFAllocatorMallocZone",
313 NULL,
314 NULL,
315 &__CFAllocatorZoneIntrospect,
316 NULL,
317 #endif
318 NULL, // _allocator
319 {0, NULL, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL}
320 };
321
322 static struct __CFAllocator __kCFAllocatorSystemDefault = {
323 {NULL, 0, 0x0080},
324 #if defined(__MACH__)
325 __CFAllocatorCustomSize,
326 __CFAllocatorCustomMalloc,
327 __CFAllocatorCustomCalloc,
328 __CFAllocatorCustomValloc,
329 __CFAllocatorCustomFree,
330 __CFAllocatorCustomRealloc,
331 __CFAllocatorNullDestroy,
332 "kCFAllocatorSystemDefault",
333 NULL,
334 NULL,
335 &__CFAllocatorZoneIntrospect,
336 NULL,
337 #endif
338 NULL, // _allocator
339 {0, NULL, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL}
340 };
341
342 static struct __CFAllocator __kCFAllocatorNull = {
343 {NULL, 0, 0x0080},
344 #if defined(__MACH__)
345 __CFAllocatorNullSize,
346 __CFAllocatorNullMalloc,
347 __CFAllocatorNullCalloc,
348 __CFAllocatorNullValloc,
349 __CFAllocatorNullFree,
350 __CFAllocatorNullRealloc,
351 __CFAllocatorNullDestroy,
352 "kCFAllocatorNull",
353 NULL,
354 NULL,
355 &__CFAllocatorNullZoneIntrospect,
356 NULL,
357 #endif
358 NULL, // _allocator
359 {0, NULL, NULL, NULL, NULL, __CFAllocatorNullAllocate, __CFAllocatorNullReallocate, NULL, NULL}
360 };
361
362 const CFAllocatorRef kCFAllocatorDefault = NULL;
363 const CFAllocatorRef kCFAllocatorSystemDefault = &__kCFAllocatorSystemDefault;
364 const CFAllocatorRef kCFAllocatorMalloc = &__kCFAllocatorMalloc;
365 const CFAllocatorRef kCFAllocatorMallocZone = &__kCFAllocatorMallocZone;
366 const CFAllocatorRef kCFAllocatorNull = &__kCFAllocatorNull;
367 const CFAllocatorRef kCFAllocatorUseContext = (CFAllocatorRef)0x0227;
368
369 bool kCFUseCollectableAllocator = false;
370
371 static CFStringRef __CFAllocatorCopyDescription(CFTypeRef cf) {
372 CFAllocatorRef self = cf;
373 CFAllocatorRef allocator = (kCFAllocatorUseContext == self->_allocator) ? self : self->_allocator;
374 return CFStringCreateWithFormat(allocator, NULL, CFSTR("<CFAllocator 0x%x [0x%x]>{info = 0x%x}"), (UInt32)cf, (UInt32)allocator, self->_context.info);
375 // CF: should use copyDescription function here to describe info field
376 // remember to release value returned from copydescr function when this happens
377 }
378
379 __private_extern__ CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef cf) {
380 CFAllocatorRef allocator = cf;
381 return (kCFAllocatorUseContext == allocator->_allocator) ? allocator : allocator->_allocator;
382 }
383
384 __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf) {
385 CFAllocatorRef self = cf;
386 CFAllocatorRef allocator = self->_allocator;
387 CFAllocatorReleaseCallBack releaseFunc = __CFAllocatorGetReleaseFunction(&self->_context);
388 if (kCFAllocatorUseContext == allocator) {
389 /* Rather a chicken and egg problem here, so we do things
390 in the reverse order from what was done at create time. */
391 CFAllocatorDeallocateCallBack deallocateFunc = __CFAllocatorGetDeallocateFunction(&self->_context);
392 void *info = self->_context.info;
393 if (NULL != deallocateFunc) {
394 INVOKE_CALLBACK2(deallocateFunc, (void *)self, info);
395 }
396 if (NULL != releaseFunc) {
397 INVOKE_CALLBACK1(releaseFunc, info);
398 }
399 } else {
400 if (NULL != releaseFunc) {
401 INVOKE_CALLBACK1(releaseFunc, self->_context.info);
402 }
403 CFAllocatorDeallocate(allocator, (void *)self);
404 }
405 }
406
407 static CFTypeID __kCFAllocatorTypeID = _kCFRuntimeNotATypeID;
408
409 static const CFRuntimeClass __CFAllocatorClass = {
410 0,
411 "CFAllocator",
412 NULL, // init
413 NULL, // copy
414 __CFAllocatorDeallocate,
415 NULL, // equal
416 NULL, // hash
417 NULL, //
418 __CFAllocatorCopyDescription
419 };
420
421 __private_extern__ void __CFAllocatorInitialize(void) {
422 __kCFAllocatorTypeID = _CFRuntimeRegisterClass(&__CFAllocatorClass);
423
424 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorSystemDefault, __kCFAllocatorTypeID);
425 __kCFAllocatorSystemDefault._base._isa = __CFISAForTypeID(__kCFAllocatorTypeID);
426 #if defined(__MACH__)
427 __kCFAllocatorSystemDefault._context.info = (CF_USING_COLLECTABLE_MEMORY ? __CFCollectableZone : malloc_default_zone());
428 memset(malloc_default_zone(), 0, 8);
429 #endif
430 __kCFAllocatorSystemDefault._allocator = kCFAllocatorSystemDefault;
431
432 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMalloc, __kCFAllocatorTypeID);
433 __kCFAllocatorMalloc._base._isa = __CFISAForTypeID(__kCFAllocatorTypeID);
434 __kCFAllocatorMalloc._allocator = kCFAllocatorSystemDefault;
435
436 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMallocZone, __kCFAllocatorTypeID);
437 __kCFAllocatorMallocZone._base._isa = __CFISAForTypeID(__kCFAllocatorTypeID);
438 __kCFAllocatorMallocZone._allocator = kCFAllocatorSystemDefault;
439 __kCFAllocatorMallocZone._context.info = malloc_default_zone();
440
441 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorNull, __kCFAllocatorTypeID);
442 __kCFAllocatorNull._base._isa = __CFISAForTypeID(__kCFAllocatorTypeID);
443 __kCFAllocatorNull._allocator = kCFAllocatorSystemDefault;
444
445 }
446
447 CFTypeID CFAllocatorGetTypeID(void) {
448 return __kCFAllocatorTypeID;
449 }
450
451 CFAllocatorRef CFAllocatorGetDefault(void) {
452 CFAllocatorRef allocator = __CFGetThreadSpecificData_inline()->_allocator;
453 if (NULL == allocator) {
454 allocator = kCFAllocatorSystemDefault;
455 }
456 return allocator;
457 }
458
459 void CFAllocatorSetDefault(CFAllocatorRef allocator) {
460 CFAllocatorRef current = __CFGetThreadSpecificData_inline()->_allocator;
461 #if defined(DEBUG)
462 if (NULL != allocator) {
463 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
464 }
465 #endif
466 #if defined(__MACH__)
467 if (allocator && allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
468 return; // require allocator to this function to be an allocator
469 }
470 #endif
471 if (NULL != allocator && allocator != current) {
472 if (current) CFRelease(current);
473 CFRetain(allocator);
474 // We retain an extra time so that anything set as the default
475 // allocator never goes away.
476 CFRetain(allocator);
477 __CFGetThreadSpecificData_inline()->_allocator = (void *)allocator;
478 }
479 }
480
481 static CFAllocatorRef __CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) {
482 struct __CFAllocator *memory = NULL;
483 CFAllocatorRetainCallBack retainFunc;
484 CFAllocatorAllocateCallBack allocateFunc;
485 void *retainedInfo;
486 #if defined(__MACH__)
487 if (allocator && kCFAllocatorUseContext != allocator && allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
488 return NULL; // require allocator to this function to be an allocator
489 }
490 #endif
491 retainFunc = context->retain;
492 FAULT_CALLBACK((void **)&retainFunc);
493 allocateFunc = context->allocate;
494 FAULT_CALLBACK((void **)&allocateFunc);
495 if (NULL != retainFunc) {
496 retainedInfo = (void *)INVOKE_CALLBACK1(retainFunc, context->info);
497 } else {
498 retainedInfo = context->info;
499 }
500 // We don't use _CFRuntimeCreateInstance()
501 if (kCFAllocatorUseContext == allocator) {
502 memory = NULL;
503 if (allocateFunc) {
504 memory = (void *)INVOKE_CALLBACK3(allocateFunc, sizeof(struct __CFAllocator), 0, retainedInfo);
505 }
506 if (NULL == memory) {
507 return NULL;
508 }
509 } else {
510 allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
511 memory = CFAllocatorAllocate(allocator, sizeof(struct __CFAllocator), 0);
512 if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFAllocator");
513 if (NULL == memory) {
514 return NULL;
515 }
516 }
517 memory->_base._isa = 0;
518 memory->_base._rc = 1;
519 memory->_base._info = 0;
520 _CFRuntimeSetInstanceTypeID(memory, __kCFAllocatorTypeID);
521 memory->_base._isa = __CFISAForTypeID(__kCFAllocatorTypeID);
522 #if defined(__MACH__)
523 memory->size = __CFAllocatorCustomSize;
524 memory->malloc = __CFAllocatorCustomMalloc;
525 memory->calloc = __CFAllocatorCustomCalloc;
526 memory->valloc = __CFAllocatorCustomValloc;
527 memory->free = __CFAllocatorCustomFree;
528 memory->realloc = __CFAllocatorCustomRealloc;
529 memory->destroy = __CFAllocatorCustomDestroy;
530 memory->zone_name = "Custom CFAllocator";
531 memory->batch_malloc = NULL;
532 memory->batch_free = NULL;
533 memory->introspect = &__CFAllocatorZoneIntrospect;
534 memory->reserved5 = NULL;
535 #endif
536 memory->_allocator = allocator;
537 memory->_context.version = context->version;
538 memory->_context.info = retainedInfo;
539 memory->_context.retain = retainFunc;
540 memory->_context.release = context->release;
541 FAULT_CALLBACK((void **)&(memory->_context.release));
542 memory->_context.copyDescription = context->copyDescription;
543 FAULT_CALLBACK((void **)&(memory->_context.copyDescription));
544 memory->_context.allocate = allocateFunc;
545 memory->_context.reallocate = context->reallocate;
546 FAULT_CALLBACK((void **)&(memory->_context.reallocate));
547 memory->_context.deallocate = context->deallocate;
548 FAULT_CALLBACK((void **)&(memory->_context.deallocate));
549 memory->_context.preferredSize = context->preferredSize;
550 FAULT_CALLBACK((void **)&(memory->_context.preferredSize));
551
552 return memory;
553 }
554
555 CFAllocatorRef CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) {
556 CFAssert1(!CF_USING_COLLECTABLE_MEMORY, __kCFLogAssertion, "%s(): Shouldn't be called when GC is enabled!", __PRETTY_FUNCTION__);
557 #if defined(DEBUG)
558 if (CF_USING_COLLECTABLE_MEMORY)
559 HALT;
560 #endif
561 return __CFAllocatorCreate(allocator, context);
562 }
563
564 CFAllocatorRef _CFAllocatorCreateGC(CFAllocatorRef allocator, CFAllocatorContext *context) {
565 return __CFAllocatorCreate(allocator, context);
566 }
567
568 void *CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) {
569 CFAllocatorAllocateCallBack allocateFunc;
570 void *newptr = NULL;
571 allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
572 #if defined(__MACH__) && defined(DEBUG)
573 if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
574 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
575 }
576 #else
577 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
578 #endif
579 if (0 == size) return NULL;
580 #if defined(__MACH__)
581 if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
582 return malloc_zone_malloc((malloc_zone_t *)allocator, size);
583 }
584 #endif
585 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
586 newptr = auto_zone_allocate_object((auto_zone_t*)allocator->_context.info, size, (auto_memory_type_t)hint, true, false);
587 } else {
588 newptr = NULL;
589 allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context);
590 if (allocateFunc) {
591 newptr = (void *)INVOKE_CALLBACK3(allocateFunc, size, hint, allocator->_context.info);
592 }
593 }
594 return newptr;
595 }
596
597 void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint) {
598 CFAllocatorAllocateCallBack allocateFunc;
599 CFAllocatorReallocateCallBack reallocateFunc;
600 CFAllocatorDeallocateCallBack deallocateFunc;
601 void *newptr;
602 allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
603 #if defined(__MACH__) && defined(DEBUG)
604 if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
605 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
606 }
607 #else
608 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
609 #endif
610 if (NULL == ptr && 0 < newsize) {
611 #if defined(__MACH__)
612 if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
613 return malloc_zone_malloc((malloc_zone_t *)allocator, newsize);
614 }
615 #endif
616 newptr = NULL;
617 allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context);
618 if (allocateFunc) {
619 newptr = (void *)INVOKE_CALLBACK3(allocateFunc, newsize, hint, allocator->_context.info);
620 }
621 return newptr;
622 }
623 if (NULL != ptr && 0 == newsize) {
624 #if defined(__MACH__)
625 if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
626 #if defined(DEBUG)
627 size_t size = malloc_size(ptr);
628 if (size) memset(ptr, 0xCC, size);
629 #endif
630 malloc_zone_free((malloc_zone_t *)allocator, ptr);
631 return NULL;
632 }
633 #endif
634 deallocateFunc = __CFAllocatorGetDeallocateFunction(&allocator->_context);
635 if (NULL != deallocateFunc) {
636 INVOKE_CALLBACK2(deallocateFunc, ptr, allocator->_context.info);
637 }
638 return NULL;
639 }
640 if (NULL == ptr && 0 == newsize) return NULL;
641 #if defined(__MACH__)
642 if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
643 return malloc_zone_realloc((malloc_zone_t *)allocator, ptr, newsize);
644 }
645 #endif
646 reallocateFunc = __CFAllocatorGetReallocateFunction(&allocator->_context);
647 if (NULL == reallocateFunc) return NULL;
648 newptr = (void *)INVOKE_CALLBACK4(reallocateFunc, ptr, newsize, hint, allocator->_context.info);
649 return newptr;
650 }
651
652 void CFAllocatorDeallocate(CFAllocatorRef allocator, void *ptr) {
653 CFAllocatorDeallocateCallBack deallocateFunc;
654 allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
655 #if defined(__MACH__) && defined(DEBUG)
656 if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
657 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
658 }
659 #else
660 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
661 #endif
662 #if defined(__MACH__)
663 if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
664 #if defined(DEBUG)
665 size_t size = malloc_size(ptr);
666 if (size) memset(ptr, 0xCC, size);
667 #endif
668 return malloc_zone_free((malloc_zone_t *)allocator, ptr);
669 }
670 #endif
671 deallocateFunc = __CFAllocatorGetDeallocateFunction(&allocator->_context);
672 if (NULL != ptr && NULL != deallocateFunc) {
673 INVOKE_CALLBACK2(deallocateFunc, ptr, allocator->_context.info);
674 }
675 }
676
677 CFIndex CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) {
678 CFAllocatorPreferredSizeCallBack prefFunc;
679 CFIndex newsize = 0;
680 allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
681 #if defined(__MACH__) && defined(DEBUG)
682 if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
683 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
684 }
685 #else
686 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
687 #endif
688 #if defined(__MACH__)
689 if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
690 return malloc_good_size(size);
691 }
692 #endif
693 prefFunc = __CFAllocatorGetPreferredSizeFunction(&allocator->_context);
694 if (0 < size && NULL != prefFunc) {
695 newsize = (CFIndex)(INVOKE_CALLBACK3(prefFunc, size, hint, allocator->_context.info));
696 }
697 if (newsize < size) newsize = size;
698 return newsize;
699 }
700
701 void CFAllocatorGetContext(CFAllocatorRef allocator, CFAllocatorContext *context) {
702 allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator;
703 #if defined(__MACH__) && defined(DEBUG)
704 if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) {
705 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
706 }
707 #else
708 __CFGenericValidateType(allocator, __kCFAllocatorTypeID);
709 #endif
710 CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__);
711 #if defined(__MACH__)
712 if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
713 return;
714 }
715 #endif
716 context->version = 0;
717 context->info = allocator->_context.info;
718 context->retain = __CFAllocatorGetRetainFunction(&allocator->_context);
719 context->release = __CFAllocatorGetReleaseFunction(&allocator->_context);
720 context->copyDescription = __CFAllocatorGetCopyDescriptionFunction(&allocator->_context);
721 context->allocate = __CFAllocatorGetAllocateFunction(&allocator->_context);
722 context->reallocate = __CFAllocatorGetReallocateFunction(&allocator->_context);
723 context->deallocate = __CFAllocatorGetDeallocateFunction(&allocator->_context);
724 context->preferredSize = __CFAllocatorGetPreferredSizeFunction(&allocator->_context);
725 #if defined(__ppc__)
726 context->retain = (void *)((uintptr_t)context->retain & ~0x3);
727 context->release = (void *)((uintptr_t)context->release & ~0x3);
728 context->copyDescription = (void *)((uintptr_t)context->copyDescription & ~0x3);
729 context->allocate = (void *)((uintptr_t)context->allocate & ~0x3);
730 context->reallocate = (void *)((uintptr_t)context->reallocate & ~0x3);
731 context->deallocate = (void *)((uintptr_t)context->deallocate & ~0x3);
732 context->preferredSize = (void *)((uintptr_t)context->preferredSize & ~0x3);
733 #endif
734 }
735
736 void *_CFAllocatorAllocateGC(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint)
737 {
738 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator))
739 return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, size, (auto_memory_type_t)hint, false, false);
740 else
741 return CFAllocatorAllocate(allocator, size, hint);
742 }
743
744 void *_CFAllocatorReallocateGC(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint)
745 {
746 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
747 if (ptr && (newsize == 0)) {
748 return NULL; // equivalent to _CFAllocatorDeallocateGC.
749 }
750 if (ptr == NULL) {
751 return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, newsize, (auto_memory_type_t)hint, false, false); // eq. to _CFAllocator
752 }
753 }
754 // otherwise, auto_realloc() now preserves layout type and refCount.
755 return CFAllocatorReallocate(allocator, ptr, newsize, hint);
756 }
757
758 void _CFAllocatorDeallocateGC(CFAllocatorRef allocator, void *ptr)
759 {
760 // when running GC, don't deallocate.
761 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) CFAllocatorDeallocate(allocator, ptr);
762 }
763
764 // -------- -------- -------- -------- -------- -------- -------- --------
765
766 #if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
767 __private_extern__ pthread_key_t __CFTSDKey = (pthread_key_t)NULL;
768 #endif
769 #if defined(__WIN32__)
770 __private_extern__ DWORD __CFTSDKey = 0xFFFFFFFF;
771 #endif
772
773 // Called for each thread as it exits
774 __private_extern__ void __CFFinalizeThreadData(void *arg) {
775 #if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
776 __CFThreadSpecificData *tsd = (__CFThreadSpecificData *)arg;
777 #elif defined(__WIN32)
778 __CFThreadSpecificData *tsd = TlsGetValue(__CFTSDKey);
779 TlsSetValue(__CFTSDKey, NULL);
780 #endif
781 if (NULL == tsd) return;
782 if (tsd->_allocator) CFRelease(tsd->_allocator);
783 if (tsd->_runLoop) CFRelease(tsd->_runLoop);
784 CFAllocatorDeallocate(kCFAllocatorSystemDefault, tsd);
785 }
786
787 __private_extern__ __CFThreadSpecificData *__CFGetThreadSpecificData(void) {
788 #if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
789 __CFThreadSpecificData *data;
790 data = pthread_getspecific(__CFTSDKey);
791 if (data) {
792 return data;
793 }
794 data = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFThreadSpecificData), 0);
795 if (__CFOASafe) __CFSetLastAllocationEventName(data, "CFUtilities (thread-data)");
796 memset(data, 0, sizeof(__CFThreadSpecificData));
797 pthread_setspecific(__CFTSDKey, data);
798 return data;
799 #elif defined(__WIN32__)
800 __CFThreadSpecificData *data;
801 data = TlsGetValue(__CFTSDKey);
802 if (data) {
803 return data;
804 }
805 data = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFThreadSpecificData), 0);
806 if (__CFOASafe) __CFSetLastAllocationEventName(data, "CFUtilities (thread-data)");
807 memset(data, 0, sizeof(__CFThreadSpecificData));
808 TlsSetValue(__CFTSDKey, data);
809 return data;
810 #endif
811 }
812
813 __private_extern__ void __CFBaseInitialize(void) {
814 #if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
815 pthread_key_create(&__CFTSDKey, __CFFinalizeThreadData);
816 #endif
817 #if defined(__WIN32__)
818 __CFTSDKey = TlsAlloc();
819 #endif
820 //kCFUseCollectableAllocator = objc_collecting_enabled();
821 }
822
823 #if defined(__WIN32__)
824 __private_extern__ void __CFBaseCleanup(void) {
825 TlsFree(__CFTSDKey);
826 }
827 #endif
828
829
830 CFRange __CFRangeMake(CFIndex loc, CFIndex len) {
831 CFRange range;
832 range.location = loc;
833 range.length = len;
834 return range;
835 }
836
837 __private_extern__ const void *__CFTypeCollectionRetain(CFAllocatorRef allocator, const void *ptr) {
838 return (const void *)CFRetain(ptr);
839 }
840
841 __private_extern__ void __CFTypeCollectionRelease(CFAllocatorRef allocator, const void *ptr) {
842 CFRelease(ptr);
843 }
844
845
846 struct __CFNull {
847 CFRuntimeBase _base;
848 };
849
850 static struct __CFNull __kCFNull = {
851 INIT_CFRUNTIME_BASE(NULL, 0, 0x0080)
852 };
853 const CFNullRef kCFNull = &__kCFNull;
854
855 static CFStringRef __CFNullCopyDescription(CFTypeRef cf) {
856 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<CFNull %p [%p]>"), cf, CFGetAllocator(cf));
857 }
858
859 static CFStringRef __CFNullCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
860 return CFRetain(CFSTR("null"));
861 }
862
863 static void __CFNullDeallocate(CFTypeRef cf) {
864 CFAssert(false, __kCFLogAssertion, "Deallocated CFNull!");
865 }
866
867 static CFTypeID __kCFNullTypeID = _kCFRuntimeNotATypeID;
868
869 static const CFRuntimeClass __CFNullClass = {
870 0,
871 "CFNull",
872 NULL, // init
873 NULL, // copy
874 __CFNullDeallocate,
875 NULL,
876 NULL,
877 __CFNullCopyFormattingDescription,
878 __CFNullCopyDescription
879 };
880
881 __private_extern__ void __CFNullInitialize(void) {
882 __kCFNullTypeID = _CFRuntimeRegisterClass(&__CFNullClass);
883 _CFRuntimeSetInstanceTypeID(&__kCFNull, __kCFNullTypeID);
884 __kCFNull._base._isa = __CFISAForTypeID(__kCFNullTypeID);
885 }
886
887 CFTypeID CFNullGetTypeID(void) {
888 return __kCFNullTypeID;
889 }
890
891
892 static int hasCFM = 0;
893
894 void _CFRuntimeSetCFMPresent(void *addr) {
895 hasCFM = 1;
896 }
897
898 #if defined(__MACH__) && defined(__ppc__)
899
900 /* See comments below */
901 __private_extern__ void __CF_FAULT_CALLBACK(void **ptr) {
902 uintptr_t p = (uintptr_t)*ptr;
903 if ((0 == p) || (p & 0x1)) return;
904 // warning: revisit this address check in Chablis, and for 64-bit
905 if (0 == hasCFM || (0x90000000 <= p && p < 0xA0000000)) {
906 *ptr = (void *)(p | 0x1);
907 } else {
908 Dl_info info;
909 int __known = dladdr(p, &info);
910 *ptr = (void *)(p | (__known ? 0x1 : 0x3));
911 }
912 }
913
914 /*
915 Jump to callback function. r2 is not saved and restored
916 in the jump-to-CFM case, since we assume that dyld code
917 never uses that register and that CF is dyld.
918
919 There are three states for (ptr & 0x3):
920 0b00: check not yet done (or not going to be done, and is a dyld func ptr)
921 0b01: check done, dyld function pointer
922 0b11: check done, CFM tvector pointer
923 (but a NULL callback just stays NULL)
924
925 There may be up to 5 word-sized arguments. Floating point
926 arguments can be done, but count as two word arguments.
927 Return value can be integral or real.
928 */
929
930 /* Keep this assembly at the bottom of the source file! */
931
932 __asm__ (
933 ".text\n"
934 " .align 2\n"
935 ".private_extern ___CF_INVOKE_CALLBACK\n"
936 "___CF_INVOKE_CALLBACK:\n"
937 "rlwinm r12,r3,0,0,29\n"
938 "andi. r0,r3,0x2\n"
939 "or r3,r4,r4\n"
940 "or r4,r5,r5\n"
941 "or r5,r6,r6\n"
942 "or r6,r7,r7\n"
943 "or r7,r8,r8\n"
944 "beq- Lcall\n"
945 "lwz r2,0x4(r12)\n"
946 "lwz r12,0x0(r12)\n"
947 "Lcall: mtspr ctr,r12\n"
948 "bctr\n");
949
950 #endif
951
952
953 // void __HALT(void);
954
955 #if defined(__ppc__) || defined(__ppc64__)
956 __asm__ (
957 ".text\n"
958 " .align 2\n"
959 #if defined(__MACH__)
960 ".private_extern ___HALT\n"
961 #else
962 ".globl ___HALT\n"
963 #endif
964 "___HALT:\n"
965 " trap\n"
966 );
967 #endif
968
969 #if defined(__i386__)
970 #if defined(_MSC_VER) || defined(__MWERKS__)
971 __private_extern__ void __HALT()
972 {
973 __asm int 3;
974 }
975 #else
976 __asm__ (
977 ".text\n"
978 " .align 2, 0x90\n"
979 #if defined(__MACH__)
980 ".private_extern ___HALT\n"
981 #else
982 ".globl ___HALT\n"
983 #endif
984 "___HALT:\n"
985 " int3\n"
986 );
987 #endif
988 #endif
989