]>
Commit | Line | Data |
---|---|---|
9ce05555 | 1 | /* |
bd5b749c | 2 | * Copyright (c) 2008 Apple 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" | |
bd5b749c A |
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> | |
9ce05555 A |
35 | #include <stdlib.h> |
36 | #include <string.h> | |
37 | ||
d8925383 A |
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 | |
9ce05555 A |
41 | |
42 | // -------- -------- -------- -------- -------- -------- -------- -------- | |
43 | ||
9ce05555 A |
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 | |
9ce05555 A |
46 | struct __CFAllocator { |
47 | CFRuntimeBase _base; | |
9ce05555 A |
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; | |
9ce05555 A |
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 | ||
bd5b749c | 106 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 A |
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); | |
bd5b749c | 144 | newptr = (void *)round_page((uintptr_t)newptr); |
9ce05555 A |
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) { | |
d8925383 A |
235 | #if defined(DEBUG) |
236 | size_t size = malloc_size(ptr); | |
237 | if (size) memset(ptr, 0xCC, size); | |
238 | #endif | |
9ce05555 A |
239 | malloc_zone_free(info, ptr); |
240 | } | |
241 | ||
242 | #endif | |
243 | ||
bd5b749c | 244 | #if defined(__WIN32__) || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD |
9ce05555 A |
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 | ||
bd5b749c A |
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 | ||
9ce05555 | 282 | static struct __CFAllocator __kCFAllocatorMalloc = { |
bd5b749c A |
283 | INIT_CFRUNTIME_BASE(), |
284 | #if DEPLOYMENT_TARGET_MACOSX | |
9ce05555 A |
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. | |
bd5b749c A |
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 | |
9ce05555 A |
307 | }; |
308 | ||
d8925383 | 309 | static struct __CFAllocator __kCFAllocatorMallocZone = { |
bd5b749c A |
310 | INIT_CFRUNTIME_BASE(), |
311 | #if DEPLOYMENT_TARGET_MACOSX | |
d8925383 A |
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 | ||
9ce05555 | 329 | static struct __CFAllocator __kCFAllocatorSystemDefault = { |
bd5b749c A |
330 | INIT_CFRUNTIME_BASE(), |
331 | #if DEPLOYMENT_TARGET_MACOSX | |
9ce05555 A |
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 = { | |
bd5b749c A |
350 | INIT_CFRUNTIME_BASE(), |
351 | #if DEPLOYMENT_TARGET_MACOSX | |
9ce05555 A |
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; | |
d8925383 | 372 | const CFAllocatorRef kCFAllocatorMallocZone = &__kCFAllocatorMallocZone; |
9ce05555 | 373 | const CFAllocatorRef kCFAllocatorNull = &__kCFAllocatorNull; |
bd5b749c | 374 | const CFAllocatorRef kCFAllocatorUseContext = (CFAllocatorRef)0x0257; |
d8925383 | 375 | |
9ce05555 | 376 | static CFStringRef __CFAllocatorCopyDescription(CFTypeRef cf) { |
bd5b749c | 377 | CFAllocatorRef self = (CFAllocatorRef)cf; |
9ce05555 | 378 | CFAllocatorRef allocator = (kCFAllocatorUseContext == self->_allocator) ? self : self->_allocator; |
bd5b749c | 379 | return CFStringCreateWithFormat(allocator, NULL, CFSTR("<CFAllocator %p [%p]>{info = %p}"), cf, allocator, self->_context.info); |
9ce05555 A |
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) { | |
bd5b749c | 385 | CFAllocatorRef allocator = (CFAllocatorRef)cf; |
9ce05555 A |
386 | return (kCFAllocatorUseContext == allocator->_allocator) ? allocator : allocator->_allocator; |
387 | } | |
388 | ||
389 | __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf) { | |
bd5b749c | 390 | CFAllocatorRef self = (CFAllocatorRef)cf; |
9ce05555 A |
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 | } | |
bd5b749c | 408 | _CFAllocatorDeallocateGC(allocator, (void *)self); |
9ce05555 A |
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); | |
bd5b749c A |
430 | __kCFAllocatorSystemDefault._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); |
431 | #if DEPLOYMENT_TARGET_MACOSX | |
d8925383 | 432 | __kCFAllocatorSystemDefault._context.info = (CF_USING_COLLECTABLE_MEMORY ? __CFCollectableZone : malloc_default_zone()); |
bd5b749c | 433 | memset(malloc_default_zone(), 0, 2 * sizeof(void *)); |
9ce05555 A |
434 | #endif |
435 | __kCFAllocatorSystemDefault._allocator = kCFAllocatorSystemDefault; | |
9ce05555 A |
436 | |
437 | _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMalloc, __kCFAllocatorTypeID); | |
bd5b749c | 438 | __kCFAllocatorMalloc._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); |
9ce05555 A |
439 | __kCFAllocatorMalloc._allocator = kCFAllocatorSystemDefault; |
440 | ||
bd5b749c A |
441 | #if DEPLOYMENT_TARGET_MACOSX |
442 | _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMallocZone, __kCFAllocatorTypeID); | |
443 | __kCFAllocatorMallocZone._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); | |
d8925383 A |
444 | __kCFAllocatorMallocZone._allocator = kCFAllocatorSystemDefault; |
445 | __kCFAllocatorMallocZone._context.info = malloc_default_zone(); | |
bd5b749c | 446 | #endif //__MACH__ |
d8925383 | 447 | |
9ce05555 | 448 | _CFRuntimeSetInstanceTypeID(&__kCFAllocatorNull, __kCFAllocatorTypeID); |
bd5b749c | 449 | __kCFAllocatorNull._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); |
9ce05555 A |
450 | __kCFAllocatorNull._allocator = kCFAllocatorSystemDefault; |
451 | ||
452 | } | |
453 | ||
454 | CFTypeID CFAllocatorGetTypeID(void) { | |
455 | return __kCFAllocatorTypeID; | |
456 | } | |
457 | ||
458 | CFAllocatorRef CFAllocatorGetDefault(void) { | |
bd5b749c | 459 | CFAllocatorRef allocator = (CFAllocatorRef)__CFGetThreadSpecificData_inline()->_allocator; |
9ce05555 A |
460 | if (NULL == allocator) { |
461 | allocator = kCFAllocatorSystemDefault; | |
462 | } | |
463 | return allocator; | |
464 | } | |
465 | ||
466 | void CFAllocatorSetDefault(CFAllocatorRef allocator) { | |
bd5b749c | 467 | CFAllocatorRef current = (CFAllocatorRef)__CFGetThreadSpecificData_inline()->_allocator; |
9ce05555 A |
468 | #if defined(DEBUG) |
469 | if (NULL != allocator) { | |
470 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
471 | } | |
472 | #endif | |
bd5b749c A |
473 | #if DEPLOYMENT_TARGET_MACOSX |
474 | if (allocator && allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
9ce05555 A |
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 | ||
d8925383 A |
488 | static CFAllocatorRef __CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) { |
489 | struct __CFAllocator *memory = NULL; | |
9ce05555 A |
490 | CFAllocatorRetainCallBack retainFunc; |
491 | CFAllocatorAllocateCallBack allocateFunc; | |
492 | void *retainedInfo; | |
bd5b749c A |
493 | #if DEPLOYMENT_TARGET_MACOSX |
494 | if (allocator && kCFAllocatorUseContext != allocator && allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
9ce05555 A |
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) { | |
d8925383 A |
509 | memory = NULL; |
510 | if (allocateFunc) { | |
bd5b749c | 511 | memory = (struct __CFAllocator *)INVOKE_CALLBACK3(allocateFunc, sizeof(struct __CFAllocator), 0, retainedInfo); |
d8925383 | 512 | } |
9ce05555 A |
513 | if (NULL == memory) { |
514 | return NULL; | |
515 | } | |
516 | } else { | |
517 | allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; | |
bd5b749c | 518 | memory = (struct __CFAllocator *)CFAllocatorAllocate(allocator, sizeof(struct __CFAllocator), __kCFAllocatorGCObjectMemory); |
9ce05555 A |
519 | if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFAllocator"); |
520 | if (NULL == memory) { | |
521 | return NULL; | |
522 | } | |
523 | } | |
bd5b749c A |
524 | memory->_base._cfisa = 0; |
525 | #if __LP64__ | |
9ce05555 | 526 | memory->_base._rc = 1; |
bd5b749c A |
527 | #else |
528 | memory->_base._cfinfo[CF_RC_BITS] = 1; | |
529 | #endif | |
530 | memory->_base._cfinfo[CF_INFO_BITS] = 0; | |
9ce05555 | 531 | _CFRuntimeSetInstanceTypeID(memory, __kCFAllocatorTypeID); |
bd5b749c A |
532 | memory->_base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); |
533 | #if DEPLOYMENT_TARGET_MACOSX | |
9ce05555 A |
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 | ||
d8925383 A |
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 | ||
9ce05555 A |
579 | void *CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) { |
580 | CFAllocatorAllocateCallBack allocateFunc; | |
d8925383 | 581 | void *newptr = NULL; |
9ce05555 | 582 | allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; |
bd5b749c A |
583 | #if (DEPLOYMENT_TARGET_MACOSX) && defined(DEBUG) |
584 | if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { | |
9ce05555 A |
585 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); |
586 | } | |
587 | #else | |
588 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
589 | #endif | |
590 | if (0 == size) return NULL; | |
bd5b749c A |
591 | #if DEPLOYMENT_TARGET_MACOSX |
592 | if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
9ce05555 A |
593 | return malloc_zone_malloc((malloc_zone_t *)allocator, size); |
594 | } | |
595 | #endif | |
d8925383 | 596 | if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { |
bd5b749c | 597 | newptr = auto_zone_allocate_object((auto_zone_t*)allocator->_context.info, size, CF_GET_GC_MEMORY_TYPE(hint), true, false); |
d8925383 A |
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 | } | |
9ce05555 A |
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; | |
bd5b749c A |
614 | #if (DEPLOYMENT_TARGET_MACOSX) && defined(DEBUG) |
615 | if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { | |
9ce05555 A |
616 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); |
617 | } | |
618 | #else | |
619 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
620 | #endif | |
621 | if (NULL == ptr && 0 < newsize) { | |
bd5b749c A |
622 | #if DEPLOYMENT_TARGET_MACOSX |
623 | if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
9ce05555 A |
624 | return malloc_zone_malloc((malloc_zone_t *)allocator, newsize); |
625 | } | |
626 | #endif | |
d8925383 | 627 | newptr = NULL; |
9ce05555 | 628 | allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context); |
d8925383 A |
629 | if (allocateFunc) { |
630 | newptr = (void *)INVOKE_CALLBACK3(allocateFunc, newsize, hint, allocator->_context.info); | |
631 | } | |
9ce05555 A |
632 | return newptr; |
633 | } | |
634 | if (NULL != ptr && 0 == newsize) { | |
bd5b749c A |
635 | #if DEPLOYMENT_TARGET_MACOSX |
636 | if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
d8925383 A |
637 | #if defined(DEBUG) |
638 | size_t size = malloc_size(ptr); | |
639 | if (size) memset(ptr, 0xCC, size); | |
640 | #endif | |
9ce05555 A |
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; | |
bd5b749c A |
652 | #if DEPLOYMENT_TARGET_MACOSX |
653 | if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
9ce05555 A |
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; | |
bd5b749c A |
666 | #if (DEPLOYMENT_TARGET_MACOSX) && defined(DEBUG) |
667 | if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { | |
9ce05555 A |
668 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); |
669 | } | |
670 | #else | |
671 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
672 | #endif | |
bd5b749c A |
673 | #if DEPLOYMENT_TARGET_MACOSX |
674 | if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
d8925383 A |
675 | #if defined(DEBUG) |
676 | size_t size = malloc_size(ptr); | |
677 | if (size) memset(ptr, 0xCC, size); | |
678 | #endif | |
9ce05555 A |
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; | |
bd5b749c A |
692 | #if (DEPLOYMENT_TARGET_MACOSX) && defined(DEBUG) |
693 | if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { | |
9ce05555 A |
694 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); |
695 | } | |
696 | #else | |
697 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
698 | #endif | |
bd5b749c A |
699 | #if DEPLOYMENT_TARGET_MACOSX |
700 | if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
9ce05555 A |
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; | |
bd5b749c A |
714 | #if (DEPLOYMENT_TARGET_MACOSX) && defined(DEBUG) |
715 | if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { | |
9ce05555 A |
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__); | |
bd5b749c A |
722 | #if DEPLOYMENT_TARGET_MACOSX |
723 | if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
9ce05555 A |
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); | |
bd5b749c | 736 | #if (DEPLOYMENT_TARGET_MACOSX) && defined(__ppc__) |
9ce05555 A |
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); | |
4c91a73d | 744 | #endif |
9ce05555 A |
745 | } |
746 | ||
d8925383 A |
747 | void *_CFAllocatorAllocateGC(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) |
748 | { | |
749 | if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) | |
bd5b749c | 750 | return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, size, CF_GET_GC_MEMORY_TYPE(hint), false, false); |
d8925383 A |
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) { | |
bd5b749c | 762 | return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, newsize, CF_GET_GC_MEMORY_TYPE(hint), false, false); // eq. to _CFAllocator |
d8925383 A |
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 | ||
9ce05555 A |
775 | // -------- -------- -------- -------- -------- -------- -------- -------- |
776 | ||
bd5b749c | 777 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD |
9ce05555 A |
778 | __private_extern__ pthread_key_t __CFTSDKey = (pthread_key_t)NULL; |
779 | #endif | |
bd5b749c | 780 | #if 0 |
9ce05555 A |
781 | __private_extern__ DWORD __CFTSDKey = 0xFFFFFFFF; |
782 | #endif | |
783 | ||
bd5b749c A |
784 | extern void _CFRunLoop1(void); |
785 | ||
9ce05555 | 786 | // Called for each thread as it exits |
d8925383 | 787 | __private_extern__ void __CFFinalizeThreadData(void *arg) { |
bd5b749c | 788 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD |
9ce05555 | 789 | __CFThreadSpecificData *tsd = (__CFThreadSpecificData *)arg; |
bd5b749c A |
790 | #elif defined(__WIN32__) |
791 | __CFThreadSpecificData *tsd = (__CFThreadSpecificData*)TlsGetValue(__CFTSDKey); | |
d8925383 A |
792 | TlsSetValue(__CFTSDKey, NULL); |
793 | #endif | |
9ce05555 A |
794 | if (NULL == tsd) return; |
795 | if (tsd->_allocator) CFRelease(tsd->_allocator); | |
bd5b749c A |
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 | ||
9ce05555 A |
805 | CFAllocatorDeallocate(kCFAllocatorSystemDefault, tsd); |
806 | } | |
807 | ||
808 | __private_extern__ __CFThreadSpecificData *__CFGetThreadSpecificData(void) { | |
bd5b749c | 809 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD |
9ce05555 A |
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; | |
bd5b749c | 822 | data = (__CFThreadSpecificData *)TlsGetValue(__CFTSDKey); |
9ce05555 A |
823 | if (data) { |
824 | return data; | |
825 | } | |
bd5b749c | 826 | data = (__CFThreadSpecificData *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFThreadSpecificData), 0); |
9ce05555 A |
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) { | |
bd5b749c | 835 | #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD |
9ce05555 A |
836 | pthread_key_create(&__CFTSDKey, __CFFinalizeThreadData); |
837 | #endif | |
bd5b749c | 838 | #if 0 || 0 |
9ce05555 A |
839 | __CFTSDKey = TlsAlloc(); |
840 | #endif | |
d8925383 A |
841 | } |
842 | ||
bd5b749c | 843 | #if 0 || 0 |
d8925383 A |
844 | __private_extern__ void __CFBaseCleanup(void) { |
845 | TlsFree(__CFTSDKey); | |
9ce05555 | 846 | } |
d8925383 | 847 | #endif |
9ce05555 A |
848 | |
849 | ||
bd5b749c A |
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 | ||
9ce05555 A |
861 | CFRange __CFRangeMake(CFIndex loc, CFIndex len) { |
862 | CFRange range; | |
863 | range.location = loc; | |
864 | range.length = len; | |
865 | return range; | |
866 | } | |
867 | ||
9ce05555 A |
868 | |
869 | struct __CFNull { | |
870 | CFRuntimeBase _base; | |
871 | }; | |
872 | ||
873 | static struct __CFNull __kCFNull = { | |
bd5b749c | 874 | INIT_CFRUNTIME_BASE() |
9ce05555 A |
875 | }; |
876 | const CFNullRef kCFNull = &__kCFNull; | |
877 | ||
878 | static CFStringRef __CFNullCopyDescription(CFTypeRef cf) { | |
bd5b749c | 879 | return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFNull %p [%p]>"), cf, CFGetAllocator(cf)); |
9ce05555 A |
880 | } |
881 | ||
882 | static CFStringRef __CFNullCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { | |
bd5b749c | 883 | return (CFStringRef)CFRetain(CFSTR("null")); |
9ce05555 A |
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); | |
bd5b749c | 907 | __kCFNull._base._cfisa = __CFISAForTypeID(__kCFNullTypeID); |
9ce05555 A |
908 | } |
909 | ||
910 | CFTypeID CFNullGetTypeID(void) { | |
911 | return __kCFNullTypeID; | |
912 | } | |
913 | ||
bd5b749c A |
914 | void CFCollection_non_gc_storage_error(void) { } |
915 | ||
9ce05555 A |
916 | |
917 | static int hasCFM = 0; | |
918 | ||
d8925383 | 919 | void _CFRuntimeSetCFMPresent(void *addr) { |
9ce05555 A |
920 | hasCFM = 1; |
921 | } | |
922 | ||
bd5b749c | 923 | #if (DEPLOYMENT_TARGET_MACOSX) && defined(__ppc__) |
9ce05555 A |
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; | |
d8925383 | 929 | if (0 == hasCFM || (0x90000000 <= p && p < 0xA0000000)) { |
9ce05555 A |
930 | *ptr = (void *)(p | 0x1); |
931 | } else { | |
bd5b749c A |
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)); | |
9ce05555 A |
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 | ||
d8925383 | 990 | #if defined(__ppc__) || defined(__ppc64__) |
9ce05555 A |
991 | __asm__ ( |
992 | ".text\n" | |
993 | " .align 2\n" | |
bd5b749c | 994 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 A |
995 | ".private_extern ___HALT\n" |
996 | #else | |
997 | ".globl ___HALT\n" | |
998 | #endif | |
999 | "___HALT:\n" | |
1000 | " trap\n" | |
1001 | ); | |
1002 | #endif | |
1003 | ||
bd5b749c A |
1004 | #if defined(__i386__) || defined(__x86_64__) |
1005 | #if defined(_MSC_VER) | |
1006 | void __HALT() { | |
d8925383 A |
1007 | __asm int 3; |
1008 | } | |
1009 | #else | |
9ce05555 A |
1010 | __asm__ ( |
1011 | ".text\n" | |
1012 | " .align 2, 0x90\n" | |
bd5b749c | 1013 | #if DEPLOYMENT_TARGET_MACOSX |
9ce05555 A |
1014 | ".private_extern ___HALT\n" |
1015 | #else | |
1016 | ".globl ___HALT\n" | |
1017 | #endif | |
1018 | "___HALT:\n" | |
1019 | " int3\n" | |
1020 | ); | |
1021 | #endif | |
d8925383 | 1022 | #endif |
9ce05555 | 1023 | |
bd5b749c | 1024 |