]> git.saurik.com Git - apple/cf.git/blame - Base.subproj/CFBase.c
CF-368.11.tar.gz
[apple/cf.git] / Base.subproj / CFBase.c
CommitLineData
9ce05555 1/*
d8925383 2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
9ce05555
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
9ce05555
A
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__)
9ce05555 39 #include <malloc/malloc.h>
d8925383 40 extern size_t malloc_good_size(size_t size);
9ce05555 41 #include <mach/mach.h>
d8925383 42 #include <dlfcn.h>
9ce05555
A
43#endif
44#include <stdlib.h>
45#include <string.h>
46
d8925383
A
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
9ce05555
A
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
57struct __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
77CF_INLINE CFAllocatorRetainCallBack __CFAllocatorGetRetainFunction(const CFAllocatorContext *context) {
78 CFAllocatorRetainCallBack retval = NULL;
79 retval = context->retain;
80 return retval;
81}
82
83CF_INLINE CFAllocatorReleaseCallBack __CFAllocatorGetReleaseFunction(const CFAllocatorContext *context) {
84 CFAllocatorReleaseCallBack retval = NULL;
85 retval = context->release;
86 return retval;
87}
88
89CF_INLINE CFAllocatorCopyDescriptionCallBack __CFAllocatorGetCopyDescriptionFunction(const CFAllocatorContext *context) {
90 CFAllocatorCopyDescriptionCallBack retval = NULL;
91 retval = context->copyDescription;
92 return retval;
93}
94
95CF_INLINE CFAllocatorAllocateCallBack __CFAllocatorGetAllocateFunction(const CFAllocatorContext *context) {
96 CFAllocatorAllocateCallBack retval = NULL;
97 retval = context->allocate;
98 return retval;
99}
100
101CF_INLINE CFAllocatorReallocateCallBack __CFAllocatorGetReallocateFunction(const CFAllocatorContext *context) {
102 CFAllocatorReallocateCallBack retval = NULL;
103 retval = context->reallocate;
104 return retval;
105}
106
107CF_INLINE CFAllocatorDeallocateCallBack __CFAllocatorGetDeallocateFunction(const CFAllocatorContext *context) {
108 CFAllocatorDeallocateCallBack retval = NULL;
109 retval = context->deallocate;
110 return retval;
111}
112
113CF_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
123static kern_return_t __CFAllocatorZoneIntrospectNoOp(void) {
124 return 0;
125}
126
127static boolean_t __CFAllocatorZoneIntrospectTrue(void) {
128 return 1;
129}
130
131static 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
142static void *__CFAllocatorCustomMalloc(malloc_zone_t *zone, size_t size) {
143 CFAllocatorRef allocator = (CFAllocatorRef)zone;
144 return CFAllocatorAllocate(allocator, size, 0);
145}
146
147static 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
154static 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
161static void __CFAllocatorCustomFree(malloc_zone_t *zone, void *ptr) {
162 CFAllocatorRef allocator = (CFAllocatorRef)zone;
163 CFAllocatorDeallocate(allocator, ptr);
164}
165
166static 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
171static 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
182static size_t __CFAllocatorCustomGoodSize(malloc_zone_t *zone, size_t size) {
183 CFAllocatorRef allocator = (CFAllocatorRef)zone;
184 return CFAllocatorGetPreferredSizeForSize(allocator, size, 0);
185}
186
187static 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
198static size_t __CFAllocatorNullSize(malloc_zone_t *zone, const void *ptr) {
199 return 0;
200}
201
202static void * __CFAllocatorNullMalloc(malloc_zone_t *zone, size_t size) {
203 return NULL;
204}
205
206static void * __CFAllocatorNullCalloc(malloc_zone_t *zone, size_t num_items, size_t size) {
207 return NULL;
208}
209
210static void * __CFAllocatorNullValloc(malloc_zone_t *zone, size_t size) {
211 return NULL;
212}
213
214static void __CFAllocatorNullFree(malloc_zone_t *zone, void *ptr) {
215}
216
217static void * __CFAllocatorNullRealloc(malloc_zone_t *zone, void *ptr, size_t size) {
218 return NULL;
219}
220
221static void __CFAllocatorNullDestroy(malloc_zone_t *zone) {
222}
223
224static size_t __CFAllocatorNullGoodSize(malloc_zone_t *zone, size_t size) {
225 return size;
226}
227
228static 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
239static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) {
240 return malloc_zone_malloc(info, size);
241}
242
243static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
244 return malloc_zone_realloc(info, ptr, newsize);
245}
246
247static void __CFAllocatorSystemDeallocate(void *ptr, void *info) {
d8925383
A
248#if defined(DEBUG)
249 size_t size = malloc_size(ptr);
250 if (size) memset(ptr, 0xCC, size);
251#endif
9ce05555
A
252 malloc_zone_free(info, ptr);
253}
254
255#endif
256
257#if defined(__WIN32__) || defined(__LINUX__) || defined(__FREEBSD__)
258static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) {
259 return malloc(size);
260}
261
262static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
263 return realloc(ptr, newsize);
264}
265
266static void __CFAllocatorSystemDeallocate(void *ptr, void *info) {
267 free(ptr);
268}
269#endif
270
271static void *__CFAllocatorNullAllocate(CFIndex size, CFOptionFlags hint, void *info) {
272 return NULL;
273}
274
275static void *__CFAllocatorNullReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) {
276 return NULL;
277}
278
279static 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
d8925383
A
302static 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
9ce05555
A
322static 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
342static 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
362const CFAllocatorRef kCFAllocatorDefault = NULL;
363const CFAllocatorRef kCFAllocatorSystemDefault = &__kCFAllocatorSystemDefault;
364const CFAllocatorRef kCFAllocatorMalloc = &__kCFAllocatorMalloc;
d8925383 365const CFAllocatorRef kCFAllocatorMallocZone = &__kCFAllocatorMallocZone;
9ce05555
A
366const CFAllocatorRef kCFAllocatorNull = &__kCFAllocatorNull;
367const CFAllocatorRef kCFAllocatorUseContext = (CFAllocatorRef)0x0227;
368
d8925383
A
369bool kCFUseCollectableAllocator = false;
370
9ce05555
A
371static 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
407static CFTypeID __kCFAllocatorTypeID = _kCFRuntimeNotATypeID;
408
409static 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__)
d8925383
A
427 __kCFAllocatorSystemDefault._context.info = (CF_USING_COLLECTABLE_MEMORY ? __CFCollectableZone : malloc_default_zone());
428 memset(malloc_default_zone(), 0, 8);
9ce05555
A
429#endif
430 __kCFAllocatorSystemDefault._allocator = kCFAllocatorSystemDefault;
9ce05555
A
431
432 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMalloc, __kCFAllocatorTypeID);
433 __kCFAllocatorMalloc._base._isa = __CFISAForTypeID(__kCFAllocatorTypeID);
434 __kCFAllocatorMalloc._allocator = kCFAllocatorSystemDefault;
435
d8925383
A
436 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMallocZone, __kCFAllocatorTypeID);
437 __kCFAllocatorMallocZone._base._isa = __CFISAForTypeID(__kCFAllocatorTypeID);
438 __kCFAllocatorMallocZone._allocator = kCFAllocatorSystemDefault;
439 __kCFAllocatorMallocZone._context.info = malloc_default_zone();
440
9ce05555
A
441 _CFRuntimeSetInstanceTypeID(&__kCFAllocatorNull, __kCFAllocatorTypeID);
442 __kCFAllocatorNull._base._isa = __CFISAForTypeID(__kCFAllocatorTypeID);
443 __kCFAllocatorNull._allocator = kCFAllocatorSystemDefault;
444
445}
446
447CFTypeID CFAllocatorGetTypeID(void) {
448 return __kCFAllocatorTypeID;
449}
450
451CFAllocatorRef CFAllocatorGetDefault(void) {
452 CFAllocatorRef allocator = __CFGetThreadSpecificData_inline()->_allocator;
453 if (NULL == allocator) {
454 allocator = kCFAllocatorSystemDefault;
455 }
456 return allocator;
457}
458
459void 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
d8925383
A
481static CFAllocatorRef __CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) {
482 struct __CFAllocator *memory = NULL;
9ce05555
A
483 CFAllocatorRetainCallBack retainFunc;
484 CFAllocatorAllocateCallBack allocateFunc;
485 void *retainedInfo;
9ce05555
A
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) {
d8925383
A
502 memory = NULL;
503 if (allocateFunc) {
504 memory = (void *)INVOKE_CALLBACK3(allocateFunc, sizeof(struct __CFAllocator), 0, retainedInfo);
505 }
9ce05555
A
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
d8925383
A
555CFAllocatorRef 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
564CFAllocatorRef _CFAllocatorCreateGC(CFAllocatorRef allocator, CFAllocatorContext *context) {
565 return __CFAllocatorCreate(allocator, context);
566}
567
9ce05555
A
568void *CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) {
569 CFAllocatorAllocateCallBack allocateFunc;
d8925383 570 void *newptr = NULL;
9ce05555
A
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
d8925383
A
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 }
9ce05555
A
594 return newptr;
595}
596
597void *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
d8925383 616 newptr = NULL;
9ce05555 617 allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context);
d8925383
A
618 if (allocateFunc) {
619 newptr = (void *)INVOKE_CALLBACK3(allocateFunc, newsize, hint, allocator->_context.info);
620 }
9ce05555
A
621 return newptr;
622 }
623 if (NULL != ptr && 0 == newsize) {
624#if defined(__MACH__)
625 if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t *
d8925383
A
626#if defined(DEBUG)
627 size_t size = malloc_size(ptr);
628 if (size) memset(ptr, 0xCC, size);
629#endif
9ce05555
A
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
652void 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 *
d8925383
A
664#if defined(DEBUG)
665 size_t size = malloc_size(ptr);
666 if (size) memset(ptr, 0xCC, size);
667#endif
9ce05555
A
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
677CFIndex 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
701void 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 context->retain = (void *)((uintptr_t)context->retain & ~0x3);
726 context->release = (void *)((uintptr_t)context->release & ~0x3);
727 context->copyDescription = (void *)((uintptr_t)context->copyDescription & ~0x3);
728 context->allocate = (void *)((uintptr_t)context->allocate & ~0x3);
729 context->reallocate = (void *)((uintptr_t)context->reallocate & ~0x3);
730 context->deallocate = (void *)((uintptr_t)context->deallocate & ~0x3);
731 context->preferredSize = (void *)((uintptr_t)context->preferredSize & ~0x3);
732}
733
d8925383
A
734void *_CFAllocatorAllocateGC(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint)
735{
736 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator))
737 return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, size, (auto_memory_type_t)hint, false, false);
738 else
739 return CFAllocatorAllocate(allocator, size, hint);
740}
741
742void *_CFAllocatorReallocateGC(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint)
743{
744 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
745 if (ptr && (newsize == 0)) {
746 return NULL; // equivalent to _CFAllocatorDeallocateGC.
747 }
748 if (ptr == NULL) {
749 return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, newsize, (auto_memory_type_t)hint, false, false); // eq. to _CFAllocator
750 }
751 }
752 // otherwise, auto_realloc() now preserves layout type and refCount.
753 return CFAllocatorReallocate(allocator, ptr, newsize, hint);
754}
755
756void _CFAllocatorDeallocateGC(CFAllocatorRef allocator, void *ptr)
757{
758 // when running GC, don't deallocate.
759 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) CFAllocatorDeallocate(allocator, ptr);
760}
761
9ce05555
A
762// -------- -------- -------- -------- -------- -------- -------- --------
763
764#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
765__private_extern__ pthread_key_t __CFTSDKey = (pthread_key_t)NULL;
766#endif
767#if defined(__WIN32__)
768__private_extern__ DWORD __CFTSDKey = 0xFFFFFFFF;
769#endif
770
771// Called for each thread as it exits
d8925383
A
772__private_extern__ void __CFFinalizeThreadData(void *arg) {
773#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
9ce05555 774 __CFThreadSpecificData *tsd = (__CFThreadSpecificData *)arg;
d8925383
A
775#elif defined(__WIN32)
776 __CFThreadSpecificData *tsd = TlsGetValue(__CFTSDKey);
777 TlsSetValue(__CFTSDKey, NULL);
778#endif
9ce05555
A
779 if (NULL == tsd) return;
780 if (tsd->_allocator) CFRelease(tsd->_allocator);
781 if (tsd->_runLoop) CFRelease(tsd->_runLoop);
782 CFAllocatorDeallocate(kCFAllocatorSystemDefault, tsd);
783}
784
785__private_extern__ __CFThreadSpecificData *__CFGetThreadSpecificData(void) {
786#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
787 __CFThreadSpecificData *data;
788 data = pthread_getspecific(__CFTSDKey);
789 if (data) {
790 return data;
791 }
792 data = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFThreadSpecificData), 0);
793 if (__CFOASafe) __CFSetLastAllocationEventName(data, "CFUtilities (thread-data)");
794 memset(data, 0, sizeof(__CFThreadSpecificData));
795 pthread_setspecific(__CFTSDKey, data);
796 return data;
797#elif defined(__WIN32__)
798 __CFThreadSpecificData *data;
799 data = TlsGetValue(__CFTSDKey);
800 if (data) {
801 return data;
802 }
803 data = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFThreadSpecificData), 0);
804 if (__CFOASafe) __CFSetLastAllocationEventName(data, "CFUtilities (thread-data)");
805 memset(data, 0, sizeof(__CFThreadSpecificData));
806 TlsSetValue(__CFTSDKey, data);
807 return data;
808#endif
809}
810
811__private_extern__ void __CFBaseInitialize(void) {
812#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
813 pthread_key_create(&__CFTSDKey, __CFFinalizeThreadData);
814#endif
815#if defined(__WIN32__)
816 __CFTSDKey = TlsAlloc();
817#endif
d8925383
A
818 //kCFUseCollectableAllocator = objc_collecting_enabled();
819}
820
821#if defined(__WIN32__)
822__private_extern__ void __CFBaseCleanup(void) {
823 TlsFree(__CFTSDKey);
9ce05555 824}
d8925383 825#endif
9ce05555
A
826
827
828CFRange __CFRangeMake(CFIndex loc, CFIndex len) {
829 CFRange range;
830 range.location = loc;
831 range.length = len;
832 return range;
833}
834
835__private_extern__ const void *__CFTypeCollectionRetain(CFAllocatorRef allocator, const void *ptr) {
836 return (const void *)CFRetain(ptr);
837}
838
839__private_extern__ void __CFTypeCollectionRelease(CFAllocatorRef allocator, const void *ptr) {
840 CFRelease(ptr);
841}
842
843
844struct __CFNull {
845 CFRuntimeBase _base;
846};
847
848static struct __CFNull __kCFNull = {
d8925383 849 INIT_CFRUNTIME_BASE(NULL, 0, 0x0080)
9ce05555
A
850};
851const CFNullRef kCFNull = &__kCFNull;
852
853static CFStringRef __CFNullCopyDescription(CFTypeRef cf) {
854 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<CFNull %p [%p]>"), cf, CFGetAllocator(cf));
855}
856
857static CFStringRef __CFNullCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
858 return CFRetain(CFSTR("null"));
859}
860
861static void __CFNullDeallocate(CFTypeRef cf) {
862 CFAssert(false, __kCFLogAssertion, "Deallocated CFNull!");
863}
864
865static CFTypeID __kCFNullTypeID = _kCFRuntimeNotATypeID;
866
867static const CFRuntimeClass __CFNullClass = {
868 0,
869 "CFNull",
870 NULL, // init
871 NULL, // copy
872 __CFNullDeallocate,
873 NULL,
874 NULL,
875 __CFNullCopyFormattingDescription,
876 __CFNullCopyDescription
877};
878
879__private_extern__ void __CFNullInitialize(void) {
880 __kCFNullTypeID = _CFRuntimeRegisterClass(&__CFNullClass);
881 _CFRuntimeSetInstanceTypeID(&__kCFNull, __kCFNullTypeID);
882 __kCFNull._base._isa = __CFISAForTypeID(__kCFNullTypeID);
883}
884
885CFTypeID CFNullGetTypeID(void) {
886 return __kCFNullTypeID;
887}
888
889
890static int hasCFM = 0;
891
d8925383 892void _CFRuntimeSetCFMPresent(void *addr) {
9ce05555
A
893 hasCFM = 1;
894}
895
896#if defined(__MACH__) && defined(__ppc__)
897
898/* See comments below */
899__private_extern__ void __CF_FAULT_CALLBACK(void **ptr) {
900 uintptr_t p = (uintptr_t)*ptr;
901 if ((0 == p) || (p & 0x1)) return;
d8925383
A
902// warning: revisit this address check in Chablis, and for 64-bit
903 if (0 == hasCFM || (0x90000000 <= p && p < 0xA0000000)) {
9ce05555
A
904 *ptr = (void *)(p | 0x1);
905 } else {
d8925383
A
906 Dl_info info;
907 int __known = dladdr(p, &info);
9ce05555
A
908 *ptr = (void *)(p | (__known ? 0x1 : 0x3));
909 }
910}
911
912/*
913Jump to callback function. r2 is not saved and restored
914in the jump-to-CFM case, since we assume that dyld code
915never uses that register and that CF is dyld.
916
917There are three states for (ptr & 0x3):
918 0b00: check not yet done (or not going to be done, and is a dyld func ptr)
919 0b01: check done, dyld function pointer
920 0b11: check done, CFM tvector pointer
921(but a NULL callback just stays NULL)
922
923There may be up to 5 word-sized arguments. Floating point
924arguments can be done, but count as two word arguments.
925Return value can be integral or real.
926*/
927
928/* Keep this assembly at the bottom of the source file! */
929
930__asm__ (
931".text\n"
932" .align 2\n"
933".private_extern ___CF_INVOKE_CALLBACK\n"
934"___CF_INVOKE_CALLBACK:\n"
935 "rlwinm r12,r3,0,0,29\n"
936 "andi. r0,r3,0x2\n"
937 "or r3,r4,r4\n"
938 "or r4,r5,r5\n"
939 "or r5,r6,r6\n"
940 "or r6,r7,r7\n"
941 "or r7,r8,r8\n"
942 "beq- Lcall\n"
943 "lwz r2,0x4(r12)\n"
944 "lwz r12,0x0(r12)\n"
945"Lcall: mtspr ctr,r12\n"
946 "bctr\n");
947
948#endif
949
950
951// void __HALT(void);
952
d8925383 953#if defined(__ppc__) || defined(__ppc64__)
9ce05555
A
954__asm__ (
955".text\n"
956" .align 2\n"
957#if defined(__MACH__)
958".private_extern ___HALT\n"
959#else
960".globl ___HALT\n"
961#endif
962"___HALT:\n"
963" trap\n"
964);
965#endif
966
967#if defined(__i386__)
d8925383
A
968#if defined(_MSC_VER) || defined(__MWERKS__)
969__private_extern__ void __HALT()
970{
971 __asm int 3;
972}
973#else
9ce05555
A
974__asm__ (
975".text\n"
976" .align 2, 0x90\n"
977#if defined(__MACH__)
978".private_extern ___HALT\n"
979#else
980".globl ___HALT\n"
981#endif
982"___HALT:\n"
983" int3\n"
984);
985#endif
d8925383 986#endif
9ce05555 987