]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-runtime.mm
49719ab2124fde039416bb783945e48eb634d168
[apple/objc4.git] / runtime / objc-runtime.mm
1 /*
2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /***********************************************************************
24 * objc-runtime.m
25 * Copyright 1988-1996, NeXT Software, Inc.
26 * Author: s. naroff
27 *
28 **********************************************************************/
29
30
31
32 /***********************************************************************
33 * Imports.
34 **********************************************************************/
35
36 #include "objc-private.h"
37 #include "objc-loadmethod.h"
38 #include "message.h"
39
40 OBJC_EXPORT Class getOriginalClassForPosingClass(Class);
41
42
43 /***********************************************************************
44 * Exports.
45 **********************************************************************/
46
47 // Settings from environment variables
48 #if SUPPORT_ENVIRON
49 int PrintImages = -1; // env OBJC_PRINT_IMAGES
50 int PrintLoading = -1; // env OBJC_PRINT_LOAD_METHODS
51 int PrintInitializing = -1; // env OBJC_PRINT_INITIALIZE_METHODS
52 int PrintResolving = -1; // env OBJC_PRINT_RESOLVED_METHODS
53 int PrintConnecting = -1; // env OBJC_PRINT_CLASS_SETUP
54 int PrintProtocols = -1; // env OBJC_PRINT_PROTOCOL_SETUP
55 int PrintIvars = -1; // env OBJC_PRINT_IVAR_SETUP
56 int PrintVtables = -1; // env OBJC_PRINT_VTABLE_SETUP
57 int PrintVtableImages = -1;//env OBJC_PRINT_VTABLE_IMAGES
58 int PrintFuture = -1; // env OBJC_PRINT_FUTURE_CLASSES
59 int PrintGC = -1; // env OBJC_PRINT_GC
60 int PrintPreopt = -1; // env OBJC_PRINT_PREOPTIMIZATION
61 int PrintCxxCtors = -1; // env OBJC_PRINT_CXX_CTORS
62 int PrintExceptions = -1; // env OBJC_PRINT_EXCEPTIONS
63 int PrintExceptionThrow = -1; // env OBJC_PRINT_EXCEPTION_THROW
64 int PrintAltHandlers = -1; // env OBJC_PRINT_ALT_HANDLERS
65 int PrintDeprecation = -1;// env OBJC_PRINT_DEPRECATION_WARNINGS
66 int PrintReplacedMethods = -1; // env OBJC_PRINT_REPLACED_METHODS
67 int PrintCaches = -1; // env OBJC_PRINT_CACHE_SETUP
68 int PrintPoolHiwat = -1; // env OBJC_PRINT_POOL_HIGHWATER
69 int PrintCustomRR = -1; // env OBJC_PRINT_CUSTOM_RR
70 int PrintCustomAWZ = -1; // env OBJC_PRINT_CUSTOM_AWZ
71
72 int UseInternalZone = -1; // env OBJC_USE_INTERNAL_ZONE
73
74 int DebugUnload = -1; // env OBJC_DEBUG_UNLOAD
75 int DebugFragileSuperclasses = -1; // env OBJC_DEBUG_FRAGILE_SUPERCLASSES
76 int DebugNilSync = -1; // env OBJC_DEBUG_NIL_SYNC
77 int DebugNonFragileIvars = -1; // env OBJC_DEBUG_NONFRAGILE_IVARS
78 int DebugAltHandlers = -1;// env OBJC_DEBUG_ALT_HANDLERS
79
80 int DisableGC = -1; // env OBJC_DISABLE_GC
81 int DisableVtables = -1; // env OBJC_DISABLE_VTABLES
82 int DisablePreopt = -1; // env OBJC_DISABLE_PREOPTIMIZATION
83 int DebugFinalizers = -1; // env OBJC_DEBUG_FINALIZERS
84 #endif
85
86
87 // objc's key for pthread_getspecific
88 static tls_key_t _objc_pthread_key;
89
90 // Selectors
91 SEL SEL_load = NULL;
92 SEL SEL_initialize = NULL;
93 SEL SEL_resolveInstanceMethod = NULL;
94 SEL SEL_resolveClassMethod = NULL;
95 SEL SEL_cxx_construct = NULL;
96 SEL SEL_cxx_destruct = NULL;
97 SEL SEL_retain = NULL;
98 SEL SEL_release = NULL;
99 SEL SEL_autorelease = NULL;
100 SEL SEL_retainCount = NULL;
101 SEL SEL_alloc = NULL;
102 SEL SEL_allocWithZone = NULL;
103 SEL SEL_copy = NULL;
104 SEL SEL_new = NULL;
105 SEL SEL_finalize = NULL;
106 SEL SEL_forwardInvocation = NULL;
107
108 header_info *FirstHeader = 0; // NULL means empty list
109 header_info *LastHeader = 0; // NULL means invalid; recompute it
110 int HeaderCount = 0;
111
112
113
114 /***********************************************************************
115 * objc_getClass. Return the id of the named class. If the class does
116 * not exist, call _objc_classLoader and then objc_classHandler, either of
117 * which may create a new class.
118 * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
119 **********************************************************************/
120 id objc_getClass(const char *aClassName)
121 {
122 if (!aClassName) return Nil;
123
124 // NO unconnected, YES class handler
125 return look_up_class(aClassName, NO, YES);
126 }
127
128
129 /***********************************************************************
130 * objc_getRequiredClass.
131 * Same as objc_getClass, but kills the process if the class is not found.
132 * This is used by ZeroLink, where failing to find a class would be a
133 * compile-time link error without ZeroLink.
134 **********************************************************************/
135 id objc_getRequiredClass(const char *aClassName)
136 {
137 id cls = objc_getClass(aClassName);
138 if (!cls) _objc_fatal("link error: class '%s' not found.", aClassName);
139 return cls;
140 }
141
142
143 /***********************************************************************
144 * objc_lookUpClass. Return the id of the named class.
145 * If the class does not exist, call _objc_classLoader, which may create
146 * a new class.
147 *
148 * Formerly objc_getClassWithoutWarning ()
149 **********************************************************************/
150 id objc_lookUpClass(const char *aClassName)
151 {
152 if (!aClassName) return Nil;
153
154 // NO unconnected, NO class handler
155 return look_up_class(aClassName, NO, NO);
156 }
157
158 /***********************************************************************
159 * objc_getFutureClass. Return the id of the named class.
160 * If the class does not exist, return an uninitialized class
161 * structure that will be used for the class when and if it
162 * does get loaded.
163 * Not thread safe.
164 **********************************************************************/
165 Class objc_getFutureClass(const char *name)
166 {
167 Class cls;
168
169 // YES unconnected, NO class handler
170 // (unconnected is OK because it will someday be the real class)
171 cls = (Class)look_up_class(name, YES, NO);
172 if (cls) {
173 if (PrintFuture) {
174 _objc_inform("FUTURE: found %p already in use for %s", cls, name);
175 }
176 return cls;
177 }
178
179 // No class or future class with that name yet. Make one.
180 // fixme not thread-safe with respect to
181 // simultaneous library load or getFutureClass.
182 return _objc_allocateFutureClass(name);
183 }
184
185
186 /***********************************************************************
187 * objc_getMetaClass. Return the id of the meta class the named class.
188 * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
189 **********************************************************************/
190 id objc_getMetaClass(const char *aClassName)
191 {
192 Class cls;
193
194 if (!aClassName) return Nil;
195
196 cls = (Class)objc_getClass (aClassName);
197 if (!cls)
198 {
199 _objc_inform ("class `%s' not linked into application", aClassName);
200 return Nil;
201 }
202
203 return (id)cls->isa;
204 }
205
206
207 /***********************************************************************
208 * appendHeader. Add a newly-constructed header_info to the list.
209 **********************************************************************/
210 void appendHeader(header_info *hi)
211 {
212 // Add the header to the header list.
213 // The header is appended to the list, to preserve the bottom-up order.
214 HeaderCount++;
215 hi->next = NULL;
216 if (!FirstHeader) {
217 // list is empty
218 FirstHeader = LastHeader = hi;
219 } else {
220 if (!LastHeader) {
221 // list is not empty, but LastHeader is invalid - recompute it
222 LastHeader = FirstHeader;
223 while (LastHeader->next) LastHeader = LastHeader->next;
224 }
225 // LastHeader is now valid
226 LastHeader->next = hi;
227 LastHeader = hi;
228 }
229 }
230
231
232 /***********************************************************************
233 * removeHeader
234 * Remove the given header from the header list.
235 * FirstHeader is updated.
236 * LastHeader is set to NULL. Any code that uses LastHeader must
237 * detect this NULL and recompute LastHeader by traversing the list.
238 **********************************************************************/
239 void removeHeader(header_info *hi)
240 {
241 header_info **hiP;
242
243 for (hiP = &FirstHeader; *hiP != NULL; hiP = &(**hiP).next) {
244 if (*hiP == hi) {
245 header_info *deadHead = *hiP;
246
247 // Remove from the linked list (updating FirstHeader if necessary).
248 *hiP = (**hiP).next;
249
250 // Update LastHeader if necessary.
251 if (LastHeader == deadHead) {
252 LastHeader = NULL; // will be recomputed next time it's used
253 }
254
255 HeaderCount--;
256 break;
257 }
258 }
259 }
260
261
262 /***********************************************************************
263 * environ_init
264 * Read environment variables that affect the runtime.
265 * Also print environment variable help, if requested.
266 **********************************************************************/
267 void environ_init(void)
268 {
269 #if SUPPORT_ENVIRON
270 int PrintHelp = (getenv("OBJC_HELP") != NULL);
271 int PrintOptions = (getenv("OBJC_PRINT_OPTIONS") != NULL);
272 int secure = issetugid();
273
274 if (secure) {
275 // All environment variables are ignored when setuid or setgid.
276 // This includes OBJC_HELP and OBJC_PRINT_OPTIONS themselves.
277 }
278 else {
279 if (PrintHelp) {
280 _objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");
281 _objc_inform("OBJC_HELP: describe available environment variables");
282 if (PrintOptions) {
283 _objc_inform("OBJC_HELP is set");
284 }
285 _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
286 }
287 if (PrintOptions) {
288 _objc_inform("OBJC_PRINT_OPTIONS is set");
289 }
290 }
291
292 #define OPTION(var, env, help) \
293 if ( var == -1 ) { \
294 char *value = getenv(#env); \
295 var = value != NULL && !strcmp("YES", value); \
296 if (secure) { \
297 if (var) _objc_inform(#env " ignored when running setuid or setgid"); \
298 var = 0; \
299 } else { \
300 if (PrintHelp) _objc_inform(#env ": " help); \
301 if (PrintOptions && var) _objc_inform(#env " is set"); \
302 } \
303 }
304
305 OPTION(PrintImages, OBJC_PRINT_IMAGES,
306 "log image and library names as they are loaded");
307 OPTION(PrintLoading, OBJC_PRINT_LOAD_METHODS,
308 "log calls to class and category +load methods");
309 OPTION(PrintInitializing, OBJC_PRINT_INITIALIZE_METHODS,
310 "log calls to class +initialize methods");
311 OPTION(PrintResolving, OBJC_PRINT_RESOLVED_METHODS,
312 "log methods created by +resolveClassMethod: and +resolveInstanceMethod:");
313 OPTION(PrintConnecting, OBJC_PRINT_CLASS_SETUP,
314 "log progress of class and category setup");
315 OPTION(PrintProtocols, OBJC_PRINT_PROTOCOL_SETUP,
316 "log progress of protocol setup");
317 OPTION(PrintIvars, OBJC_PRINT_IVAR_SETUP,
318 "log processing of non-fragile ivars");
319 OPTION(PrintVtables, OBJC_PRINT_VTABLE_SETUP,
320 "log processing of class vtables");
321 OPTION(PrintVtableImages, OBJC_PRINT_VTABLE_IMAGES,
322 "print vtable images showing overridden methods");
323 OPTION(PrintCaches, OBJC_PRINT_CACHE_SETUP,
324 "log processing of method caches");
325 OPTION(PrintFuture, OBJC_PRINT_FUTURE_CLASSES,
326 "log use of future classes for toll-free bridging");
327 OPTION(PrintGC, OBJC_PRINT_GC,
328 "log some GC operations");
329 OPTION(PrintPreopt, OBJC_PRINT_PREOPTIMIZATION,
330 "log preoptimization courtesy of dyld shared cache");
331 OPTION(PrintCxxCtors, OBJC_PRINT_CXX_CTORS,
332 "log calls to C++ ctors and dtors for instance variables");
333 OPTION(PrintExceptions, OBJC_PRINT_EXCEPTIONS,
334 "log exception handling");
335 OPTION(PrintExceptionThrow, OBJC_PRINT_EXCEPTION_THROW,
336 "log backtrace of every objc_exception_throw()");
337 OPTION(PrintAltHandlers, OBJC_PRINT_ALT_HANDLERS,
338 "log processing of exception alt handlers");
339 OPTION(PrintReplacedMethods, OBJC_PRINT_REPLACED_METHODS,
340 "log methods replaced by category implementations");
341 OPTION(PrintDeprecation, OBJC_PRINT_DEPRECATION_WARNINGS,
342 "warn about calls to deprecated runtime functions");
343 OPTION(PrintPoolHiwat, OBJC_PRINT_POOL_HIGHWATER,
344 "log high-water marks for autorelease pools");
345 OPTION(PrintCustomRR, OBJC_PRINT_CUSTOM_RR,
346 "log classes with un-optimized custom retain/release methods");
347 OPTION(PrintCustomAWZ, OBJC_PRINT_CUSTOM_AWZ,
348 "log classes with un-optimized custom allocWithZone methods");
349
350 OPTION(DebugUnload, OBJC_DEBUG_UNLOAD,
351 "warn about poorly-behaving bundles when unloaded");
352 OPTION(DebugFragileSuperclasses, OBJC_DEBUG_FRAGILE_SUPERCLASSES,
353 "warn about subclasses that may have been broken by subsequent changes to superclasses");
354 OPTION(DebugFinalizers, OBJC_DEBUG_FINALIZERS,
355 "warn about classes that implement -dealloc but not -finalize");
356 OPTION(DebugNilSync, OBJC_DEBUG_NIL_SYNC,
357 "warn about @synchronized(nil), which does no synchronization");
358 OPTION(DebugNonFragileIvars, OBJC_DEBUG_NONFRAGILE_IVARS,
359 "capriciously rearrange non-fragile ivars");
360 OPTION(DebugAltHandlers, OBJC_DEBUG_ALT_HANDLERS,
361 "record more info about bad alt handler use");
362
363 OPTION(UseInternalZone, OBJC_USE_INTERNAL_ZONE,
364 "allocate runtime data in a dedicated malloc zone");
365
366 OPTION(DisableGC, OBJC_DISABLE_GC,
367 "force GC OFF, even if the executable wants it on");
368 OPTION(DisableVtables, OBJC_DISABLE_VTABLES,
369 "disable vtable dispatch");
370 OPTION(DisablePreopt, OBJC_DISABLE_PREOPTIMIZATION,
371 "disable preoptimization courtesy of dyld shared cache");
372
373 #undef OPTION
374 #endif
375 }
376
377
378 /***********************************************************************
379 * logReplacedMethod
380 * OBJC_PRINT_REPLACED_METHODS implementation
381 **********************************************************************/
382 void
383 logReplacedMethod(const char *className, SEL s,
384 BOOL isMeta, const char *catName,
385 IMP oldImp, IMP newImp)
386 {
387 const char *oldImage = "??";
388 const char *newImage = "??";
389
390 // Silently ignore +load replacement because category +load is special
391 if (s == SEL_load) return;
392
393 #if TARGET_OS_WIN32
394 // don't know dladdr()/dli_fname equivalent
395 #else
396 Dl_info dl;
397
398 if (dladdr((void*)oldImp, &dl) && dl.dli_fname) oldImage = dl.dli_fname;
399 if (dladdr((void*)newImp, &dl) && dl.dli_fname) newImage = dl.dli_fname;
400 #endif
401
402 _objc_inform("REPLACED: %c[%s %s] %s%s (IMP was %p (%s), now %p (%s))",
403 isMeta ? '+' : '-', className, sel_getName(s),
404 catName ? "by category " : "", catName ? catName : "",
405 oldImp, oldImage, newImp, newImage);
406 }
407
408
409
410 /***********************************************************************
411 * objc_setMultithreaded.
412 **********************************************************************/
413 void objc_setMultithreaded (BOOL flag)
414 {
415 OBJC_WARN_DEPRECATED;
416
417 // Nothing here. Thread synchronization in the runtime is always active.
418 }
419
420
421 /***********************************************************************
422 * _objc_fetch_pthread_data
423 * Fetch objc's pthread data for this thread.
424 * If the data doesn't exist yet and create is NO, return NULL.
425 * If the data doesn't exist yet and create is YES, allocate and return it.
426 **********************************************************************/
427 _objc_pthread_data *_objc_fetch_pthread_data(BOOL create)
428 {
429 _objc_pthread_data *data;
430
431 data = (_objc_pthread_data *)tls_get(_objc_pthread_key);
432 if (!data && create) {
433 data = (_objc_pthread_data *)
434 _calloc_internal(1, sizeof(_objc_pthread_data));
435 tls_set(_objc_pthread_key, data);
436 }
437
438 return data;
439 }
440
441
442 /***********************************************************************
443 * _objc_pthread_destroyspecific
444 * Destructor for objc's per-thread data.
445 * arg shouldn't be NULL, but we check anyway.
446 **********************************************************************/
447 extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
448 void _objc_pthread_destroyspecific(void *arg)
449 {
450 _objc_pthread_data *data = (_objc_pthread_data *)arg;
451 if (data != NULL) {
452 _destroyInitializingClassList(data->initializingClasses);
453 _destroySyncCache(data->syncCache);
454 _destroyAltHandlerList(data->handlerList);
455
456 // add further cleanup here...
457
458 _free_internal(data);
459 }
460 }
461
462
463 void tls_init(void)
464 {
465 #if SUPPORT_DIRECT_THREAD_KEYS
466 _objc_pthread_key = TLS_DIRECT_KEY;
467 pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);
468 #else
469 _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);
470 #endif
471 }
472
473
474 /***********************************************************************
475 * _objcInit
476 * Former library initializer. This function is now merely a placeholder
477 * for external callers. All runtime initialization has now been moved
478 * to map_images() and _objc_init.
479 **********************************************************************/
480 void _objcInit(void)
481 {
482 // do nothing
483 }
484
485
486 #if !(TARGET_OS_WIN32 || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)
487 /***********************************************************************
488 * _objc_setNilReceiver
489 **********************************************************************/
490 id _objc_setNilReceiver(id newNilReceiver)
491 {
492 id oldNilReceiver;
493
494 oldNilReceiver = _objc_nilReceiver;
495 _objc_nilReceiver = newNilReceiver;
496
497 return oldNilReceiver;
498 }
499
500 /***********************************************************************
501 * _objc_getNilReceiver
502 **********************************************************************/
503 id _objc_getNilReceiver(void)
504 {
505 return _objc_nilReceiver;
506 }
507 #endif
508
509
510 /***********************************************************************
511 * objc_setForwardHandler
512 **********************************************************************/
513 void objc_setForwardHandler(void *fwd, void *fwd_stret)
514 {
515 _objc_forward_handler = fwd;
516 _objc_forward_stret_handler = fwd_stret;
517 }
518
519
520 #if defined(__i386__) || defined(__x86_64__)
521
522 /**********************************************************************
523 * objc_branch_size
524 * Returns the number of BYTES needed
525 * for a branch from entry to target.
526 **********************************************************************/
527 size_t objc_branch_size(void *entry, void *target)
528 {
529 return objc_cond_branch_size(entry, target, COND_ALWAYS);
530 }
531
532 size_t
533 objc_cond_branch_size(void *entry, void *target, unsigned cond)
534 {
535 // For simplicity, always use 32-bit relative jumps.
536 if (cond == COND_ALWAYS) return 5;
537 else return 6;
538 }
539
540 /**********************************************************************
541 * objc_write_branch
542 * Writes at entry an i386 branch instruction sequence that branches to target.
543 * The sequence written will be objc_branch_size(entry, target) BYTES.
544 * Returns the number of BYTES written.
545 **********************************************************************/
546 size_t objc_write_branch(void *entry, void *target)
547 {
548 return objc_write_cond_branch(entry, target, COND_ALWAYS);
549 }
550
551 size_t
552 objc_write_cond_branch(void *entry, void *target, unsigned cond)
553 {
554 uint8_t *address = (uint8_t *)entry; // instructions written to here
555 intptr_t destination = (intptr_t)target; // branch dest as absolute address
556 intptr_t displacement = (intptr_t)destination - ((intptr_t)address + objc_cond_branch_size(entry, target, cond)); // branch dest as relative offset
557
558 // For simplicity, always use 32-bit relative jumps
559 if (cond != COND_ALWAYS) {
560 *address++ = 0x0f; // Jcc prefix
561 }
562 *address++ = cond;
563 *address++ = displacement & 0xff;
564 *address++ = (displacement >> 8) & 0xff;
565 *address++ = (displacement >> 16) & 0xff;
566 *address++ = (displacement >> 24) & 0xff;
567
568 return address - (uint8_t *)entry;
569 }
570
571 // defined __i386__
572 #endif
573
574
575
576
577 #if !__OBJC2__
578 // GrP fixme
579 OBJC_EXTERN Class _objc_getOrigClass(const char *name);
580 #endif
581 const char *class_getImageName(Class cls)
582 {
583 #if TARGET_OS_WIN32
584 TCHAR *szFileName;
585 DWORD charactersCopied;
586 Class origCls;
587 HMODULE classModule;
588 BOOL res;
589 #endif
590 if (!cls) return NULL;
591
592 #if !__OBJC2__
593 cls = _objc_getOrigClass(_class_getName(cls));
594 #endif
595 #if TARGET_OS_WIN32
596 charactersCopied = 0;
597 szFileName = malloc(MAX_PATH * sizeof(TCHAR));
598
599 origCls = objc_getOrigClass(class_getName(cls));
600 classModule = NULL;
601 res = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)origCls, &classModule);
602 if (res && classModule) {
603 charactersCopied = GetModuleFileName(classModule, szFileName, MAX_PATH * sizeof(TCHAR));
604 }
605 if (classModule) FreeLibrary(classModule);
606 if (charactersCopied) {
607 return (const char *)szFileName;
608 } else
609 free(szFileName);
610 return NULL;
611 #else
612 return dyld_image_path_containing_address(cls);
613 #endif
614 }
615
616
617 const char **objc_copyImageNames(unsigned int *outCount)
618 {
619 header_info *hi;
620 int count = 0;
621 int max = HeaderCount;
622 #if TARGET_OS_WIN32
623 const TCHAR **names = (const TCHAR **)calloc(max+1, sizeof(TCHAR *));
624 #else
625 const char **names = (const char **)calloc(max+1, sizeof(char *));
626 #endif
627
628 for (hi = FirstHeader; hi != NULL && count < max; hi = hi->next) {
629 #if TARGET_OS_WIN32
630 if (hi->moduleName) {
631 names[count++] = hi->moduleName;
632 }
633 #else
634 if (hi->fname) {
635 names[count++] = hi->fname;
636 }
637 #endif
638 }
639 names[count] = NULL;
640
641 if (count == 0) {
642 // Return NULL instead of empty list if there are no images
643 free((void *)names);
644 names = NULL;
645 }
646
647 if (outCount) *outCount = count;
648 return names;
649 }
650
651
652 /**********************************************************************
653 *
654 **********************************************************************/
655 const char **
656 objc_copyClassNamesForImage(const char *image, unsigned int *outCount)
657 {
658 header_info *hi;
659
660 if (!image) {
661 if (outCount) *outCount = 0;
662 return NULL;
663 }
664
665 // Find the image.
666 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
667 #if TARGET_OS_WIN32
668 if (0 == wcscmp((TCHAR *)image, hi->moduleName)) break;
669 #else
670 if (0 == strcmp(image, hi->fname)) break;
671 #endif
672 }
673
674 if (!hi) {
675 if (outCount) *outCount = 0;
676 return NULL;
677 }
678
679 return _objc_copyClassNamesForImage(hi, outCount);
680 }
681
682
683 /**********************************************************************
684 * Fast Enumeration Support
685 **********************************************************************/
686
687 static void (*enumerationMutationHandler)(id);
688
689 /**********************************************************************
690 * objc_enumerationMutation
691 * called by compiler when a mutation is detected during foreach iteration
692 **********************************************************************/
693 void objc_enumerationMutation(id object) {
694 if (enumerationMutationHandler == nil) {
695 _objc_fatal("mutation detected during 'for(... in ...)' enumeration of object %p.", object);
696 }
697 (*enumerationMutationHandler)(object);
698 }
699
700
701 /**********************************************************************
702 * objc_setEnumerationMutationHandler
703 * an entry point to customize mutation error handing
704 **********************************************************************/
705 void objc_setEnumerationMutationHandler(void (*handler)(id)) {
706 enumerationMutationHandler = handler;
707 }
708
709
710 /**********************************************************************
711 * Associative Reference Support
712 **********************************************************************/
713
714 #if SUPPORT_GC
715 id objc_getAssociatedObject_gc(id object, const void *key) {
716 return (id)auto_zone_get_associative_ref(gc_zone, object, (void *)key);
717 }
718 #endif
719
720 id objc_getAssociatedObject_non_gc(id object, const void *key) {
721 return _object_get_associative_reference(object, (void *)key);
722 }
723
724 id objc_getAssociatedObject(id object, const void *key) {
725 #if SUPPORT_GC
726 if (UseGC) {
727 return (id)auto_zone_get_associative_ref(gc_zone, object, (void *)key);
728 } else
729 #endif
730 {
731 return _object_get_associative_reference(object, (void *)key);
732 }
733 }
734
735 #if SUPPORT_GC
736 void objc_setAssociatedObject_gc(id object, const void *key, id value, objc_AssociationPolicy policy) {
737 if ((policy & OBJC_ASSOCIATION_COPY_NONATOMIC) == OBJC_ASSOCIATION_COPY_NONATOMIC) {
738 value = ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy);
739 }
740 auto_zone_set_associative_ref(gc_zone, object, (void *)key, value);
741 }
742 #endif
743
744 void objc_setAssociatedObject_non_gc(id object, const void *key, id value, objc_AssociationPolicy policy) {
745 _object_set_associative_reference(object, (void *)key, value, policy);
746 }
747
748 void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) {
749 #if SUPPORT_GC
750 if (UseGC) {
751 if ((policy & OBJC_ASSOCIATION_COPY_NONATOMIC) == OBJC_ASSOCIATION_COPY_NONATOMIC) {
752 value = ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy);
753 }
754 auto_zone_set_associative_ref(gc_zone, object, (void *)key, value);
755 } else
756 #endif
757 {
758 // Note, creates a retained reference in non-GC.
759 _object_set_associative_reference(object, (void *)key, value, policy);
760 }
761 }
762
763 void objc_removeAssociatedObjects(id object) {
764 #if SUPPORT_GC
765 if (UseGC) {
766 auto_zone_erase_associative_refs(gc_zone, object);
767 } else
768 #endif
769 {
770 if (_class_instancesHaveAssociatedObjects(_object_getClass(object))) _object_remove_assocations(object);
771 }
772 }
773
774 BOOL class_instancesHaveAssociatedObjects(Class cls) {
775 return _class_instancesHaveAssociatedObjects(cls);
776 }
777
778
779 /**********************************************************************
780 * Debugger mode
781 *
782 * Debugger mode is used when gdb wants to call runtime functions
783 * and other methods while other threads are stopped. The runtime
784 * provides best-effort functionality while avoiding deadlocks
785 * with the stopped threads. gdb is responsible for ensuring that all
786 * threads but one stay stopped.
787 *
788 * When debugger mode starts, the runtime acquires as many locks as
789 * it can. Any locks that can't be acquired are off-limits until
790 * debugger mode ends. The locking functions in objc-os.h check each
791 * operation and halt if a disallowed lock is used; gdb catches that
792 * trap and cleans up.
793 *
794 * Each ABI is responsible for tracking its locks. Any lock not
795 * handled there is a potential gdb deadlock.
796 **********************************************************************/
797
798 #if SUPPORT_DEBUGGER_MODE
799
800 int DebuggerMode = DEBUGGER_OFF;
801 objc_thread_t DebuggerModeThread = 0;
802 static int DebuggerModeCount;
803
804 /**********************************************************************
805 * gdb_objc_startDebuggerMode
806 * Start debugger mode by taking locks. Return 0 if not enough locks
807 * could be acquired.
808 **********************************************************************/
809 int gdb_objc_startDebuggerMode(uint32_t flags)
810 {
811 BOOL wantFull = flags & OBJC_DEBUGMODE_FULL;
812 if (! DebuggerMode) {
813 // Start debugger mode
814 int mode = startDebuggerMode(); // Do this FIRST
815 if (mode == DEBUGGER_OFF) {
816 // sorry
817 return 0;
818 }
819 else if (mode == DEBUGGER_PARTIAL && wantFull) {
820 // not good enough
821 endDebuggerMode();
822 return 0;
823 }
824 else {
825 // w00t
826 DebuggerMode = mode;
827 DebuggerModeCount = 1;
828 DebuggerModeThread = thread_self();
829 return 1;
830 }
831 }
832 else if (DebuggerMode == DEBUGGER_PARTIAL && wantFull) {
833 // Debugger mode already active, but not as requested - sorry
834 return 0;
835 }
836 else {
837 // Debugger mode already active as requested
838 if (thread_self() == DebuggerModeThread) {
839 DebuggerModeCount++;
840 return 1;
841 } else {
842 _objc_inform("DEBUGGER MODE: debugger is buggy: can't run "
843 "debugger mode from two threads!");
844 return 0;
845 }
846 }
847 }
848
849
850 /**********************************************************************
851 * gdb_objc_endDebuggerMode
852 * Relinquish locks and end debugger mode.
853 **********************************************************************/
854 void gdb_objc_endDebuggerMode(void)
855 {
856 if (DebuggerMode && thread_self() == DebuggerModeThread) {
857 if (--DebuggerModeCount == 0) {
858 DebuggerMode = NO;
859 DebuggerModeThread = 0;
860 endDebuggerMode(); // Do this LAST
861 }
862 } else {
863 _objc_inform("DEBUGGER MODE: debugger is buggy: debugger mode "
864 "not active for this thread!");
865 }
866 }
867
868
869 /**********************************************************************
870 * gdb_objc_debuggerModeFailure
871 * Breakpoint hook for gdb when debugger mode can't finish something
872 **********************************************************************/
873 void gdb_objc_debuggerModeFailure(void)
874 {
875 _objc_fatal("DEBUGGER MODE: failed");
876 }
877
878 // SUPPORT_DEBUGGER_MODE
879 #endif