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;
84 SEL SEL_finalize = NULL;
85 SEL SEL_forwardInvocation = NULL;
87 header_info *FirstHeader = 0; // NULL means empty list
88 header_info *LastHeader = 0; // NULL means invalid; recompute it
93 /***********************************************************************
94 * objc_getClass. Return the id of the named class. If the class does
95 * not exist, call _objc_classLoader and then objc_classHandler, either of
96 * which may create a new class.
97 * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
98 **********************************************************************/
99 Class objc_getClass(const char *aClassName)
101 if (!aClassName) return Nil;
103 // NO unconnected, YES class handler
104 return look_up_class(aClassName, NO, YES);
108 /***********************************************************************
109 * objc_getRequiredClass.
110 * Same as objc_getClass, but kills the process if the class is not found.
111 * This is used by ZeroLink, where failing to find a class would be a
112 * compile-time link error without ZeroLink.
113 **********************************************************************/
114 Class objc_getRequiredClass(const char *aClassName)
116 Class cls = objc_getClass(aClassName);
117 if (!cls) _objc_fatal("link error: class '%s' not found.", aClassName);
122 /***********************************************************************
123 * objc_lookUpClass. Return the id of the named class.
124 * If the class does not exist, call _objc_classLoader, which may create
127 * Formerly objc_getClassWithoutWarning ()
128 **********************************************************************/
129 Class objc_lookUpClass(const char *aClassName)
131 if (!aClassName) return Nil;
133 // NO unconnected, NO class handler
134 return look_up_class(aClassName, NO, NO);
137 /***********************************************************************
138 * objc_getFutureClass. Return the id of the named class.
139 * If the class does not exist, return an uninitialized class
140 * structure that will be used for the class when and if it
143 **********************************************************************/
144 Class objc_getFutureClass(const char *name)
148 // YES unconnected, NO class handler
149 // (unconnected is OK because it will someday be the real class)
150 cls = look_up_class(name, YES, NO);
153 _objc_inform("FUTURE: found %p already in use for %s",
159 // No class or future class with that name yet. Make one.
160 // fixme not thread-safe with respect to
161 // simultaneous library load or getFutureClass.
162 return _objc_allocateFutureClass(name);
166 /***********************************************************************
167 * objc_getMetaClass. Return the id of the meta class the named class.
168 * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
169 **********************************************************************/
170 Class objc_getMetaClass(const char *aClassName)
174 if (!aClassName) return Nil;
176 cls = objc_getClass (aClassName);
179 _objc_inform ("class `%s' not linked into application", aClassName);
187 /***********************************************************************
188 * appendHeader. Add a newly-constructed header_info to the list.
189 **********************************************************************/
190 void appendHeader(header_info *hi)
192 // Add the header to the header list.
193 // The header is appended to the list, to preserve the bottom-up order.
198 FirstHeader = LastHeader = hi;
201 // list is not empty, but LastHeader is invalid - recompute it
202 LastHeader = FirstHeader;
203 while (LastHeader->next) LastHeader = LastHeader->next;
205 // LastHeader is now valid
206 LastHeader->next = hi;
212 /***********************************************************************
214 * Remove the given header from the header list.
215 * FirstHeader is updated.
216 * LastHeader is set to NULL. Any code that uses LastHeader must
217 * detect this NULL and recompute LastHeader by traversing the list.
218 **********************************************************************/
219 void removeHeader(header_info *hi)
223 for (hiP = &FirstHeader; *hiP != NULL; hiP = &(**hiP).next) {
225 header_info *deadHead = *hiP;
227 // Remove from the linked list (updating FirstHeader if necessary).
230 // Update LastHeader if necessary.
231 if (LastHeader == deadHead) {
232 LastHeader = NULL; // will be recomputed next time it's used
242 /***********************************************************************
244 * Read environment variables that affect the runtime.
245 * Also print environment variable help, if requested.
246 **********************************************************************/
247 void environ_init(void)
250 // All environment variables are silently ignored when setuid or setgid
251 // This includes OBJC_HELP and OBJC_PRINT_OPTIONS themselves.
255 bool PrintHelp = false;
256 bool PrintOptions = false;
258 // Scan environ[] directly instead of calling getenv() a lot.
259 // This optimizes the case where none are set.
260 for (char **p = *_NSGetEnviron(); *p != nil; p++) {
261 if (0 != strncmp(*p, "OBJC_", 5)) continue;
263 if (0 == strncmp(*p, "OBJC_HELP=", 10)) {
267 if (0 == strncmp(*p, "OBJC_PRINT_OPTIONS=", 19)) {
272 const char *value = strchr(*p, '=');
273 if (!*value) continue;
276 for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
277 const option_t *opt = &Settings[i];
278 if ((size_t)(value - *p) == 1+opt->envlen &&
279 0 == strncmp(*p, opt->env, opt->envlen))
281 *opt->var = (0 == strcmp(value, "YES"));
287 // Print OBJC_HELP and OBJC_PRINT_OPTIONS output.
288 if (PrintHelp || PrintOptions) {
290 _objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");
291 _objc_inform("OBJC_HELP: describe available environment variables");
293 _objc_inform("OBJC_HELP is set");
295 _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
298 _objc_inform("OBJC_PRINT_OPTIONS is set");
301 for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
302 const option_t *opt = &Settings[i];
303 if (PrintHelp) _objc_inform("%s: %s", opt->env, opt->help);
304 if (PrintOptions && *opt->var) _objc_inform("%s is set", opt->env);
310 /***********************************************************************
312 * OBJC_PRINT_REPLACED_METHODS implementation
313 **********************************************************************/
315 logReplacedMethod(const char *className, SEL s,
316 BOOL isMeta, const char *catName,
317 IMP oldImp, IMP newImp)
319 const char *oldImage = "??";
320 const char *newImage = "??";
322 // Silently ignore +load replacement because category +load is special
323 if (s == SEL_load) return;
326 // don't know dladdr()/dli_fname equivalent
330 if (dladdr((void*)oldImp, &dl) && dl.dli_fname) oldImage = dl.dli_fname;
331 if (dladdr((void*)newImp, &dl) && dl.dli_fname) newImage = dl.dli_fname;
334 _objc_inform("REPLACED: %c[%s %s] %s%s (IMP was %p (%s), now %p (%s))",
335 isMeta ? '+' : '-', className, sel_getName(s),
336 catName ? "by category " : "", catName ? catName : "",
337 oldImp, oldImage, newImp, newImage);
342 /***********************************************************************
343 * objc_setMultithreaded.
344 **********************************************************************/
345 void objc_setMultithreaded (BOOL flag)
347 OBJC_WARN_DEPRECATED;
349 // Nothing here. Thread synchronization in the runtime is always active.
353 /***********************************************************************
354 * _objc_fetch_pthread_data
355 * Fetch objc's pthread data for this thread.
356 * If the data doesn't exist yet and create is NO, return NULL.
357 * If the data doesn't exist yet and create is YES, allocate and return it.
358 **********************************************************************/
359 _objc_pthread_data *_objc_fetch_pthread_data(BOOL create)
361 _objc_pthread_data *data;
363 data = (_objc_pthread_data *)tls_get(_objc_pthread_key);
364 if (!data && create) {
365 data = (_objc_pthread_data *)
366 _calloc_internal(1, sizeof(_objc_pthread_data));
367 tls_set(_objc_pthread_key, data);
374 /***********************************************************************
375 * _objc_pthread_destroyspecific
376 * Destructor for objc's per-thread data.
377 * arg shouldn't be NULL, but we check anyway.
378 **********************************************************************/
379 extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
380 void _objc_pthread_destroyspecific(void *arg)
382 _objc_pthread_data *data = (_objc_pthread_data *)arg;
384 _destroyInitializingClassList(data->initializingClasses);
385 _destroySyncCache(data->syncCache);
386 _destroyAltHandlerList(data->handlerList);
388 // add further cleanup here...
390 _free_internal(data);
397 #if SUPPORT_DIRECT_THREAD_KEYS
398 _objc_pthread_key = TLS_DIRECT_KEY;
399 pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);
401 _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);
406 /***********************************************************************
408 * Former library initializer. This function is now merely a placeholder
409 * for external callers. All runtime initialization has now been moved
410 * to map_images() and _objc_init.
411 **********************************************************************/
418 #if !(TARGET_OS_WIN32 || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)
419 /***********************************************************************
420 * _objc_setNilReceiver
421 **********************************************************************/
422 id _objc_setNilReceiver(id newNilReceiver)
426 oldNilReceiver = _objc_nilReceiver;
427 _objc_nilReceiver = newNilReceiver;
429 return oldNilReceiver;
432 /***********************************************************************
433 * _objc_getNilReceiver
434 **********************************************************************/
435 id _objc_getNilReceiver(void)
437 return _objc_nilReceiver;
442 /***********************************************************************
443 * objc_setForwardHandler
444 **********************************************************************/
445 void objc_setForwardHandler(void *fwd, void *fwd_stret)
447 _objc_forward_handler = fwd;
448 _objc_forward_stret_handler = fwd_stret;
454 extern "C" Class _objc_getOrigClass(const char *name);
456 const char *class_getImageName(Class cls)
460 DWORD charactersCopied;
465 if (!cls) return NULL;
468 cls = _objc_getOrigClass(cls->getName());
471 charactersCopied = 0;
472 szFileName = malloc(MAX_PATH * sizeof(TCHAR));
474 origCls = objc_getOrigClass(cls->getName());
476 res = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)origCls, &classModule);
477 if (res && classModule) {
478 charactersCopied = GetModuleFileName(classModule, szFileName, MAX_PATH * sizeof(TCHAR));
480 if (classModule) FreeLibrary(classModule);
481 if (charactersCopied) {
482 return (const char *)szFileName;
488 return dyld_image_path_containing_address(cls);
493 const char **objc_copyImageNames(unsigned int *outCount)
497 int max = HeaderCount;
499 const TCHAR **names = (const TCHAR **)calloc(max+1, sizeof(TCHAR *));
501 const char **names = (const char **)calloc(max+1, sizeof(char *));
504 for (hi = FirstHeader; hi != NULL && count < max; hi = hi->next) {
506 if (hi->moduleName) {
507 names[count++] = hi->moduleName;
511 names[count++] = hi->fname;
518 // Return NULL instead of empty list if there are no images
523 if (outCount) *outCount = count;
528 /**********************************************************************
530 **********************************************************************/
532 objc_copyClassNamesForImage(const char *image, unsigned int *outCount)
537 if (outCount) *outCount = 0;
542 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
544 if (0 == wcscmp((TCHAR *)image, hi->moduleName)) break;
546 if (0 == strcmp(image, hi->fname)) break;
551 if (outCount) *outCount = 0;
555 return _objc_copyClassNamesForImage(hi, outCount);
559 /**********************************************************************
560 * Fast Enumeration Support
561 **********************************************************************/
563 static void (*enumerationMutationHandler)(id);
565 /**********************************************************************
566 * objc_enumerationMutation
567 * called by compiler when a mutation is detected during foreach iteration
568 **********************************************************************/
569 void objc_enumerationMutation(id object) {
570 if (enumerationMutationHandler == nil) {
571 _objc_fatal("mutation detected during 'for(... in ...)' enumeration of object %p.", (void*)object);
573 (*enumerationMutationHandler)(object);
577 /**********************************************************************
578 * objc_setEnumerationMutationHandler
579 * an entry point to customize mutation error handing
580 **********************************************************************/
581 void objc_setEnumerationMutationHandler(void (*handler)(id)) {
582 enumerationMutationHandler = handler;
586 /**********************************************************************
587 * Associative Reference Support
588 **********************************************************************/
590 id objc_getAssociatedObject_non_gc(id object, const void *key) {
591 return _object_get_associative_reference(object, (void *)key);
595 void objc_setAssociatedObject_non_gc(id object, const void *key, id value, objc_AssociationPolicy policy) {
596 _object_set_associative_reference(object, (void *)key, value, policy);
602 id objc_getAssociatedObject_gc(id object, const void *key) {
603 return (id)auto_zone_get_associative_ref(gc_zone, object, (void *)key);
606 void objc_setAssociatedObject_gc(id object, const void *key, id value, objc_AssociationPolicy policy) {
607 if ((policy & OBJC_ASSOCIATION_COPY_NONATOMIC) == OBJC_ASSOCIATION_COPY_NONATOMIC) {
608 value = ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy);
610 auto_zone_set_associative_ref(gc_zone, object, (void *)key, value);
613 // objc_setAssociatedObject and objc_getAssociatedObject are
614 // resolver functions in objc-auto.mm.
619 objc_getAssociatedObject(id object, const void *key)
621 return objc_getAssociatedObject_non_gc(object, key);
625 objc_setAssociatedObject(id object, const void *key, id value,
626 objc_AssociationPolicy policy)
628 objc_setAssociatedObject_non_gc(object, key, value, policy);
634 void objc_removeAssociatedObjects(id object)
638 auto_zone_erase_associative_refs(gc_zone, object);
642 if (object && object->getIsa()->instancesHaveAssociatedObjects()) {
643 _object_remove_assocations(object);