2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 /***********************************************************************
25 * Copyright 1988-1996, NeXT Software, Inc.
28 **********************************************************************/
32 /***********************************************************************
34 **********************************************************************/
36 #include "objc-private.h"
37 #include "objc-loadmethod.h"
40 OBJC_EXPORT Class getOriginalClassForPosingClass(Class);
43 /***********************************************************************
45 **********************************************************************/
47 // Settings from environment variables
48 #define OPTION(var, env, help) bool var = false;
59 const option_t Settings[] = {
60 #define OPTION(var, env, help) option_t{&var, #env, help, strlen(#env)},
66 // objc's key for pthread_getspecific
67 static tls_key_t _objc_pthread_key;
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;
81 SEL SEL_allocWithZone = NULL;
82 SEL SEL_dealloc = NULL;
85 SEL SEL_finalize = NULL;
86 SEL SEL_forwardInvocation = NULL;
87 SEL SEL_tryRetain = NULL;
88 SEL SEL_isDeallocating = NULL;
89 SEL SEL_retainWeakReference = NULL;
90 SEL SEL_allowsWeakReference = NULL;
93 header_info *FirstHeader = 0; // NULL means empty list
94 header_info *LastHeader = 0; // NULL means invalid; recompute it
98 /***********************************************************************
99 * objc_getClass. Return the id of the named class. If the class does
100 * not exist, call _objc_classLoader and then objc_classHandler, either of
101 * which may create a new class.
102 * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
103 **********************************************************************/
104 Class objc_getClass(const char *aClassName)
106 if (!aClassName) return Nil;
108 // NO unconnected, YES class handler
109 return look_up_class(aClassName, NO, YES);
113 /***********************************************************************
114 * objc_getRequiredClass.
115 * Same as objc_getClass, but kills the process if the class is not found.
116 * This is used by ZeroLink, where failing to find a class would be a
117 * compile-time link error without ZeroLink.
118 **********************************************************************/
119 Class objc_getRequiredClass(const char *aClassName)
121 Class cls = objc_getClass(aClassName);
122 if (!cls) _objc_fatal("link error: class '%s' not found.", aClassName);
127 /***********************************************************************
128 * objc_lookUpClass. Return the id of the named class.
129 * If the class does not exist, call _objc_classLoader, which may create
132 * Formerly objc_getClassWithoutWarning ()
133 **********************************************************************/
134 Class objc_lookUpClass(const char *aClassName)
136 if (!aClassName) return Nil;
138 // NO unconnected, NO class handler
139 return look_up_class(aClassName, NO, NO);
143 /***********************************************************************
144 * objc_getMetaClass. Return the id of the meta class the named class.
145 * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
146 **********************************************************************/
147 Class objc_getMetaClass(const char *aClassName)
151 if (!aClassName) return Nil;
153 cls = objc_getClass (aClassName);
156 _objc_inform ("class `%s' not linked into application", aClassName);
164 /***********************************************************************
165 * appendHeader. Add a newly-constructed header_info to the list.
166 **********************************************************************/
167 void appendHeader(header_info *hi)
169 // Add the header to the header list.
170 // The header is appended to the list, to preserve the bottom-up order.
175 FirstHeader = LastHeader = hi;
178 // list is not empty, but LastHeader is invalid - recompute it
179 LastHeader = FirstHeader;
180 while (LastHeader->next) LastHeader = LastHeader->next;
182 // LastHeader is now valid
183 LastHeader->next = hi;
189 /***********************************************************************
191 * Remove the given header from the header list.
192 * FirstHeader is updated.
193 * LastHeader is set to NULL. Any code that uses LastHeader must
194 * detect this NULL and recompute LastHeader by traversing the list.
195 **********************************************************************/
196 void removeHeader(header_info *hi)
200 for (hiP = &FirstHeader; *hiP != NULL; hiP = &(**hiP).next) {
202 header_info *deadHead = *hiP;
204 // Remove from the linked list (updating FirstHeader if necessary).
207 // Update LastHeader if necessary.
208 if (LastHeader == deadHead) {
209 LastHeader = NULL; // will be recomputed next time it's used
219 /***********************************************************************
221 * Read environment variables that affect the runtime.
222 * Also print environment variable help, if requested.
223 **********************************************************************/
224 void environ_init(void)
227 // All environment variables are silently ignored when setuid or setgid
228 // This includes OBJC_HELP and OBJC_PRINT_OPTIONS themselves.
232 bool PrintHelp = false;
233 bool PrintOptions = false;
234 bool maybeMallocDebugging = false;
236 // Scan environ[] directly instead of calling getenv() a lot.
237 // This optimizes the case where none are set.
238 for (char **p = *_NSGetEnviron(); *p != nil; p++) {
239 if (0 == strncmp(*p, "Malloc", 6) || 0 == strncmp(*p, "DYLD", 4) ||
240 0 == strncmp(*p, "NSZombiesEnabled", 16))
242 maybeMallocDebugging = true;
245 if (0 != strncmp(*p, "OBJC_", 5)) continue;
247 if (0 == strncmp(*p, "OBJC_HELP=", 10)) {
251 if (0 == strncmp(*p, "OBJC_PRINT_OPTIONS=", 19)) {
256 const char *value = strchr(*p, '=');
257 if (!*value) continue;
260 for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
261 const option_t *opt = &Settings[i];
262 if ((size_t)(value - *p) == 1+opt->envlen &&
263 0 == strncmp(*p, opt->env, opt->envlen))
265 *opt->var = (0 == strcmp(value, "YES"));
271 // Special case: enable some autorelease pool debugging
272 // when some malloc debugging is enabled
273 // and OBJC_DEBUG_POOL_ALLOCATION is not set to something other than NO.
274 if (maybeMallocDebugging) {
275 const char *insert = getenv("DYLD_INSERT_LIBRARIES");
276 const char *zombie = getenv("NSZombiesEnabled");
277 const char *pooldebug = getenv("OBJC_DEBUG_POOL_ALLOCATION");
278 if ((getenv("MallocStackLogging")
279 || getenv("MallocStackLoggingNoCompact")
280 || (zombie && (*zombie == 'Y' || *zombie == 'y'))
281 || (insert && strstr(insert, "libgmalloc")))
283 (!pooldebug || 0 == strcmp(pooldebug, "YES")))
285 DebugPoolAllocation = true;
289 // Print OBJC_HELP and OBJC_PRINT_OPTIONS output.
290 if (PrintHelp || PrintOptions) {
292 _objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");
293 _objc_inform("OBJC_HELP: describe available environment variables");
295 _objc_inform("OBJC_HELP is set");
297 _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
300 _objc_inform("OBJC_PRINT_OPTIONS is set");
303 for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
304 const option_t *opt = &Settings[i];
305 if (PrintHelp) _objc_inform("%s: %s", opt->env, opt->help);
306 if (PrintOptions && *opt->var) _objc_inform("%s is set", opt->env);
312 /***********************************************************************
314 * OBJC_PRINT_REPLACED_METHODS implementation
315 **********************************************************************/
317 logReplacedMethod(const char *className, SEL s,
318 bool isMeta, const char *catName,
319 IMP oldImp, IMP newImp)
321 const char *oldImage = "??";
322 const char *newImage = "??";
324 // Silently ignore +load replacement because category +load is special
325 if (s == SEL_load) return;
328 // don't know dladdr()/dli_fname equivalent
332 if (dladdr((void*)oldImp, &dl) && dl.dli_fname) oldImage = dl.dli_fname;
333 if (dladdr((void*)newImp, &dl) && dl.dli_fname) newImage = dl.dli_fname;
336 _objc_inform("REPLACED: %c[%s %s] %s%s (IMP was %p (%s), now %p (%s))",
337 isMeta ? '+' : '-', className, sel_getName(s),
338 catName ? "by category " : "", catName ? catName : "",
339 oldImp, oldImage, newImp, newImage);
344 /***********************************************************************
345 * objc_setMultithreaded.
346 **********************************************************************/
347 void objc_setMultithreaded (BOOL flag)
349 OBJC_WARN_DEPRECATED;
351 // Nothing here. Thread synchronization in the runtime is always active.
355 /***********************************************************************
356 * _objc_fetch_pthread_data
357 * Fetch objc's pthread data for this thread.
358 * If the data doesn't exist yet and create is NO, return NULL.
359 * If the data doesn't exist yet and create is YES, allocate and return it.
360 **********************************************************************/
361 _objc_pthread_data *_objc_fetch_pthread_data(bool create)
363 _objc_pthread_data *data;
365 data = (_objc_pthread_data *)tls_get(_objc_pthread_key);
366 if (!data && create) {
367 data = (_objc_pthread_data *)
368 calloc(1, sizeof(_objc_pthread_data));
369 tls_set(_objc_pthread_key, data);
376 /***********************************************************************
377 * _objc_pthread_destroyspecific
378 * Destructor for objc's per-thread data.
379 * arg shouldn't be NULL, but we check anyway.
380 **********************************************************************/
381 extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
382 void _objc_pthread_destroyspecific(void *arg)
384 _objc_pthread_data *data = (_objc_pthread_data *)arg;
386 _destroyInitializingClassList(data->initializingClasses);
387 _destroySyncCache(data->syncCache);
388 _destroyAltHandlerList(data->handlerList);
389 for (int i = 0; i < (int)countof(data->printableNames); i++) {
390 if (data->printableNames[i]) {
391 free(data->printableNames[i]);
395 // add further cleanup here...
404 #if SUPPORT_DIRECT_THREAD_KEYS
405 _objc_pthread_key = TLS_DIRECT_KEY;
406 pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);
408 _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);
413 /***********************************************************************
415 * Former library initializer. This function is now merely a placeholder
416 * for external callers. All runtime initialization has now been moved
417 * to map_images() and _objc_init.
418 **********************************************************************/
425 /***********************************************************************
426 * objc_setForwardHandler
427 **********************************************************************/
431 // Default forward handler (nil) goes to forward:: dispatch.
432 void *_objc_forward_handler = nil;
433 void *_objc_forward_stret_handler = nil;
437 // Default forward handler halts the process.
438 __attribute__((noreturn)) void
439 objc_defaultForwardHandler(id self, SEL sel)
441 _objc_fatal("%c[%s %s]: unrecognized selector sent to instance %p "
442 "(no message forward handler is installed)",
443 class_isMetaClass(object_getClass(self)) ? '+' : '-',
444 object_getClassName(self), sel_getName(sel), self);
446 void *_objc_forward_handler = (void*)objc_defaultForwardHandler;
449 struct stret { int i[100]; };
450 __attribute__((noreturn)) struct stret
451 objc_defaultForwardStretHandler(id self, SEL sel)
453 objc_defaultForwardHandler(self, sel);
455 void *_objc_forward_stret_handler = (void*)objc_defaultForwardStretHandler;
460 void objc_setForwardHandler(void *fwd, void *fwd_stret)
462 _objc_forward_handler = fwd;
464 _objc_forward_stret_handler = fwd_stret;
471 extern "C" Class _objc_getOrigClass(const char *name);
473 const char *class_getImageName(Class cls)
477 DWORD charactersCopied;
482 if (!cls) return NULL;
485 cls = _objc_getOrigClass(cls->demangledName());
488 charactersCopied = 0;
489 szFileName = malloc(MAX_PATH * sizeof(TCHAR));
491 origCls = objc_getOrigClass(cls->demangledName());
493 res = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)origCls, &classModule);
494 if (res && classModule) {
495 charactersCopied = GetModuleFileName(classModule, szFileName, MAX_PATH * sizeof(TCHAR));
497 if (classModule) FreeLibrary(classModule);
498 if (charactersCopied) {
499 return (const char *)szFileName;
505 return dyld_image_path_containing_address(cls);
510 const char **objc_copyImageNames(unsigned int *outCount)
514 int max = HeaderCount;
516 const TCHAR **names = (const TCHAR **)calloc(max+1, sizeof(TCHAR *));
518 const char **names = (const char **)calloc(max+1, sizeof(char *));
521 for (hi = FirstHeader; hi != NULL && count < max; hi = hi->next) {
523 if (hi->moduleName) {
524 names[count++] = hi->moduleName;
528 names[count++] = hi->fname;
535 // Return NULL instead of empty list if there are no images
540 if (outCount) *outCount = count;
545 /**********************************************************************
547 **********************************************************************/
549 objc_copyClassNamesForImage(const char *image, unsigned int *outCount)
554 if (outCount) *outCount = 0;
559 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
561 if (0 == wcscmp((TCHAR *)image, hi->moduleName)) break;
563 if (0 == strcmp(image, hi->fname)) break;
568 if (outCount) *outCount = 0;
572 return _objc_copyClassNamesForImage(hi, outCount);
576 /**********************************************************************
577 * Fast Enumeration Support
578 **********************************************************************/
580 static void (*enumerationMutationHandler)(id);
582 /**********************************************************************
583 * objc_enumerationMutation
584 * called by compiler when a mutation is detected during foreach iteration
585 **********************************************************************/
586 void objc_enumerationMutation(id object) {
587 if (enumerationMutationHandler == nil) {
588 _objc_fatal("mutation detected during 'for(... in ...)' enumeration of object %p.", (void*)object);
590 (*enumerationMutationHandler)(object);
594 /**********************************************************************
595 * objc_setEnumerationMutationHandler
596 * an entry point to customize mutation error handing
597 **********************************************************************/
598 void objc_setEnumerationMutationHandler(void (*handler)(id)) {
599 enumerationMutationHandler = handler;
603 /**********************************************************************
604 * Associative Reference Support
605 **********************************************************************/
607 id objc_getAssociatedObject_non_gc(id object, const void *key) {
608 return _object_get_associative_reference(object, (void *)key);
612 void objc_setAssociatedObject_non_gc(id object, const void *key, id value, objc_AssociationPolicy policy) {
613 _object_set_associative_reference(object, (void *)key, value, policy);
619 id objc_getAssociatedObject_gc(id object, const void *key) {
620 // auto_zone doesn't handle tagged pointer objects. Track it ourselves.
621 if (object->isTaggedPointer()) return objc_getAssociatedObject_non_gc(object, key);
623 return (id)auto_zone_get_associative_ref(gc_zone, object, (void *)key);
626 void objc_setAssociatedObject_gc(id object, const void *key, id value, objc_AssociationPolicy policy) {
627 // auto_zone doesn't handle tagged pointer objects. Track it ourselves.
628 if (object->isTaggedPointer()) return objc_setAssociatedObject_non_gc(object, key, value, policy);
630 if ((policy & OBJC_ASSOCIATION_COPY_NONATOMIC) == OBJC_ASSOCIATION_COPY_NONATOMIC) {
631 value = ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy);
633 auto_zone_set_associative_ref(gc_zone, object, (void *)key, value);
636 // objc_setAssociatedObject and objc_getAssociatedObject are
637 // resolver functions in objc-auto.mm.
642 objc_getAssociatedObject(id object, const void *key)
644 return objc_getAssociatedObject_non_gc(object, key);
648 objc_setAssociatedObject(id object, const void *key, id value,
649 objc_AssociationPolicy policy)
651 objc_setAssociatedObject_non_gc(object, key, value, policy);
657 void objc_removeAssociatedObjects(id object)
661 auto_zone_erase_associative_refs(gc_zone, object);
665 if (object && object->hasAssociatedObjects()) {
666 _object_remove_assocations(object);