]>
Commit | Line | Data |
---|---|---|
13d88034 | 1 | /* |
b3962a83 | 2 | * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved. |
390d5862 | 3 | * |
b3962a83 | 4 | * @APPLE_LICENSE_HEADER_START@ |
390d5862 A |
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 | * | |
13d88034 | 13 | * The Original Code and all software distributed under the License are |
390d5862 | 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
13d88034 A |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
390d5862 A |
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 | * | |
13d88034 A |
21 | * @APPLE_LICENSE_HEADER_END@ |
22 | */ | |
23 | /*********************************************************************** | |
41c8faa5 A |
24 | * objc-runtime.m |
25 | * Copyright 1988-1996, NeXT Software, Inc. | |
26 | * Author: s. naroff | |
27 | * | |
28 | **********************************************************************/ | |
13d88034 | 29 | |
2bfd4448 A |
30 | |
31 | ||
13d88034 | 32 | /*********************************************************************** |
41c8faa5 A |
33 | * Imports. |
34 | **********************************************************************/ | |
13d88034 | 35 | |
7af964d1 A |
36 | #include "objc-private.h" |
37 | #include "objc-loadmethod.h" | |
8972963c | 38 | #include "message.h" |
2bfd4448 | 39 | |
b3962a83 | 40 | OBJC_EXPORT Class getOriginalClassForPosingClass(Class); |
2bfd4448 A |
41 | |
42 | ||
43 | /*********************************************************************** | |
b3962a83 | 44 | * Exports. |
2bfd4448 | 45 | **********************************************************************/ |
2bfd4448 | 46 | |
b3962a83 | 47 | // Settings from environment variables |
7257e56c A |
48 | #define OPTION(var, env, help) bool var = false; |
49 | #include "objc-env.h" | |
50 | #undef OPTION | |
51 | ||
52 | struct option_t { | |
53 | bool* var; | |
54 | const char *env; | |
55 | const char *help; | |
56 | size_t envlen; | |
57 | }; | |
58 | ||
59 | const option_t Settings[] = { | |
60 | #define OPTION(var, env, help) option_t{&var, #env, help, strlen(#env)}, | |
61 | #include "objc-env.h" | |
62 | #undef OPTION | |
63 | }; | |
2bfd4448 | 64 | |
2bfd4448 | 65 | |
b3962a83 | 66 | // objc's key for pthread_getspecific |
7af964d1 | 67 | static tls_key_t _objc_pthread_key; |
2bfd4448 | 68 | |
7af964d1 | 69 | // Selectors |
cd5f04f5 A |
70 | SEL SEL_load = NULL; |
71 | SEL SEL_initialize = NULL; | |
72 | SEL SEL_resolveInstanceMethod = NULL; | |
73 | SEL SEL_resolveClassMethod = NULL; | |
74 | SEL SEL_cxx_construct = NULL; | |
75 | SEL SEL_cxx_destruct = NULL; | |
76 | SEL SEL_retain = NULL; | |
77 | SEL SEL_release = NULL; | |
78 | SEL SEL_autorelease = NULL; | |
79 | SEL SEL_retainCount = NULL; | |
80 | SEL SEL_alloc = NULL; | |
81 | SEL SEL_allocWithZone = NULL; | |
8070259c | 82 | SEL SEL_dealloc = NULL; |
cd5f04f5 A |
83 | SEL SEL_copy = NULL; |
84 | SEL SEL_new = NULL; | |
85 | SEL SEL_finalize = NULL; | |
86 | SEL SEL_forwardInvocation = NULL; | |
8070259c A |
87 | SEL SEL_tryRetain = NULL; |
88 | SEL SEL_isDeallocating = NULL; | |
89 | SEL SEL_retainWeakReference = NULL; | |
90 | SEL SEL_allowsWeakReference = NULL; | |
91 | ||
cd5f04f5 A |
92 | |
93 | header_info *FirstHeader = 0; // NULL means empty list | |
94 | header_info *LastHeader = 0; // NULL means invalid; recompute it | |
95 | int HeaderCount = 0; | |
2bfd4448 | 96 | |
8070259c | 97 | uint32_t AppSDKVersion = 0; |
13d88034 | 98 | |
2bfd4448 | 99 | |
13d88034 | 100 | /*********************************************************************** |
b3962a83 A |
101 | * objc_getClass. Return the id of the named class. If the class does |
102 | * not exist, call _objc_classLoader and then objc_classHandler, either of | |
103 | * which may create a new class. | |
104 | * Warning: doesn't work if aClassName is the name of a posed-for class's isa! | |
41c8faa5 | 105 | **********************************************************************/ |
7257e56c | 106 | Class objc_getClass(const char *aClassName) |
13d88034 | 107 | { |
b3962a83 | 108 | if (!aClassName) return Nil; |
41c8faa5 | 109 | |
b3962a83 A |
110 | // NO unconnected, YES class handler |
111 | return look_up_class(aClassName, NO, YES); | |
13d88034 A |
112 | } |
113 | ||
2bfd4448 | 114 | |
13d88034 | 115 | /*********************************************************************** |
b3962a83 A |
116 | * objc_getRequiredClass. |
117 | * Same as objc_getClass, but kills the process if the class is not found. | |
118 | * This is used by ZeroLink, where failing to find a class would be a | |
119 | * compile-time link error without ZeroLink. | |
41c8faa5 | 120 | **********************************************************************/ |
7257e56c | 121 | Class objc_getRequiredClass(const char *aClassName) |
13d88034 | 122 | { |
7257e56c | 123 | Class cls = objc_getClass(aClassName); |
b3962a83 A |
124 | if (!cls) _objc_fatal("link error: class '%s' not found.", aClassName); |
125 | return cls; | |
13d88034 A |
126 | } |
127 | ||
2bfd4448 | 128 | |
13d88034 | 129 | /*********************************************************************** |
b3962a83 A |
130 | * objc_lookUpClass. Return the id of the named class. |
131 | * If the class does not exist, call _objc_classLoader, which may create | |
132 | * a new class. | |
133 | * | |
134 | * Formerly objc_getClassWithoutWarning () | |
41c8faa5 | 135 | **********************************************************************/ |
7257e56c | 136 | Class objc_lookUpClass(const char *aClassName) |
13d88034 | 137 | { |
b3962a83 | 138 | if (!aClassName) return Nil; |
13d88034 | 139 | |
b3962a83 A |
140 | // NO unconnected, NO class handler |
141 | return look_up_class(aClassName, NO, NO); | |
142 | } | |
2bfd4448 | 143 | |
2bfd4448 | 144 | |
13d88034 | 145 | /*********************************************************************** |
b3962a83 A |
146 | * objc_getMetaClass. Return the id of the meta class the named class. |
147 | * Warning: doesn't work if aClassName is the name of a posed-for class's isa! | |
41c8faa5 | 148 | **********************************************************************/ |
7257e56c | 149 | Class objc_getMetaClass(const char *aClassName) |
41c8faa5 | 150 | { |
b3962a83 | 151 | Class cls; |
41c8faa5 | 152 | |
b3962a83 | 153 | if (!aClassName) return Nil; |
390d5862 | 154 | |
7257e56c | 155 | cls = objc_getClass (aClassName); |
b3962a83 | 156 | if (!cls) |
41c8faa5 | 157 | { |
b3962a83 A |
158 | _objc_inform ("class `%s' not linked into application", aClassName); |
159 | return Nil; | |
41c8faa5 | 160 | } |
2bfd4448 | 161 | |
7257e56c | 162 | return cls->ISA(); |
13d88034 A |
163 | } |
164 | ||
165 | ||
13d88034 | 166 | /*********************************************************************** |
cd5f04f5 | 167 | * appendHeader. Add a newly-constructed header_info to the list. |
41c8faa5 | 168 | **********************************************************************/ |
cd5f04f5 | 169 | void appendHeader(header_info *hi) |
b3962a83 | 170 | { |
2bfd4448 A |
171 | // Add the header to the header list. |
172 | // The header is appended to the list, to preserve the bottom-up order. | |
b3962a83 | 173 | HeaderCount++; |
7af964d1 | 174 | hi->next = NULL; |
2bfd4448 A |
175 | if (!FirstHeader) { |
176 | // list is empty | |
7af964d1 | 177 | FirstHeader = LastHeader = hi; |
2bfd4448 A |
178 | } else { |
179 | if (!LastHeader) { | |
180 | // list is not empty, but LastHeader is invalid - recompute it | |
181 | LastHeader = FirstHeader; | |
182 | while (LastHeader->next) LastHeader = LastHeader->next; | |
390d5862 | 183 | } |
2bfd4448 | 184 | // LastHeader is now valid |
7af964d1 A |
185 | LastHeader->next = hi; |
186 | LastHeader = hi; | |
390d5862 | 187 | } |
390d5862 A |
188 | } |
189 | ||
2bfd4448 | 190 | |
390d5862 | 191 | /*********************************************************************** |
cd5f04f5 | 192 | * removeHeader |
2bfd4448 A |
193 | * Remove the given header from the header list. |
194 | * FirstHeader is updated. | |
195 | * LastHeader is set to NULL. Any code that uses LastHeader must | |
196 | * detect this NULL and recompute LastHeader by traversing the list. | |
390d5862 | 197 | **********************************************************************/ |
cd5f04f5 | 198 | void removeHeader(header_info *hi) |
390d5862 | 199 | { |
2bfd4448 A |
200 | header_info **hiP; |
201 | ||
202 | for (hiP = &FirstHeader; *hiP != NULL; hiP = &(**hiP).next) { | |
203 | if (*hiP == hi) { | |
204 | header_info *deadHead = *hiP; | |
205 | ||
206 | // Remove from the linked list (updating FirstHeader if necessary). | |
207 | *hiP = (**hiP).next; | |
208 | ||
209 | // Update LastHeader if necessary. | |
210 | if (LastHeader == deadHead) { | |
211 | LastHeader = NULL; // will be recomputed next time it's used | |
212 | } | |
213 | ||
b3962a83 | 214 | HeaderCount--; |
2bfd4448 | 215 | break; |
390d5862 A |
216 | } |
217 | } | |
390d5862 A |
218 | } |
219 | ||
220 | ||
13d88034 | 221 | /*********************************************************************** |
7af964d1 | 222 | * environ_init |
2bfd4448 A |
223 | * Read environment variables that affect the runtime. |
224 | * Also print environment variable help, if requested. | |
41c8faa5 | 225 | **********************************************************************/ |
cd5f04f5 | 226 | void environ_init(void) |
7af964d1 | 227 | { |
7257e56c A |
228 | if (issetugid()) { |
229 | // All environment variables are silently ignored when setuid or setgid | |
7af964d1 | 230 | // This includes OBJC_HELP and OBJC_PRINT_OPTIONS themselves. |
7257e56c | 231 | return; |
b3962a83 | 232 | } |
7257e56c A |
233 | |
234 | bool PrintHelp = false; | |
235 | bool PrintOptions = false; | |
236 | ||
237 | // Scan environ[] directly instead of calling getenv() a lot. | |
238 | // This optimizes the case where none are set. | |
239 | for (char **p = *_NSGetEnviron(); *p != nil; p++) { | |
240 | if (0 != strncmp(*p, "OBJC_", 5)) continue; | |
241 | ||
242 | if (0 == strncmp(*p, "OBJC_HELP=", 10)) { | |
243 | PrintHelp = true; | |
244 | continue; | |
245 | } | |
246 | if (0 == strncmp(*p, "OBJC_PRINT_OPTIONS=", 19)) { | |
247 | PrintOptions = true; | |
248 | continue; | |
249 | } | |
250 | ||
251 | const char *value = strchr(*p, '='); | |
252 | if (!*value) continue; | |
253 | value++; | |
254 | ||
255 | for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) { | |
256 | const option_t *opt = &Settings[i]; | |
257 | if ((size_t)(value - *p) == 1+opt->envlen && | |
258 | 0 == strncmp(*p, opt->env, opt->envlen)) | |
259 | { | |
260 | *opt->var = (0 == strcmp(value, "YES")); | |
261 | break; | |
262 | } | |
263 | } | |
264 | } | |
265 | ||
266 | // Print OBJC_HELP and OBJC_PRINT_OPTIONS output. | |
267 | if (PrintHelp || PrintOptions) { | |
b3962a83 | 268 | if (PrintHelp) { |
7af964d1 A |
269 | _objc_inform("Objective-C runtime debugging. Set variable=YES to enable."); |
270 | _objc_inform("OBJC_HELP: describe available environment variables"); | |
b3962a83 A |
271 | if (PrintOptions) { |
272 | _objc_inform("OBJC_HELP is set"); | |
273 | } | |
274 | _objc_inform("OBJC_PRINT_OPTIONS: list which options are set"); | |
275 | } | |
2bfd4448 | 276 | if (PrintOptions) { |
b3962a83 | 277 | _objc_inform("OBJC_PRINT_OPTIONS is set"); |
2bfd4448 | 278 | } |
b3962a83 | 279 | |
7257e56c A |
280 | for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) { |
281 | const option_t *opt = &Settings[i]; | |
282 | if (PrintHelp) _objc_inform("%s: %s", opt->env, opt->help); | |
283 | if (PrintOptions && *opt->var) _objc_inform("%s is set", opt->env); | |
284 | } | |
285 | } | |
7af964d1 A |
286 | } |
287 | ||
288 | ||
289 | /*********************************************************************** | |
290 | * logReplacedMethod | |
291 | * OBJC_PRINT_REPLACED_METHODS implementation | |
292 | **********************************************************************/ | |
cd5f04f5 | 293 | void |
7af964d1 A |
294 | logReplacedMethod(const char *className, SEL s, |
295 | BOOL isMeta, const char *catName, | |
296 | IMP oldImp, IMP newImp) | |
297 | { | |
298 | const char *oldImage = "??"; | |
299 | const char *newImage = "??"; | |
300 | ||
301 | // Silently ignore +load replacement because category +load is special | |
302 | if (s == SEL_load) return; | |
303 | ||
304 | #if TARGET_OS_WIN32 | |
305 | // don't know dladdr()/dli_fname equivalent | |
306 | #else | |
307 | Dl_info dl; | |
308 | ||
cd5f04f5 A |
309 | if (dladdr((void*)oldImp, &dl) && dl.dli_fname) oldImage = dl.dli_fname; |
310 | if (dladdr((void*)newImp, &dl) && dl.dli_fname) newImage = dl.dli_fname; | |
7af964d1 A |
311 | #endif |
312 | ||
313 | _objc_inform("REPLACED: %c[%s %s] %s%s (IMP was %p (%s), now %p (%s))", | |
314 | isMeta ? '+' : '-', className, sel_getName(s), | |
315 | catName ? "by category " : "", catName ? catName : "", | |
316 | oldImp, oldImage, newImp, newImage); | |
41c8faa5 | 317 | } |
2bfd4448 A |
318 | |
319 | ||
7af964d1 | 320 | |
41c8faa5 A |
321 | /*********************************************************************** |
322 | * objc_setMultithreaded. | |
323 | **********************************************************************/ | |
13d88034 A |
324 | void objc_setMultithreaded (BOOL flag) |
325 | { | |
b3962a83 A |
326 | OBJC_WARN_DEPRECATED; |
327 | ||
1f20c7a7 | 328 | // Nothing here. Thread synchronization in the runtime is always active. |
13d88034 | 329 | } |
1f20c7a7 A |
330 | |
331 | ||
b3962a83 A |
332 | /*********************************************************************** |
333 | * _objc_fetch_pthread_data | |
334 | * Fetch objc's pthread data for this thread. | |
335 | * If the data doesn't exist yet and create is NO, return NULL. | |
336 | * If the data doesn't exist yet and create is YES, allocate and return it. | |
337 | **********************************************************************/ | |
cd5f04f5 | 338 | _objc_pthread_data *_objc_fetch_pthread_data(BOOL create) |
b3962a83 A |
339 | { |
340 | _objc_pthread_data *data; | |
341 | ||
cd5f04f5 | 342 | data = (_objc_pthread_data *)tls_get(_objc_pthread_key); |
b3962a83 | 343 | if (!data && create) { |
cd5f04f5 A |
344 | data = (_objc_pthread_data *) |
345 | _calloc_internal(1, sizeof(_objc_pthread_data)); | |
7af964d1 | 346 | tls_set(_objc_pthread_key, data); |
b3962a83 A |
347 | } |
348 | ||
349 | return data; | |
350 | } | |
351 | ||
1f20c7a7 A |
352 | |
353 | /*********************************************************************** | |
354 | * _objc_pthread_destroyspecific | |
355 | * Destructor for objc's per-thread data. | |
356 | * arg shouldn't be NULL, but we check anyway. | |
357 | **********************************************************************/ | |
358 | extern void _destroyInitializingClassList(struct _objc_initializing_classes *list); | |
cd5f04f5 | 359 | void _objc_pthread_destroyspecific(void *arg) |
1f20c7a7 A |
360 | { |
361 | _objc_pthread_data *data = (_objc_pthread_data *)arg; | |
362 | if (data != NULL) { | |
363 | _destroyInitializingClassList(data->initializingClasses); | |
b3962a83 A |
364 | _destroySyncCache(data->syncCache); |
365 | _destroyAltHandlerList(data->handlerList); | |
8070259c A |
366 | for (int i = 0; i < (int)countof(data->printableNames); i++) { |
367 | if (data->printableNames[i]) { | |
368 | free(data->printableNames[i]); | |
369 | } | |
370 | } | |
1f20c7a7 A |
371 | |
372 | // add further cleanup here... | |
373 | ||
b3962a83 A |
374 | _free_internal(data); |
375 | } | |
376 | } | |
377 | ||
378 | ||
cd5f04f5 | 379 | void tls_init(void) |
b3962a83 | 380 | { |
8972963c | 381 | #if SUPPORT_DIRECT_THREAD_KEYS |
7af964d1 A |
382 | _objc_pthread_key = TLS_DIRECT_KEY; |
383 | pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific); | |
8972963c A |
384 | #else |
385 | _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific); | |
b3962a83 | 386 | #endif |
2bfd4448 A |
387 | } |
388 | ||
13d88034 | 389 | |
2bfd4448 | 390 | /*********************************************************************** |
7af964d1 A |
391 | * _objcInit |
392 | * Former library initializer. This function is now merely a placeholder | |
393 | * for external callers. All runtime initialization has now been moved | |
394 | * to map_images() and _objc_init. | |
41c8faa5 | 395 | **********************************************************************/ |
7af964d1 | 396 | void _objcInit(void) |
2bfd4448 | 397 | { |
7af964d1 | 398 | // do nothing |
13d88034 | 399 | } |
13d88034 | 400 | |
2bfd4448 | 401 | |
13d88034 | 402 | /*********************************************************************** |
8070259c | 403 | * objc_setForwardHandler |
41c8faa5 | 404 | **********************************************************************/ |
390d5862 | 405 | |
8070259c A |
406 | #if !__OBJC2__ |
407 | ||
408 | // Default forward handler (nil) goes to forward:: dispatch. | |
409 | void *_objc_forward_handler = nil; | |
410 | void *_objc_forward_stret_handler = nil; | |
390d5862 | 411 | |
8070259c A |
412 | #else |
413 | ||
414 | // Default forward handler halts the process. | |
415 | __attribute__((noreturn)) void | |
416 | objc_defaultForwardHandler(id self, SEL sel) | |
417 | { | |
418 | _objc_fatal("%c[%s %s]: unrecognized selector sent to instance %p " | |
419 | "(no message forward handler is installed)", | |
420 | class_isMetaClass(object_getClass(self)) ? '+' : '-', | |
421 | object_getClassName(self), sel_getName(sel), self); | |
13d88034 | 422 | } |
8070259c | 423 | void *_objc_forward_handler = (void*)objc_defaultForwardHandler; |
13d88034 | 424 | |
8070259c A |
425 | #if SUPPORT_STRET |
426 | struct stret { int i[100]; }; | |
427 | __attribute__((noreturn)) struct stret | |
428 | objc_defaultForwardStretHandler(id self, SEL sel) | |
13d88034 | 429 | { |
8070259c | 430 | objc_defaultForwardHandler(self, sel); |
13d88034 | 431 | } |
8070259c | 432 | void *_objc_forward_stret_handler = (void*)objc_defaultForwardStretHandler; |
7af964d1 | 433 | #endif |
13d88034 | 434 | |
8070259c | 435 | #endif |
13d88034 | 436 | |
b3962a83 A |
437 | void objc_setForwardHandler(void *fwd, void *fwd_stret) |
438 | { | |
439 | _objc_forward_handler = fwd; | |
8070259c | 440 | #if SUPPORT_STRET |
b3962a83 | 441 | _objc_forward_stret_handler = fwd_stret; |
8070259c | 442 | #endif |
b3962a83 A |
443 | } |
444 | ||
445 | ||
b3962a83 A |
446 | #if !__OBJC2__ |
447 | // GrP fixme | |
7257e56c | 448 | extern "C" Class _objc_getOrigClass(const char *name); |
b3962a83 A |
449 | #endif |
450 | const char *class_getImageName(Class cls) | |
451 | { | |
7af964d1 A |
452 | #if TARGET_OS_WIN32 |
453 | TCHAR *szFileName; | |
454 | DWORD charactersCopied; | |
455 | Class origCls; | |
456 | HMODULE classModule; | |
457 | BOOL res; | |
458 | #endif | |
b3962a83 A |
459 | if (!cls) return NULL; |
460 | ||
461 | #if !__OBJC2__ | |
8070259c | 462 | cls = _objc_getOrigClass(cls->demangledName()); |
b3962a83 | 463 | #endif |
7af964d1 | 464 | #if TARGET_OS_WIN32 |
7257e56c A |
465 | charactersCopied = 0; |
466 | szFileName = malloc(MAX_PATH * sizeof(TCHAR)); | |
467 | ||
8070259c | 468 | origCls = objc_getOrigClass(cls->demangledName()); |
7257e56c A |
469 | classModule = NULL; |
470 | res = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)origCls, &classModule); | |
471 | if (res && classModule) { | |
472 | charactersCopied = GetModuleFileName(classModule, szFileName, MAX_PATH * sizeof(TCHAR)); | |
473 | } | |
474 | if (classModule) FreeLibrary(classModule); | |
475 | if (charactersCopied) { | |
476 | return (const char *)szFileName; | |
477 | } else { | |
478 | free(szFileName); | |
479 | } | |
7af964d1 A |
480 | return NULL; |
481 | #else | |
482 | return dyld_image_path_containing_address(cls); | |
483 | #endif | |
b3962a83 A |
484 | } |
485 | ||
486 | ||
487 | const char **objc_copyImageNames(unsigned int *outCount) | |
488 | { | |
489 | header_info *hi; | |
490 | int count = 0; | |
491 | int max = HeaderCount; | |
8972963c | 492 | #if TARGET_OS_WIN32 |
cd5f04f5 | 493 | const TCHAR **names = (const TCHAR **)calloc(max+1, sizeof(TCHAR *)); |
8972963c | 494 | #else |
cd5f04f5 | 495 | const char **names = (const char **)calloc(max+1, sizeof(char *)); |
8972963c | 496 | #endif |
b3962a83 | 497 | |
7af964d1 A |
498 | for (hi = FirstHeader; hi != NULL && count < max; hi = hi->next) { |
499 | #if TARGET_OS_WIN32 | |
cd5f04f5 A |
500 | if (hi->moduleName) { |
501 | names[count++] = hi->moduleName; | |
8972963c | 502 | } |
7af964d1 | 503 | #else |
cd5f04f5 A |
504 | if (hi->fname) { |
505 | names[count++] = hi->fname; | |
b3962a83 | 506 | } |
7af964d1 | 507 | #endif |
b3962a83 A |
508 | } |
509 | names[count] = NULL; | |
510 | ||
511 | if (count == 0) { | |
512 | // Return NULL instead of empty list if there are no images | |
7af964d1 | 513 | free((void *)names); |
b3962a83 A |
514 | names = NULL; |
515 | } | |
516 | ||
517 | if (outCount) *outCount = count; | |
518 | return names; | |
519 | } | |
520 | ||
521 | ||
522 | /********************************************************************** | |
523 | * | |
524 | **********************************************************************/ | |
525 | const char ** | |
526 | objc_copyClassNamesForImage(const char *image, unsigned int *outCount) | |
527 | { | |
528 | header_info *hi; | |
529 | ||
530 | if (!image) { | |
531 | if (outCount) *outCount = 0; | |
532 | return NULL; | |
533 | } | |
534 | ||
535 | // Find the image. | |
7af964d1 A |
536 | for (hi = FirstHeader; hi != NULL; hi = hi->next) { |
537 | #if TARGET_OS_WIN32 | |
cd5f04f5 | 538 | if (0 == wcscmp((TCHAR *)image, hi->moduleName)) break; |
7af964d1 | 539 | #else |
cd5f04f5 | 540 | if (0 == strcmp(image, hi->fname)) break; |
7af964d1 | 541 | #endif |
b3962a83 A |
542 | } |
543 | ||
544 | if (!hi) { | |
545 | if (outCount) *outCount = 0; | |
546 | return NULL; | |
547 | } | |
548 | ||
549 | return _objc_copyClassNamesForImage(hi, outCount); | |
550 | } | |
551 | ||
552 | ||
553 | /********************************************************************** | |
554 | * Fast Enumeration Support | |
555 | **********************************************************************/ | |
556 | ||
557 | static void (*enumerationMutationHandler)(id); | |
558 | ||
559 | /********************************************************************** | |
560 | * objc_enumerationMutation | |
561 | * called by compiler when a mutation is detected during foreach iteration | |
562 | **********************************************************************/ | |
563 | void objc_enumerationMutation(id object) { | |
564 | if (enumerationMutationHandler == nil) { | |
7257e56c | 565 | _objc_fatal("mutation detected during 'for(... in ...)' enumeration of object %p.", (void*)object); |
b3962a83 A |
566 | } |
567 | (*enumerationMutationHandler)(object); | |
568 | } | |
569 | ||
570 | ||
571 | /********************************************************************** | |
572 | * objc_setEnumerationMutationHandler | |
573 | * an entry point to customize mutation error handing | |
574 | **********************************************************************/ | |
575 | void objc_setEnumerationMutationHandler(void (*handler)(id)) { | |
576 | enumerationMutationHandler = handler; | |
577 | } | |
7af964d1 A |
578 | |
579 | ||
8972963c A |
580 | /********************************************************************** |
581 | * Associative Reference Support | |
582 | **********************************************************************/ | |
583 | ||
cd5f04f5 | 584 | id objc_getAssociatedObject_non_gc(id object, const void *key) { |
8972963c A |
585 | return _object_get_associative_reference(object, (void *)key); |
586 | } | |
587 | ||
7257e56c A |
588 | |
589 | void objc_setAssociatedObject_non_gc(id object, const void *key, id value, objc_AssociationPolicy policy) { | |
590 | _object_set_associative_reference(object, (void *)key, value, policy); | |
8972963c A |
591 | } |
592 | ||
7257e56c | 593 | |
8972963c | 594 | #if SUPPORT_GC |
7257e56c A |
595 | |
596 | id objc_getAssociatedObject_gc(id object, const void *key) { | |
597 | return (id)auto_zone_get_associative_ref(gc_zone, object, (void *)key); | |
598 | } | |
599 | ||
cd5f04f5 | 600 | void objc_setAssociatedObject_gc(id object, const void *key, id value, objc_AssociationPolicy policy) { |
8972963c | 601 | if ((policy & OBJC_ASSOCIATION_COPY_NONATOMIC) == OBJC_ASSOCIATION_COPY_NONATOMIC) { |
cd5f04f5 | 602 | value = ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy); |
8972963c A |
603 | } |
604 | auto_zone_set_associative_ref(gc_zone, object, (void *)key, value); | |
605 | } | |
8972963c | 606 | |
7257e56c A |
607 | // objc_setAssociatedObject and objc_getAssociatedObject are |
608 | // resolver functions in objc-auto.mm. | |
609 | ||
610 | #else | |
611 | ||
612 | id | |
613 | objc_getAssociatedObject(id object, const void *key) | |
614 | { | |
615 | return objc_getAssociatedObject_non_gc(object, key); | |
8972963c A |
616 | } |
617 | ||
7257e56c A |
618 | void |
619 | objc_setAssociatedObject(id object, const void *key, id value, | |
620 | objc_AssociationPolicy policy) | |
621 | { | |
622 | objc_setAssociatedObject_non_gc(object, key, value, policy); | |
8972963c A |
623 | } |
624 | ||
7257e56c A |
625 | #endif |
626 | ||
627 | ||
628 | void objc_removeAssociatedObjects(id object) | |
629 | { | |
8972963c A |
630 | #if SUPPORT_GC |
631 | if (UseGC) { | |
632 | auto_zone_erase_associative_refs(gc_zone, object); | |
633 | } else | |
634 | #endif | |
635 | { | |
8070259c | 636 | if (object && object->hasAssociatedObjects()) { |
7257e56c | 637 | _object_remove_assocations(object); |
7af964d1 A |
638 | } |
639 | } | |
640 | } | |
641 |