]>
Commit | Line | Data |
---|---|---|
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 | |
57 | struct __CFAllocator { | |
58 | CFRuntimeBase _base; | |
59 | #if defined(__MACH__) | |
60 | size_t (*size)(struct _malloc_zone_t *zone, const void *ptr); /* returns the size of a block or 0 if not in this zone; must be fast, especially for negative answers */ | |
61 | void *(*malloc)(struct _malloc_zone_t *zone, size_t size); | |
62 | void *(*calloc)(struct _malloc_zone_t *zone, size_t num_items, size_t size); /* same as malloc, but block returned is set to zero */ | |
63 | void *(*valloc)(struct _malloc_zone_t *zone, size_t size); /* same as malloc, but block returned is set to zero and is guaranteed to be page aligned */ | |
64 | void (*free)(struct _malloc_zone_t *zone, void *ptr); | |
65 | void *(*realloc)(struct _malloc_zone_t *zone, void *ptr, size_t size); | |
66 | void (*destroy)(struct _malloc_zone_t *zone); /* zone is destroyed and all memory reclaimed */ | |
67 | const char *zone_name; | |
68 | unsigned (*batch_malloc)(struct _malloc_zone_t *zone, size_t size, void **results, unsigned num_requested); /* given a size, returns pointers capable of holding that size; returns the number of pointers allocated (maybe 0 or less than num_requested) */ | |
69 | void (*batch_free)(struct _malloc_zone_t *zone, void **to_be_freed, unsigned num_to_be_freed); /* frees all the pointers in to_be_freed; note that to_be_freed may be overwritten during the process */ | |
70 | struct malloc_introspection_t *introspect; | |
71 | void *reserved5; | |
72 | #endif | |
73 | CFAllocatorRef _allocator; | |
74 | CFAllocatorContext _context; | |
75 | }; | |
76 | ||
77 | CF_INLINE CFAllocatorRetainCallBack __CFAllocatorGetRetainFunction(const CFAllocatorContext *context) { | |
78 | CFAllocatorRetainCallBack retval = NULL; | |
79 | retval = context->retain; | |
80 | return retval; | |
81 | } | |
82 | ||
83 | CF_INLINE CFAllocatorReleaseCallBack __CFAllocatorGetReleaseFunction(const CFAllocatorContext *context) { | |
84 | CFAllocatorReleaseCallBack retval = NULL; | |
85 | retval = context->release; | |
86 | return retval; | |
87 | } | |
88 | ||
89 | CF_INLINE CFAllocatorCopyDescriptionCallBack __CFAllocatorGetCopyDescriptionFunction(const CFAllocatorContext *context) { | |
90 | CFAllocatorCopyDescriptionCallBack retval = NULL; | |
91 | retval = context->copyDescription; | |
92 | return retval; | |
93 | } | |
94 | ||
95 | CF_INLINE CFAllocatorAllocateCallBack __CFAllocatorGetAllocateFunction(const CFAllocatorContext *context) { | |
96 | CFAllocatorAllocateCallBack retval = NULL; | |
97 | retval = context->allocate; | |
98 | return retval; | |
99 | } | |
100 | ||
101 | CF_INLINE CFAllocatorReallocateCallBack __CFAllocatorGetReallocateFunction(const CFAllocatorContext *context) { | |
102 | CFAllocatorReallocateCallBack retval = NULL; | |
103 | retval = context->reallocate; | |
104 | return retval; | |
105 | } | |
106 | ||
107 | CF_INLINE CFAllocatorDeallocateCallBack __CFAllocatorGetDeallocateFunction(const CFAllocatorContext *context) { | |
108 | CFAllocatorDeallocateCallBack retval = NULL; | |
109 | retval = context->deallocate; | |
110 | return retval; | |
111 | } | |
112 | ||
113 | CF_INLINE CFAllocatorPreferredSizeCallBack __CFAllocatorGetPreferredSizeFunction(const CFAllocatorContext *context) { | |
114 | CFAllocatorPreferredSizeCallBack retval = NULL; | |
115 | retval = context->preferredSize; | |
116 | return retval; | |
117 | } | |
118 | ||
119 | #if defined(__MACH__) | |
120 | ||
121 | __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf); | |
122 | ||
123 | static kern_return_t __CFAllocatorZoneIntrospectNoOp(void) { | |
124 | return 0; | |
125 | } | |
126 | ||
127 | static boolean_t __CFAllocatorZoneIntrospectTrue(void) { | |
128 | return 1; | |
129 | } | |
130 | ||
131 | static size_t __CFAllocatorCustomSize(malloc_zone_t *zone, const void *ptr) { | |
132 | return 0; | |
133 | ||
134 | // The only way to implement this with a version 0 allocator would be | |
135 | // for CFAllocator to keep track of all blocks allocated itself, which | |
136 | // could be done, but would be bad for performance, so we don't do it. | |
137 | // size_t (*size)(struct _malloc_zone_t *zone, const void *ptr); | |
138 | /* returns the size of a block or 0 if not in this zone; | |
139 | * must be fast, especially for negative answers */ | |
140 | } | |
141 | ||
142 | static void *__CFAllocatorCustomMalloc(malloc_zone_t *zone, size_t size) { | |
143 | CFAllocatorRef allocator = (CFAllocatorRef)zone; | |
144 | return CFAllocatorAllocate(allocator, size, 0); | |
145 | } | |
146 | ||
147 | static void *__CFAllocatorCustomCalloc(malloc_zone_t *zone, size_t num_items, size_t size) { | |
148 | CFAllocatorRef allocator = (CFAllocatorRef)zone; | |
149 | void *newptr = CFAllocatorAllocate(allocator, size, 0); | |
150 | if (newptr) memset(newptr, 0, size); | |
151 | return newptr; | |
152 | } | |
153 | ||
154 | static void *__CFAllocatorCustomValloc(malloc_zone_t *zone, size_t size) { | |
155 | CFAllocatorRef allocator = (CFAllocatorRef)zone; | |
156 | void *newptr = CFAllocatorAllocate(allocator, size + vm_page_size, 0); | |
157 | newptr = (void *)round_page((unsigned)newptr); | |
158 | return newptr; | |
159 | } | |
160 | ||
161 | static void __CFAllocatorCustomFree(malloc_zone_t *zone, void *ptr) { | |
162 | CFAllocatorRef allocator = (CFAllocatorRef)zone; | |
163 | CFAllocatorDeallocate(allocator, ptr); | |
164 | } | |
165 | ||
166 | static void *__CFAllocatorCustomRealloc(malloc_zone_t *zone, void *ptr, size_t size) { | |
167 | CFAllocatorRef allocator = (CFAllocatorRef)zone; | |
168 | return CFAllocatorReallocate(allocator, ptr, size, 0); | |
169 | } | |
170 | ||
171 | static void __CFAllocatorCustomDestroy(malloc_zone_t *zone) { | |
172 | CFAllocatorRef allocator = (CFAllocatorRef)zone; | |
173 | // !!! we do it, and caller of malloc_destroy_zone() assumes | |
174 | // COMPLETE responsibility for the result; NO Apple library | |
175 | // code should be modified as a result of discovering that | |
176 | // some activity results in inconveniences to developers | |
177 | // trying to use malloc_destroy_zone() with a CFAllocatorRef; | |
178 | // that's just too bad for them. | |
179 | __CFAllocatorDeallocate(allocator); | |
180 | } | |
181 | ||
182 | static size_t __CFAllocatorCustomGoodSize(malloc_zone_t *zone, size_t size) { | |
183 | CFAllocatorRef allocator = (CFAllocatorRef)zone; | |
184 | return CFAllocatorGetPreferredSizeForSize(allocator, size, 0); | |
185 | } | |
186 | ||
187 | static struct malloc_introspection_t __CFAllocatorZoneIntrospect = { | |
188 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
189 | (void *)__CFAllocatorCustomGoodSize, | |
190 | (void *)__CFAllocatorZoneIntrospectTrue, | |
191 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
192 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
193 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
194 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
195 | (void *)__CFAllocatorZoneIntrospectNoOp | |
196 | }; | |
197 | ||
198 | static size_t __CFAllocatorNullSize(malloc_zone_t *zone, const void *ptr) { | |
199 | return 0; | |
200 | } | |
201 | ||
202 | static void * __CFAllocatorNullMalloc(malloc_zone_t *zone, size_t size) { | |
203 | return NULL; | |
204 | } | |
205 | ||
206 | static void * __CFAllocatorNullCalloc(malloc_zone_t *zone, size_t num_items, size_t size) { | |
207 | return NULL; | |
208 | } | |
209 | ||
210 | static void * __CFAllocatorNullValloc(malloc_zone_t *zone, size_t size) { | |
211 | return NULL; | |
212 | } | |
213 | ||
214 | static void __CFAllocatorNullFree(malloc_zone_t *zone, void *ptr) { | |
215 | } | |
216 | ||
217 | static void * __CFAllocatorNullRealloc(malloc_zone_t *zone, void *ptr, size_t size) { | |
218 | return NULL; | |
219 | } | |
220 | ||
221 | static void __CFAllocatorNullDestroy(malloc_zone_t *zone) { | |
222 | } | |
223 | ||
224 | static size_t __CFAllocatorNullGoodSize(malloc_zone_t *zone, size_t size) { | |
225 | return size; | |
226 | } | |
227 | ||
228 | static struct malloc_introspection_t __CFAllocatorNullZoneIntrospect = { | |
229 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
230 | (void *)__CFAllocatorNullGoodSize, | |
231 | (void *)__CFAllocatorZoneIntrospectTrue, | |
232 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
233 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
234 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
235 | (void *)__CFAllocatorZoneIntrospectNoOp, | |
236 | (void *)__CFAllocatorZoneIntrospectNoOp | |
237 | }; | |
238 | ||
239 | static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) { | |
240 | return malloc_zone_malloc(info, size); | |
241 | } | |
242 | ||
243 | static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) { | |
244 | return malloc_zone_realloc(info, ptr, newsize); | |
245 | } | |
246 | ||
247 | static void __CFAllocatorSystemDeallocate(void *ptr, void *info) { | |
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__) | |
258 | static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) { | |
259 | return malloc(size); | |
260 | } | |
261 | ||
262 | static void *__CFAllocatorSystemReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) { | |
263 | return realloc(ptr, newsize); | |
264 | } | |
265 | ||
266 | static void __CFAllocatorSystemDeallocate(void *ptr, void *info) { | |
267 | free(ptr); | |
268 | } | |
269 | #endif | |
270 | ||
271 | static void *__CFAllocatorNullAllocate(CFIndex size, CFOptionFlags hint, void *info) { | |
272 | return NULL; | |
273 | } | |
274 | ||
275 | static void *__CFAllocatorNullReallocate(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) { | |
276 | return NULL; | |
277 | } | |
278 | ||
279 | static struct __CFAllocator __kCFAllocatorMalloc = { | |
280 | {NULL, 0, 0x0080}, | |
281 | #if defined(__MACH__) | |
282 | __CFAllocatorCustomSize, | |
283 | __CFAllocatorCustomMalloc, | |
284 | __CFAllocatorCustomCalloc, | |
285 | __CFAllocatorCustomValloc, | |
286 | __CFAllocatorCustomFree, | |
287 | __CFAllocatorCustomRealloc, | |
288 | __CFAllocatorNullDestroy, | |
289 | "kCFAllocatorMalloc", | |
290 | NULL, | |
291 | NULL, | |
292 | &__CFAllocatorZoneIntrospect, | |
293 | NULL, | |
294 | #endif | |
295 | NULL, // _allocator | |
296 | // Using the malloc functions directly is a total cheat, but works (in C) | |
297 | // because the function signatures match in their common prefix of arguments. | |
298 | // This saves us one hop through an adaptor function. | |
299 | {0, NULL, NULL, NULL, NULL, (void *)malloc, (void *)realloc, (void *)free, NULL} | |
300 | }; | |
301 | ||
d8925383 A |
302 | static struct __CFAllocator __kCFAllocatorMallocZone = { |
303 | {NULL, 0, 0x0080}, | |
304 | #if defined(__MACH__) | |
305 | __CFAllocatorCustomSize, | |
306 | __CFAllocatorCustomMalloc, | |
307 | __CFAllocatorCustomCalloc, | |
308 | __CFAllocatorCustomValloc, | |
309 | __CFAllocatorCustomFree, | |
310 | __CFAllocatorCustomRealloc, | |
311 | __CFAllocatorNullDestroy, | |
312 | "kCFAllocatorMallocZone", | |
313 | NULL, | |
314 | NULL, | |
315 | &__CFAllocatorZoneIntrospect, | |
316 | NULL, | |
317 | #endif | |
318 | NULL, // _allocator | |
319 | {0, NULL, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL} | |
320 | }; | |
321 | ||
9ce05555 A |
322 | static struct __CFAllocator __kCFAllocatorSystemDefault = { |
323 | {NULL, 0, 0x0080}, | |
324 | #if defined(__MACH__) | |
325 | __CFAllocatorCustomSize, | |
326 | __CFAllocatorCustomMalloc, | |
327 | __CFAllocatorCustomCalloc, | |
328 | __CFAllocatorCustomValloc, | |
329 | __CFAllocatorCustomFree, | |
330 | __CFAllocatorCustomRealloc, | |
331 | __CFAllocatorNullDestroy, | |
332 | "kCFAllocatorSystemDefault", | |
333 | NULL, | |
334 | NULL, | |
335 | &__CFAllocatorZoneIntrospect, | |
336 | NULL, | |
337 | #endif | |
338 | NULL, // _allocator | |
339 | {0, NULL, NULL, NULL, NULL, __CFAllocatorSystemAllocate, __CFAllocatorSystemReallocate, __CFAllocatorSystemDeallocate, NULL} | |
340 | }; | |
341 | ||
342 | static struct __CFAllocator __kCFAllocatorNull = { | |
343 | {NULL, 0, 0x0080}, | |
344 | #if defined(__MACH__) | |
345 | __CFAllocatorNullSize, | |
346 | __CFAllocatorNullMalloc, | |
347 | __CFAllocatorNullCalloc, | |
348 | __CFAllocatorNullValloc, | |
349 | __CFAllocatorNullFree, | |
350 | __CFAllocatorNullRealloc, | |
351 | __CFAllocatorNullDestroy, | |
352 | "kCFAllocatorNull", | |
353 | NULL, | |
354 | NULL, | |
355 | &__CFAllocatorNullZoneIntrospect, | |
356 | NULL, | |
357 | #endif | |
358 | NULL, // _allocator | |
359 | {0, NULL, NULL, NULL, NULL, __CFAllocatorNullAllocate, __CFAllocatorNullReallocate, NULL, NULL} | |
360 | }; | |
361 | ||
362 | const CFAllocatorRef kCFAllocatorDefault = NULL; | |
363 | const CFAllocatorRef kCFAllocatorSystemDefault = &__kCFAllocatorSystemDefault; | |
364 | const CFAllocatorRef kCFAllocatorMalloc = &__kCFAllocatorMalloc; | |
d8925383 | 365 | const CFAllocatorRef kCFAllocatorMallocZone = &__kCFAllocatorMallocZone; |
9ce05555 A |
366 | const CFAllocatorRef kCFAllocatorNull = &__kCFAllocatorNull; |
367 | const CFAllocatorRef kCFAllocatorUseContext = (CFAllocatorRef)0x0227; | |
368 | ||
d8925383 A |
369 | bool kCFUseCollectableAllocator = false; |
370 | ||
9ce05555 A |
371 | static CFStringRef __CFAllocatorCopyDescription(CFTypeRef cf) { |
372 | CFAllocatorRef self = cf; | |
373 | CFAllocatorRef allocator = (kCFAllocatorUseContext == self->_allocator) ? self : self->_allocator; | |
374 | return CFStringCreateWithFormat(allocator, NULL, CFSTR("<CFAllocator 0x%x [0x%x]>{info = 0x%x}"), (UInt32)cf, (UInt32)allocator, self->_context.info); | |
375 | // CF: should use copyDescription function here to describe info field | |
376 | // remember to release value returned from copydescr function when this happens | |
377 | } | |
378 | ||
379 | __private_extern__ CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef cf) { | |
380 | CFAllocatorRef allocator = cf; | |
381 | return (kCFAllocatorUseContext == allocator->_allocator) ? allocator : allocator->_allocator; | |
382 | } | |
383 | ||
384 | __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf) { | |
385 | CFAllocatorRef self = cf; | |
386 | CFAllocatorRef allocator = self->_allocator; | |
387 | CFAllocatorReleaseCallBack releaseFunc = __CFAllocatorGetReleaseFunction(&self->_context); | |
388 | if (kCFAllocatorUseContext == allocator) { | |
389 | /* Rather a chicken and egg problem here, so we do things | |
390 | in the reverse order from what was done at create time. */ | |
391 | CFAllocatorDeallocateCallBack deallocateFunc = __CFAllocatorGetDeallocateFunction(&self->_context); | |
392 | void *info = self->_context.info; | |
393 | if (NULL != deallocateFunc) { | |
394 | INVOKE_CALLBACK2(deallocateFunc, (void *)self, info); | |
395 | } | |
396 | if (NULL != releaseFunc) { | |
397 | INVOKE_CALLBACK1(releaseFunc, info); | |
398 | } | |
399 | } else { | |
400 | if (NULL != releaseFunc) { | |
401 | INVOKE_CALLBACK1(releaseFunc, self->_context.info); | |
402 | } | |
403 | CFAllocatorDeallocate(allocator, (void *)self); | |
404 | } | |
405 | } | |
406 | ||
407 | static CFTypeID __kCFAllocatorTypeID = _kCFRuntimeNotATypeID; | |
408 | ||
409 | static const CFRuntimeClass __CFAllocatorClass = { | |
410 | 0, | |
411 | "CFAllocator", | |
412 | NULL, // init | |
413 | NULL, // copy | |
414 | __CFAllocatorDeallocate, | |
415 | NULL, // equal | |
416 | NULL, // hash | |
417 | NULL, // | |
418 | __CFAllocatorCopyDescription | |
419 | }; | |
420 | ||
421 | __private_extern__ void __CFAllocatorInitialize(void) { | |
422 | __kCFAllocatorTypeID = _CFRuntimeRegisterClass(&__CFAllocatorClass); | |
423 | ||
424 | _CFRuntimeSetInstanceTypeID(&__kCFAllocatorSystemDefault, __kCFAllocatorTypeID); | |
425 | __kCFAllocatorSystemDefault._base._isa = __CFISAForTypeID(__kCFAllocatorTypeID); | |
426 | #if defined(__MACH__) | |
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 | ||
447 | CFTypeID CFAllocatorGetTypeID(void) { | |
448 | return __kCFAllocatorTypeID; | |
449 | } | |
450 | ||
451 | CFAllocatorRef CFAllocatorGetDefault(void) { | |
452 | CFAllocatorRef allocator = __CFGetThreadSpecificData_inline()->_allocator; | |
453 | if (NULL == allocator) { | |
454 | allocator = kCFAllocatorSystemDefault; | |
455 | } | |
456 | return allocator; | |
457 | } | |
458 | ||
459 | void CFAllocatorSetDefault(CFAllocatorRef allocator) { | |
460 | CFAllocatorRef current = __CFGetThreadSpecificData_inline()->_allocator; | |
461 | #if defined(DEBUG) | |
462 | if (NULL != allocator) { | |
463 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
464 | } | |
465 | #endif | |
466 | #if defined(__MACH__) | |
467 | if (allocator && allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
468 | return; // require allocator to this function to be an allocator | |
469 | } | |
470 | #endif | |
471 | if (NULL != allocator && allocator != current) { | |
472 | if (current) CFRelease(current); | |
473 | CFRetain(allocator); | |
474 | // We retain an extra time so that anything set as the default | |
475 | // allocator never goes away. | |
476 | CFRetain(allocator); | |
477 | __CFGetThreadSpecificData_inline()->_allocator = (void *)allocator; | |
478 | } | |
479 | } | |
480 | ||
d8925383 A |
481 | static 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 |
555 | CFAllocatorRef CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *context) { |
556 | CFAssert1(!CF_USING_COLLECTABLE_MEMORY, __kCFLogAssertion, "%s(): Shouldn't be called when GC is enabled!", __PRETTY_FUNCTION__); | |
557 | #if defined(DEBUG) | |
558 | if (CF_USING_COLLECTABLE_MEMORY) | |
559 | HALT; | |
560 | #endif | |
561 | return __CFAllocatorCreate(allocator, context); | |
562 | } | |
563 | ||
564 | CFAllocatorRef _CFAllocatorCreateGC(CFAllocatorRef allocator, CFAllocatorContext *context) { | |
565 | return __CFAllocatorCreate(allocator, context); | |
566 | } | |
567 | ||
9ce05555 A |
568 | void *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 | ||
597 | void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize, CFOptionFlags hint) { | |
598 | CFAllocatorAllocateCallBack allocateFunc; | |
599 | CFAllocatorReallocateCallBack reallocateFunc; | |
600 | CFAllocatorDeallocateCallBack deallocateFunc; | |
601 | void *newptr; | |
602 | allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; | |
603 | #if defined(__MACH__) && defined(DEBUG) | |
604 | if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) { | |
605 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
606 | } | |
607 | #else | |
608 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
609 | #endif | |
610 | if (NULL == ptr && 0 < newsize) { | |
611 | #if defined(__MACH__) | |
612 | if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
613 | return malloc_zone_malloc((malloc_zone_t *)allocator, newsize); | |
614 | } | |
615 | #endif | |
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 | ||
652 | void CFAllocatorDeallocate(CFAllocatorRef allocator, void *ptr) { | |
653 | CFAllocatorDeallocateCallBack deallocateFunc; | |
654 | allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; | |
655 | #if defined(__MACH__) && defined(DEBUG) | |
656 | if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) { | |
657 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
658 | } | |
659 | #else | |
660 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
661 | #endif | |
662 | #if defined(__MACH__) | |
663 | if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
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 | ||
677 | CFIndex CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) { | |
678 | CFAllocatorPreferredSizeCallBack prefFunc; | |
679 | CFIndex newsize = 0; | |
680 | allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; | |
681 | #if defined(__MACH__) && defined(DEBUG) | |
682 | if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) { | |
683 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
684 | } | |
685 | #else | |
686 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
687 | #endif | |
688 | #if defined(__MACH__) | |
689 | if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
690 | return malloc_good_size(size); | |
691 | } | |
692 | #endif | |
693 | prefFunc = __CFAllocatorGetPreferredSizeFunction(&allocator->_context); | |
694 | if (0 < size && NULL != prefFunc) { | |
695 | newsize = (CFIndex)(INVOKE_CALLBACK3(prefFunc, size, hint, allocator->_context.info)); | |
696 | } | |
697 | if (newsize < size) newsize = size; | |
698 | return newsize; | |
699 | } | |
700 | ||
701 | void CFAllocatorGetContext(CFAllocatorRef allocator, CFAllocatorContext *context) { | |
702 | allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; | |
703 | #if defined(__MACH__) && defined(DEBUG) | |
704 | if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) { | |
705 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
706 | } | |
707 | #else | |
708 | __CFGenericValidateType(allocator, __kCFAllocatorTypeID); | |
709 | #endif | |
710 | CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__); | |
711 | #if defined(__MACH__) | |
712 | if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * | |
713 | return; | |
714 | } | |
715 | #endif | |
716 | context->version = 0; | |
717 | context->info = allocator->_context.info; | |
718 | context->retain = __CFAllocatorGetRetainFunction(&allocator->_context); | |
719 | context->release = __CFAllocatorGetReleaseFunction(&allocator->_context); | |
720 | context->copyDescription = __CFAllocatorGetCopyDescriptionFunction(&allocator->_context); | |
721 | context->allocate = __CFAllocatorGetAllocateFunction(&allocator->_context); | |
722 | context->reallocate = __CFAllocatorGetReallocateFunction(&allocator->_context); | |
723 | context->deallocate = __CFAllocatorGetDeallocateFunction(&allocator->_context); | |
724 | context->preferredSize = __CFAllocatorGetPreferredSizeFunction(&allocator->_context); | |
725 | 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 |
734 | void *_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 | ||
742 | void *_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 | ||
756 | void _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 | ||
828 | CFRange __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 | ||
844 | struct __CFNull { | |
845 | CFRuntimeBase _base; | |
846 | }; | |
847 | ||
848 | static struct __CFNull __kCFNull = { | |
d8925383 | 849 | INIT_CFRUNTIME_BASE(NULL, 0, 0x0080) |
9ce05555 A |
850 | }; |
851 | const CFNullRef kCFNull = &__kCFNull; | |
852 | ||
853 | static CFStringRef __CFNullCopyDescription(CFTypeRef cf) { | |
854 | return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<CFNull %p [%p]>"), cf, CFGetAllocator(cf)); | |
855 | } | |
856 | ||
857 | static CFStringRef __CFNullCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { | |
858 | return CFRetain(CFSTR("null")); | |
859 | } | |
860 | ||
861 | static void __CFNullDeallocate(CFTypeRef cf) { | |
862 | CFAssert(false, __kCFLogAssertion, "Deallocated CFNull!"); | |
863 | } | |
864 | ||
865 | static CFTypeID __kCFNullTypeID = _kCFRuntimeNotATypeID; | |
866 | ||
867 | static 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 | ||
885 | CFTypeID CFNullGetTypeID(void) { | |
886 | return __kCFNullTypeID; | |
887 | } | |
888 | ||
889 | ||
890 | static int hasCFM = 0; | |
891 | ||
d8925383 | 892 | void _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 | /* | |
913 | Jump to callback function. r2 is not saved and restored | |
914 | in the jump-to-CFM case, since we assume that dyld code | |
915 | never uses that register and that CF is dyld. | |
916 | ||
917 | There 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 | ||
923 | There may be up to 5 word-sized arguments. Floating point | |
924 | arguments can be done, but count as two word arguments. | |
925 | Return 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 |