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
97 uint32_t AppSDKVersion = 0;
100 /***********************************************************************
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!
105 **********************************************************************/
106 Class objc_getClass(const char *aClassName)
108 if (!aClassName) return Nil;
110 // NO unconnected, YES class handler
111 return look_up_class(aClassName, NO, YES);
115 /***********************************************************************
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.
120 **********************************************************************/
121 Class objc_getRequiredClass(const char *aClassName)
123 Class cls = objc_getClass(aClassName);
124 if (!cls) _objc_fatal("link error: class '%s' not found.", aClassName);
129 /***********************************************************************
130 * objc_lookUpClass. Return the id of the named class.
131 * If the class does not exist, call _objc_classLoader, which may create
134 * Formerly objc_getClassWithoutWarning ()
135 **********************************************************************/
136 Class objc_lookUpClass(const char *aClassName)
138 if (!aClassName) return Nil;
140 // NO unconnected, NO class handler
141 return look_up_class(aClassName, NO, NO);
145 /***********************************************************************
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!
148 **********************************************************************/
149 Class objc_getMetaClass(const char *aClassName)
153 if (!aClassName) return Nil;
155 cls = objc_getClass (aClassName);
158 _objc_inform ("class `%s' not linked into application", aClassName);
166 /***********************************************************************
167 * appendHeader. Add a newly-constructed header_info to the list.
168 **********************************************************************/
169 void appendHeader(header_info *hi)
171 // Add the header to the header list.
172 // The header is appended to the list, to preserve the bottom-up order.
177 FirstHeader = LastHeader = hi;
180 // list is not empty, but LastHeader is invalid - recompute it
181 LastHeader = FirstHeader;
182 while (LastHeader->next) LastHeader = LastHeader->next;
184 // LastHeader is now valid
185 LastHeader->next = hi;
191 /***********************************************************************
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.
197 **********************************************************************/
198 void removeHeader(header_info *hi)
202 for (hiP = &FirstHeader; *hiP != NULL; hiP = &(**hiP).next) {
204 header_info *deadHead = *hiP;
206 // Remove from the linked list (updating FirstHeader if necessary).
209 // Update LastHeader if necessary.
210 if (LastHeader == deadHead) {
211 LastHeader = NULL; // will be recomputed next time it's used
221 /***********************************************************************
223 * Read environment variables that affect the runtime.
224 * Also print environment variable help, if requested.
225 **********************************************************************/
226 void environ_init(void)
229 // All environment variables are silently ignored when setuid or setgid
230 // This includes OBJC_HELP and OBJC_PRINT_OPTIONS themselves.
234 bool PrintHelp = false;
235 bool PrintOptions = false;
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;
242 if (0 == strncmp(*p, "OBJC_HELP=", 10)) {
246 if (0 == strncmp(*p, "OBJC_PRINT_OPTIONS=", 19)) {
251 const char *value = strchr(*p, '=');
252 if (!*value) continue;
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))
260 *opt->var = (0 == strcmp(value, "YES"));
266 // Print OBJC_HELP and OBJC_PRINT_OPTIONS output.
267 if (PrintHelp || PrintOptions) {
269 _objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");
270 _objc_inform("OBJC_HELP: describe available environment variables");
272 _objc_inform("OBJC_HELP is set");
274 _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
277 _objc_inform("OBJC_PRINT_OPTIONS is set");
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);
289 /***********************************************************************
291 * OBJC_PRINT_REPLACED_METHODS implementation
292 **********************************************************************/
294 logReplacedMethod(const char *className, SEL s,
295 BOOL isMeta, const char *catName,
296 IMP oldImp, IMP newImp)
298 const char *oldImage = "??";
299 const char *newImage = "??";
301 // Silently ignore +load replacement because category +load is special
302 if (s == SEL_load) return;
305 // don't know dladdr()/dli_fname equivalent
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;
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);
321 /***********************************************************************
322 * objc_setMultithreaded.
323 **********************************************************************/
324 void objc_setMultithreaded (BOOL flag)
326 OBJC_WARN_DEPRECATED;
328 // Nothing here. Thread synchronization in the runtime is always active.
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 **********************************************************************/
338 _objc_pthread_data *_objc_fetch_pthread_data(BOOL create)
340 _objc_pthread_data *data;
342 data = (_objc_pthread_data *)tls_get(_objc_pthread_key);
343 if (!data && create) {
344 data = (_objc_pthread_data *)
345 _calloc_internal(1, sizeof(_objc_pthread_data));
346 tls_set(_objc_pthread_key, data);
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);
359 void _objc_pthread_destroyspecific(void *arg)
361 _objc_pthread_data *data = (_objc_pthread_data *)arg;
363 _destroyInitializingClassList(data->initializingClasses);
364 _destroySyncCache(data->syncCache);
365 _destroyAltHandlerList(data->handlerList);
366 for (int i = 0; i < (int)countof(data->printableNames); i++) {
367 if (data->printableNames[i]) {
368 free(data->printableNames[i]);
372 // add further cleanup here...
374 _free_internal(data);
381 #if SUPPORT_DIRECT_THREAD_KEYS
382 _objc_pthread_key = TLS_DIRECT_KEY;
383 pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);
385 _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);
390 /***********************************************************************
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.
395 **********************************************************************/
402 /***********************************************************************
403 * objc_setForwardHandler
404 **********************************************************************/
408 // Default forward handler (nil) goes to forward:: dispatch.
409 void *_objc_forward_handler = nil;
410 void *_objc_forward_stret_handler = nil;
414 // Default forward handler halts the process.
415 __attribute__((noreturn)) void
416 objc_defaultForwardHandler(id self, SEL sel)
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);
423 void *_objc_forward_handler = (void*)objc_defaultForwardHandler;
426 struct stret { int i[100]; };
427 __attribute__((noreturn)) struct stret
428 objc_defaultForwardStretHandler(id self, SEL sel)
430 objc_defaultForwardHandler(self, sel);
432 void *_objc_forward_stret_handler = (void*)objc_defaultForwardStretHandler;
437 void objc_setForwardHandler(void *fwd, void *fwd_stret)
439 _objc_forward_handler = fwd;
441 _objc_forward_stret_handler = fwd_stret;
448 extern "C" Class _objc_getOrigClass(const char *name);
450 const char *class_getImageName(Class cls)
454 DWORD charactersCopied;
459 if (!cls) return NULL;
462 cls = _objc_getOrigClass(cls->demangledName());
465 charactersCopied = 0;
466 szFileName = malloc(MAX_PATH * sizeof(TCHAR));
468 origCls = objc_getOrigClass(cls->demangledName());
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));
474 if (classModule) FreeLibrary(classModule);
475 if (charactersCopied) {
476 return (const char *)szFileName;
482 return dyld_image_path_containing_address(cls);
487 const char **objc_copyImageNames(unsigned int *outCount)
491 int max = HeaderCount;
493 const TCHAR **names = (const TCHAR **)calloc(max+1, sizeof(TCHAR *));
495 const char **names = (const char **)calloc(max+1, sizeof(char *));
498 for (hi = FirstHeader; hi != NULL && count < max; hi = hi->next) {
500 if (hi->moduleName) {
501 names[count++] = hi->moduleName;
505 names[count++] = hi->fname;
512 // Return NULL instead of empty list if there are no images
517 if (outCount) *outCount = count;
522 /**********************************************************************
524 **********************************************************************/
526 objc_copyClassNamesForImage(const char *image, unsigned int *outCount)
531 if (outCount) *outCount = 0;
536 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
538 if (0 == wcscmp((TCHAR *)image, hi->moduleName)) break;
540 if (0 == strcmp(image, hi->fname)) break;
545 if (outCount) *outCount = 0;
549 return _objc_copyClassNamesForImage(hi, outCount);
553 /**********************************************************************
554 * Fast Enumeration Support
555 **********************************************************************/
557 static void (*enumerationMutationHandler)(id);
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) {
565 _objc_fatal("mutation detected during 'for(... in ...)' enumeration of object %p.", (void*)object);
567 (*enumerationMutationHandler)(object);
571 /**********************************************************************
572 * objc_setEnumerationMutationHandler
573 * an entry point to customize mutation error handing
574 **********************************************************************/
575 void objc_setEnumerationMutationHandler(void (*handler)(id)) {
576 enumerationMutationHandler = handler;
580 /**********************************************************************
581 * Associative Reference Support
582 **********************************************************************/
584 id objc_getAssociatedObject_non_gc(id object, const void *key) {
585 return _object_get_associative_reference(object, (void *)key);
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);
596 id objc_getAssociatedObject_gc(id object, const void *key) {
597 return (id)auto_zone_get_associative_ref(gc_zone, object, (void *)key);
600 void objc_setAssociatedObject_gc(id object, const void *key, id value, objc_AssociationPolicy policy) {
601 if ((policy & OBJC_ASSOCIATION_COPY_NONATOMIC) == OBJC_ASSOCIATION_COPY_NONATOMIC) {
602 value = ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy);
604 auto_zone_set_associative_ref(gc_zone, object, (void *)key, value);
607 // objc_setAssociatedObject and objc_getAssociatedObject are
608 // resolver functions in objc-auto.mm.
613 objc_getAssociatedObject(id object, const void *key)
615 return objc_getAssociatedObject_non_gc(object, key);
619 objc_setAssociatedObject(id object, const void *key, id value,
620 objc_AssociationPolicy policy)
622 objc_setAssociatedObject_non_gc(object, key, value, policy);
628 void objc_removeAssociatedObjects(id object)
632 auto_zone_erase_associative_refs(gc_zone, object);
636 if (object && object->hasAssociatedObjects()) {
637 _object_remove_assocations(object);