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