]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-runtime.mm
objc4-647.tar.gz
[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 #define OPTION(var, env, help) bool var = false;
49 #include "objc-env.h"
50 #undef OPTION
51
52 struct option_t {
53 bool* var;
54 const char *env;
55 const char *help;
56 size_t envlen;
57 };
58
59 const 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 };
64
65
66 // objc's key for pthread_getspecific
67 static tls_key_t _objc_pthread_key;
68
69 // Selectors
70 SEL SEL_load = NULL;
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;
80 SEL SEL_alloc = NULL;
81 SEL SEL_allocWithZone = NULL;
82 SEL SEL_dealloc = NULL;
83 SEL SEL_copy = NULL;
84 SEL SEL_new = 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;
91
92
93 header_info *FirstHeader = 0; // NULL means empty list
94 header_info *LastHeader = 0; // NULL means invalid; recompute it
95 int HeaderCount = 0;
96
97 uint32_t AppSDKVersion = 0;
98
99
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)
107 {
108 if (!aClassName) return Nil;
109
110 // NO unconnected, YES class handler
111 return look_up_class(aClassName, NO, YES);
112 }
113
114
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)
122 {
123 Class cls = objc_getClass(aClassName);
124 if (!cls) _objc_fatal("link error: class '%s' not found.", aClassName);
125 return cls;
126 }
127
128
129 /***********************************************************************
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 ()
135 **********************************************************************/
136 Class objc_lookUpClass(const char *aClassName)
137 {
138 if (!aClassName) return Nil;
139
140 // NO unconnected, NO class handler
141 return look_up_class(aClassName, NO, NO);
142 }
143
144
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)
150 {
151 Class cls;
152
153 if (!aClassName) return Nil;
154
155 cls = objc_getClass (aClassName);
156 if (!cls)
157 {
158 _objc_inform ("class `%s' not linked into application", aClassName);
159 return Nil;
160 }
161
162 return cls->ISA();
163 }
164
165
166 /***********************************************************************
167 * appendHeader. Add a newly-constructed header_info to the list.
168 **********************************************************************/
169 void appendHeader(header_info *hi)
170 {
171 // Add the header to the header list.
172 // The header is appended to the list, to preserve the bottom-up order.
173 HeaderCount++;
174 hi->next = NULL;
175 if (!FirstHeader) {
176 // list is empty
177 FirstHeader = LastHeader = hi;
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;
183 }
184 // LastHeader is now valid
185 LastHeader->next = hi;
186 LastHeader = hi;
187 }
188 }
189
190
191 /***********************************************************************
192 * removeHeader
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)
199 {
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
214 HeaderCount--;
215 break;
216 }
217 }
218 }
219
220
221 /***********************************************************************
222 * environ_init
223 * Read environment variables that affect the runtime.
224 * Also print environment variable help, if requested.
225 **********************************************************************/
226 void environ_init(void)
227 {
228 if (issetugid()) {
229 // All environment variables are silently ignored when setuid or setgid
230 // This includes OBJC_HELP and OBJC_PRINT_OPTIONS themselves.
231 return;
232 }
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) {
268 if (PrintHelp) {
269 _objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");
270 _objc_inform("OBJC_HELP: describe available environment variables");
271 if (PrintOptions) {
272 _objc_inform("OBJC_HELP is set");
273 }
274 _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
275 }
276 if (PrintOptions) {
277 _objc_inform("OBJC_PRINT_OPTIONS is set");
278 }
279
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 }
286 }
287
288
289 /***********************************************************************
290 * logReplacedMethod
291 * OBJC_PRINT_REPLACED_METHODS implementation
292 **********************************************************************/
293 void
294 logReplacedMethod(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
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;
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);
317 }
318
319
320
321 /***********************************************************************
322 * objc_setMultithreaded.
323 **********************************************************************/
324 void objc_setMultithreaded (BOOL flag)
325 {
326 OBJC_WARN_DEPRECATED;
327
328 // Nothing here. Thread synchronization in the runtime is always active.
329 }
330
331
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)
339 {
340 _objc_pthread_data *data;
341
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);
347 }
348
349 return data;
350 }
351
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 **********************************************************************/
358 extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
359 void _objc_pthread_destroyspecific(void *arg)
360 {
361 _objc_pthread_data *data = (_objc_pthread_data *)arg;
362 if (data != NULL) {
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]);
369 }
370 }
371
372 // add further cleanup here...
373
374 _free_internal(data);
375 }
376 }
377
378
379 void tls_init(void)
380 {
381 #if SUPPORT_DIRECT_THREAD_KEYS
382 _objc_pthread_key = TLS_DIRECT_KEY;
383 pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);
384 #else
385 _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);
386 #endif
387 }
388
389
390 /***********************************************************************
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.
395 **********************************************************************/
396 void _objcInit(void)
397 {
398 // do nothing
399 }
400
401
402 /***********************************************************************
403 * objc_setForwardHandler
404 **********************************************************************/
405
406 #if !__OBJC2__
407
408 // Default forward handler (nil) goes to forward:: dispatch.
409 void *_objc_forward_handler = nil;
410 void *_objc_forward_stret_handler = nil;
411
412 #else
413
414 // Default forward handler halts the process.
415 __attribute__((noreturn)) void
416 objc_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);
422 }
423 void *_objc_forward_handler = (void*)objc_defaultForwardHandler;
424
425 #if SUPPORT_STRET
426 struct stret { int i[100]; };
427 __attribute__((noreturn)) struct stret
428 objc_defaultForwardStretHandler(id self, SEL sel)
429 {
430 objc_defaultForwardHandler(self, sel);
431 }
432 void *_objc_forward_stret_handler = (void*)objc_defaultForwardStretHandler;
433 #endif
434
435 #endif
436
437 void objc_setForwardHandler(void *fwd, void *fwd_stret)
438 {
439 _objc_forward_handler = fwd;
440 #if SUPPORT_STRET
441 _objc_forward_stret_handler = fwd_stret;
442 #endif
443 }
444
445
446 #if !__OBJC2__
447 // GrP fixme
448 extern "C" Class _objc_getOrigClass(const char *name);
449 #endif
450 const char *class_getImageName(Class cls)
451 {
452 #if TARGET_OS_WIN32
453 TCHAR *szFileName;
454 DWORD charactersCopied;
455 Class origCls;
456 HMODULE classModule;
457 BOOL res;
458 #endif
459 if (!cls) return NULL;
460
461 #if !__OBJC2__
462 cls = _objc_getOrigClass(cls->demangledName());
463 #endif
464 #if TARGET_OS_WIN32
465 charactersCopied = 0;
466 szFileName = malloc(MAX_PATH * sizeof(TCHAR));
467
468 origCls = objc_getOrigClass(cls->demangledName());
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 }
480 return NULL;
481 #else
482 return dyld_image_path_containing_address(cls);
483 #endif
484 }
485
486
487 const char **objc_copyImageNames(unsigned int *outCount)
488 {
489 header_info *hi;
490 int count = 0;
491 int max = HeaderCount;
492 #if TARGET_OS_WIN32
493 const TCHAR **names = (const TCHAR **)calloc(max+1, sizeof(TCHAR *));
494 #else
495 const char **names = (const char **)calloc(max+1, sizeof(char *));
496 #endif
497
498 for (hi = FirstHeader; hi != NULL && count < max; hi = hi->next) {
499 #if TARGET_OS_WIN32
500 if (hi->moduleName) {
501 names[count++] = hi->moduleName;
502 }
503 #else
504 if (hi->fname) {
505 names[count++] = hi->fname;
506 }
507 #endif
508 }
509 names[count] = NULL;
510
511 if (count == 0) {
512 // Return NULL instead of empty list if there are no images
513 free((void *)names);
514 names = NULL;
515 }
516
517 if (outCount) *outCount = count;
518 return names;
519 }
520
521
522 /**********************************************************************
523 *
524 **********************************************************************/
525 const char **
526 objc_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.
536 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
537 #if TARGET_OS_WIN32
538 if (0 == wcscmp((TCHAR *)image, hi->moduleName)) break;
539 #else
540 if (0 == strcmp(image, hi->fname)) break;
541 #endif
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
557 static void (*enumerationMutationHandler)(id);
558
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);
566 }
567 (*enumerationMutationHandler)(object);
568 }
569
570
571 /**********************************************************************
572 * objc_setEnumerationMutationHandler
573 * an entry point to customize mutation error handing
574 **********************************************************************/
575 void objc_setEnumerationMutationHandler(void (*handler)(id)) {
576 enumerationMutationHandler = handler;
577 }
578
579
580 /**********************************************************************
581 * Associative Reference Support
582 **********************************************************************/
583
584 id objc_getAssociatedObject_non_gc(id object, const void *key) {
585 return _object_get_associative_reference(object, (void *)key);
586 }
587
588
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);
591 }
592
593
594 #if SUPPORT_GC
595
596 id objc_getAssociatedObject_gc(id object, const void *key) {
597 return (id)auto_zone_get_associative_ref(gc_zone, object, (void *)key);
598 }
599
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);
603 }
604 auto_zone_set_associative_ref(gc_zone, object, (void *)key, value);
605 }
606
607 // objc_setAssociatedObject and objc_getAssociatedObject are
608 // resolver functions in objc-auto.mm.
609
610 #else
611
612 id
613 objc_getAssociatedObject(id object, const void *key)
614 {
615 return objc_getAssociatedObject_non_gc(object, key);
616 }
617
618 void
619 objc_setAssociatedObject(id object, const void *key, id value,
620 objc_AssociationPolicy policy)
621 {
622 objc_setAssociatedObject_non_gc(object, key, value, policy);
623 }
624
625 #endif
626
627
628 void objc_removeAssociatedObjects(id object)
629 {
630 #if SUPPORT_GC
631 if (UseGC) {
632 auto_zone_erase_associative_refs(gc_zone, object);
633 } else
634 #endif
635 {
636 if (object && object->hasAssociatedObjects()) {
637 _object_remove_assocations(object);
638 }
639 }
640 }
641