]> git.saurik.com Git - apple/objc4.git/blame - runtime/objc-runtime.mm
objc4-647.tar.gz
[apple/objc4.git] / runtime / objc-runtime.mm
CommitLineData
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 40OBJC_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
52struct option_t {
53 bool* var;
54 const char *env;
55 const char *help;
56 size_t envlen;
57};
58
59const 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 67static tls_key_t _objc_pthread_key;
2bfd4448 68
7af964d1 69// Selectors
cd5f04f5
A
70SEL SEL_load = NULL;
71SEL SEL_initialize = NULL;
72SEL SEL_resolveInstanceMethod = NULL;
73SEL SEL_resolveClassMethod = NULL;
74SEL SEL_cxx_construct = NULL;
75SEL SEL_cxx_destruct = NULL;
76SEL SEL_retain = NULL;
77SEL SEL_release = NULL;
78SEL SEL_autorelease = NULL;
79SEL SEL_retainCount = NULL;
80SEL SEL_alloc = NULL;
81SEL SEL_allocWithZone = NULL;
8070259c 82SEL SEL_dealloc = NULL;
cd5f04f5
A
83SEL SEL_copy = NULL;
84SEL SEL_new = NULL;
85SEL SEL_finalize = NULL;
86SEL SEL_forwardInvocation = NULL;
8070259c
A
87SEL SEL_tryRetain = NULL;
88SEL SEL_isDeallocating = NULL;
89SEL SEL_retainWeakReference = NULL;
90SEL SEL_allowsWeakReference = NULL;
91
cd5f04f5
A
92
93header_info *FirstHeader = 0; // NULL means empty list
94header_info *LastHeader = 0; // NULL means invalid; recompute it
95int HeaderCount = 0;
2bfd4448 96
8070259c 97uint32_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 106Class 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 121Class 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 136Class 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 149Class 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 169void 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 198void 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 226void 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 293void
7af964d1
A
294logReplacedMethod(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
324void 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**********************************************************************/
358extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
cd5f04f5 359void _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 379void 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 396void _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.
409void *_objc_forward_handler = nil;
410void *_objc_forward_stret_handler = nil;
390d5862 411
8070259c
A
412#else
413
414// Default forward handler halts the process.
415__attribute__((noreturn)) void
416objc_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 423void *_objc_forward_handler = (void*)objc_defaultForwardHandler;
13d88034 424
8070259c
A
425#if SUPPORT_STRET
426struct stret { int i[100]; };
427__attribute__((noreturn)) struct stret
428objc_defaultForwardStretHandler(id self, SEL sel)
13d88034 429{
8070259c 430 objc_defaultForwardHandler(self, sel);
13d88034 431}
8070259c 432void *_objc_forward_stret_handler = (void*)objc_defaultForwardStretHandler;
7af964d1 433#endif
13d88034 434
8070259c 435#endif
13d88034 436
b3962a83
A
437void 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 448extern "C" Class _objc_getOrigClass(const char *name);
b3962a83
A
449#endif
450const 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
487const 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**********************************************************************/
525const char **
526objc_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
557static void (*enumerationMutationHandler)(id);
558
559/**********************************************************************
560* objc_enumerationMutation
561* called by compiler when a mutation is detected during foreach iteration
562**********************************************************************/
563void 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**********************************************************************/
575void objc_setEnumerationMutationHandler(void (*handler)(id)) {
576 enumerationMutationHandler = handler;
577}
7af964d1
A
578
579
8972963c
A
580/**********************************************************************
581* Associative Reference Support
582**********************************************************************/
583
cd5f04f5 584id 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
589void 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
596id objc_getAssociatedObject_gc(id object, const void *key) {
597 return (id)auto_zone_get_associative_ref(gc_zone, object, (void *)key);
598}
599
cd5f04f5 600void 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
612id
613objc_getAssociatedObject(id object, const void *key)
614{
615 return objc_getAssociatedObject_non_gc(object, key);
8972963c
A
616}
617
7257e56c
A
618void
619objc_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
628void 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