]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-runtime.mm
objc4-551.1.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_copy = NULL;
83 SEL SEL_new = NULL;
84 SEL SEL_finalize = NULL;
85 SEL SEL_forwardInvocation = NULL;
86
87 header_info *FirstHeader = 0; // NULL means empty list
88 header_info *LastHeader = 0; // NULL means invalid; recompute it
89 int HeaderCount = 0;
90
91
92
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)
100 {
101 if (!aClassName) return Nil;
102
103 // NO unconnected, YES class handler
104 return look_up_class(aClassName, NO, YES);
105 }
106
107
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)
115 {
116 Class cls = objc_getClass(aClassName);
117 if (!cls) _objc_fatal("link error: class '%s' not found.", aClassName);
118 return cls;
119 }
120
121
122 /***********************************************************************
123 * objc_lookUpClass. Return the id of the named class.
124 * If the class does not exist, call _objc_classLoader, which may create
125 * a new class.
126 *
127 * Formerly objc_getClassWithoutWarning ()
128 **********************************************************************/
129 Class objc_lookUpClass(const char *aClassName)
130 {
131 if (!aClassName) return Nil;
132
133 // NO unconnected, NO class handler
134 return look_up_class(aClassName, NO, NO);
135 }
136
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
141 * does get loaded.
142 * Not thread safe.
143 **********************************************************************/
144 Class objc_getFutureClass(const char *name)
145 {
146 Class cls;
147
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);
151 if (cls) {
152 if (PrintFuture) {
153 _objc_inform("FUTURE: found %p already in use for %s",
154 (void*)cls, name);
155 }
156 return cls;
157 }
158
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);
163 }
164
165
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)
171 {
172 Class cls;
173
174 if (!aClassName) return Nil;
175
176 cls = objc_getClass (aClassName);
177 if (!cls)
178 {
179 _objc_inform ("class `%s' not linked into application", aClassName);
180 return Nil;
181 }
182
183 return cls->ISA();
184 }
185
186
187 /***********************************************************************
188 * appendHeader. Add a newly-constructed header_info to the list.
189 **********************************************************************/
190 void appendHeader(header_info *hi)
191 {
192 // Add the header to the header list.
193 // The header is appended to the list, to preserve the bottom-up order.
194 HeaderCount++;
195 hi->next = NULL;
196 if (!FirstHeader) {
197 // list is empty
198 FirstHeader = LastHeader = hi;
199 } else {
200 if (!LastHeader) {
201 // list is not empty, but LastHeader is invalid - recompute it
202 LastHeader = FirstHeader;
203 while (LastHeader->next) LastHeader = LastHeader->next;
204 }
205 // LastHeader is now valid
206 LastHeader->next = hi;
207 LastHeader = hi;
208 }
209 }
210
211
212 /***********************************************************************
213 * removeHeader
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)
220 {
221 header_info **hiP;
222
223 for (hiP = &FirstHeader; *hiP != NULL; hiP = &(**hiP).next) {
224 if (*hiP == hi) {
225 header_info *deadHead = *hiP;
226
227 // Remove from the linked list (updating FirstHeader if necessary).
228 *hiP = (**hiP).next;
229
230 // Update LastHeader if necessary.
231 if (LastHeader == deadHead) {
232 LastHeader = NULL; // will be recomputed next time it's used
233 }
234
235 HeaderCount--;
236 break;
237 }
238 }
239 }
240
241
242 /***********************************************************************
243 * environ_init
244 * Read environment variables that affect the runtime.
245 * Also print environment variable help, if requested.
246 **********************************************************************/
247 void environ_init(void)
248 {
249 if (issetugid()) {
250 // All environment variables are silently ignored when setuid or setgid
251 // This includes OBJC_HELP and OBJC_PRINT_OPTIONS themselves.
252 return;
253 }
254
255 bool PrintHelp = false;
256 bool PrintOptions = false;
257
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;
262
263 if (0 == strncmp(*p, "OBJC_HELP=", 10)) {
264 PrintHelp = true;
265 continue;
266 }
267 if (0 == strncmp(*p, "OBJC_PRINT_OPTIONS=", 19)) {
268 PrintOptions = true;
269 continue;
270 }
271
272 const char *value = strchr(*p, '=');
273 if (!*value) continue;
274 value++;
275
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))
280 {
281 *opt->var = (0 == strcmp(value, "YES"));
282 break;
283 }
284 }
285 }
286
287 // Print OBJC_HELP and OBJC_PRINT_OPTIONS output.
288 if (PrintHelp || PrintOptions) {
289 if (PrintHelp) {
290 _objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");
291 _objc_inform("OBJC_HELP: describe available environment variables");
292 if (PrintOptions) {
293 _objc_inform("OBJC_HELP is set");
294 }
295 _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
296 }
297 if (PrintOptions) {
298 _objc_inform("OBJC_PRINT_OPTIONS is set");
299 }
300
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);
305 }
306 }
307 }
308
309
310 /***********************************************************************
311 * logReplacedMethod
312 * OBJC_PRINT_REPLACED_METHODS implementation
313 **********************************************************************/
314 void
315 logReplacedMethod(const char *className, SEL s,
316 BOOL isMeta, const char *catName,
317 IMP oldImp, IMP newImp)
318 {
319 const char *oldImage = "??";
320 const char *newImage = "??";
321
322 // Silently ignore +load replacement because category +load is special
323 if (s == SEL_load) return;
324
325 #if TARGET_OS_WIN32
326 // don't know dladdr()/dli_fname equivalent
327 #else
328 Dl_info dl;
329
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;
332 #endif
333
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);
338 }
339
340
341
342 /***********************************************************************
343 * objc_setMultithreaded.
344 **********************************************************************/
345 void objc_setMultithreaded (BOOL flag)
346 {
347 OBJC_WARN_DEPRECATED;
348
349 // Nothing here. Thread synchronization in the runtime is always active.
350 }
351
352
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)
360 {
361 _objc_pthread_data *data;
362
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);
368 }
369
370 return data;
371 }
372
373
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)
381 {
382 _objc_pthread_data *data = (_objc_pthread_data *)arg;
383 if (data != NULL) {
384 _destroyInitializingClassList(data->initializingClasses);
385 _destroySyncCache(data->syncCache);
386 _destroyAltHandlerList(data->handlerList);
387
388 // add further cleanup here...
389
390 _free_internal(data);
391 }
392 }
393
394
395 void tls_init(void)
396 {
397 #if SUPPORT_DIRECT_THREAD_KEYS
398 _objc_pthread_key = TLS_DIRECT_KEY;
399 pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);
400 #else
401 _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);
402 #endif
403 }
404
405
406 /***********************************************************************
407 * _objcInit
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 **********************************************************************/
412 void _objcInit(void)
413 {
414 // do nothing
415 }
416
417
418 #if !(TARGET_OS_WIN32 || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)
419 /***********************************************************************
420 * _objc_setNilReceiver
421 **********************************************************************/
422 id _objc_setNilReceiver(id newNilReceiver)
423 {
424 id oldNilReceiver;
425
426 oldNilReceiver = _objc_nilReceiver;
427 _objc_nilReceiver = newNilReceiver;
428
429 return oldNilReceiver;
430 }
431
432 /***********************************************************************
433 * _objc_getNilReceiver
434 **********************************************************************/
435 id _objc_getNilReceiver(void)
436 {
437 return _objc_nilReceiver;
438 }
439 #endif
440
441
442 /***********************************************************************
443 * objc_setForwardHandler
444 **********************************************************************/
445 void objc_setForwardHandler(void *fwd, void *fwd_stret)
446 {
447 _objc_forward_handler = fwd;
448 _objc_forward_stret_handler = fwd_stret;
449 }
450
451
452 #if !__OBJC2__
453 // GrP fixme
454 extern "C" Class _objc_getOrigClass(const char *name);
455 #endif
456 const char *class_getImageName(Class cls)
457 {
458 #if TARGET_OS_WIN32
459 TCHAR *szFileName;
460 DWORD charactersCopied;
461 Class origCls;
462 HMODULE classModule;
463 BOOL res;
464 #endif
465 if (!cls) return NULL;
466
467 #if !__OBJC2__
468 cls = _objc_getOrigClass(cls->getName());
469 #endif
470 #if TARGET_OS_WIN32
471 charactersCopied = 0;
472 szFileName = malloc(MAX_PATH * sizeof(TCHAR));
473
474 origCls = objc_getOrigClass(cls->getName());
475 classModule = NULL;
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));
479 }
480 if (classModule) FreeLibrary(classModule);
481 if (charactersCopied) {
482 return (const char *)szFileName;
483 } else {
484 free(szFileName);
485 }
486 return NULL;
487 #else
488 return dyld_image_path_containing_address(cls);
489 #endif
490 }
491
492
493 const char **objc_copyImageNames(unsigned int *outCount)
494 {
495 header_info *hi;
496 int count = 0;
497 int max = HeaderCount;
498 #if TARGET_OS_WIN32
499 const TCHAR **names = (const TCHAR **)calloc(max+1, sizeof(TCHAR *));
500 #else
501 const char **names = (const char **)calloc(max+1, sizeof(char *));
502 #endif
503
504 for (hi = FirstHeader; hi != NULL && count < max; hi = hi->next) {
505 #if TARGET_OS_WIN32
506 if (hi->moduleName) {
507 names[count++] = hi->moduleName;
508 }
509 #else
510 if (hi->fname) {
511 names[count++] = hi->fname;
512 }
513 #endif
514 }
515 names[count] = NULL;
516
517 if (count == 0) {
518 // Return NULL instead of empty list if there are no images
519 free((void *)names);
520 names = NULL;
521 }
522
523 if (outCount) *outCount = count;
524 return names;
525 }
526
527
528 /**********************************************************************
529 *
530 **********************************************************************/
531 const char **
532 objc_copyClassNamesForImage(const char *image, unsigned int *outCount)
533 {
534 header_info *hi;
535
536 if (!image) {
537 if (outCount) *outCount = 0;
538 return NULL;
539 }
540
541 // Find the image.
542 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
543 #if TARGET_OS_WIN32
544 if (0 == wcscmp((TCHAR *)image, hi->moduleName)) break;
545 #else
546 if (0 == strcmp(image, hi->fname)) break;
547 #endif
548 }
549
550 if (!hi) {
551 if (outCount) *outCount = 0;
552 return NULL;
553 }
554
555 return _objc_copyClassNamesForImage(hi, outCount);
556 }
557
558
559 /**********************************************************************
560 * Fast Enumeration Support
561 **********************************************************************/
562
563 static void (*enumerationMutationHandler)(id);
564
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);
572 }
573 (*enumerationMutationHandler)(object);
574 }
575
576
577 /**********************************************************************
578 * objc_setEnumerationMutationHandler
579 * an entry point to customize mutation error handing
580 **********************************************************************/
581 void objc_setEnumerationMutationHandler(void (*handler)(id)) {
582 enumerationMutationHandler = handler;
583 }
584
585
586 /**********************************************************************
587 * Associative Reference Support
588 **********************************************************************/
589
590 id objc_getAssociatedObject_non_gc(id object, const void *key) {
591 return _object_get_associative_reference(object, (void *)key);
592 }
593
594
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);
597 }
598
599
600 #if SUPPORT_GC
601
602 id objc_getAssociatedObject_gc(id object, const void *key) {
603 return (id)auto_zone_get_associative_ref(gc_zone, object, (void *)key);
604 }
605
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);
609 }
610 auto_zone_set_associative_ref(gc_zone, object, (void *)key, value);
611 }
612
613 // objc_setAssociatedObject and objc_getAssociatedObject are
614 // resolver functions in objc-auto.mm.
615
616 #else
617
618 id
619 objc_getAssociatedObject(id object, const void *key)
620 {
621 return objc_getAssociatedObject_non_gc(object, key);
622 }
623
624 void
625 objc_setAssociatedObject(id object, const void *key, id value,
626 objc_AssociationPolicy policy)
627 {
628 objc_setAssociatedObject_non_gc(object, key, value, policy);
629 }
630
631 #endif
632
633
634 void objc_removeAssociatedObjects(id object)
635 {
636 #if SUPPORT_GC
637 if (UseGC) {
638 auto_zone_erase_associative_refs(gc_zone, object);
639 } else
640 #endif
641 {
642 if (object && object->getIsa()->instancesHaveAssociatedObjects()) {
643 _object_remove_assocations(object);
644 }
645 }
646 }
647