]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-runtime.m
objc4-437.1.tar.gz
[apple/objc4.git] / runtime / objc-runtime.m
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
39 OBJC_EXPORT Class getOriginalClassForPosingClass(Class);
40
41
42 /***********************************************************************
43 * Exports.
44 **********************************************************************/
45
46 // Settings from environment variables
47 #ifndef NO_ENVIRON
48 __private_extern__ int PrintImages = -1; // env OBJC_PRINT_IMAGES
49 __private_extern__ int PrintLoading = -1; // env OBJC_PRINT_LOAD_METHODS
50 __private_extern__ int PrintInitializing = -1; // env OBJC_PRINT_INITIALIZE_METHODS
51 __private_extern__ int PrintResolving = -1; // env OBJC_PRINT_RESOLVED_METHODS
52 __private_extern__ int PrintConnecting = -1; // env OBJC_PRINT_CLASS_SETUP
53 __private_extern__ int PrintProtocols = -1; // env OBJC_PRINT_PROTOCOL_SETUP
54 __private_extern__ int PrintIvars = -1; // env OBJC_PRINT_IVAR_SETUP
55 __private_extern__ int PrintVtables = -1; // env OBJC_PRINT_VTABLE_SETUP
56 __private_extern__ int PrintVtableImages = -1;//env OBJC_PRINT_VTABLE_IMAGES
57 __private_extern__ int PrintFuture = -1; // env OBJC_PRINT_FUTURE_CLASSES
58 __private_extern__ int PrintRTP = -1; // env OBJC_PRINT_RTP
59 __private_extern__ int PrintGC = -1; // env OBJC_PRINT_GC
60 __private_extern__ int PrintPreopt = -1; // env OBJC_PRINT_PREOPTIMIZATION
61 __private_extern__ int PrintCxxCtors = -1; // env OBJC_PRINT_CXX_CTORS
62 __private_extern__ int PrintExceptions = -1; // env OBJC_PRINT_EXCEPTIONS
63 __private_extern__ int PrintAltHandlers = -1; // env OBJC_PRINT_ALT_HANDLERS
64 __private_extern__ int PrintDeprecation = -1;// env OBJC_PRINT_DEPRECATION_WARNINGS
65 __private_extern__ int PrintReplacedMethods = -1; // env OBJC_PRINT_REPLACED_METHODS
66 __private_extern__ int PrintCaches = -1; // env OBJC_PRINT_CACHE_SETUP
67
68 __private_extern__ int UseInternalZone = -1; // env OBJC_USE_INTERNAL_ZONE
69
70 __private_extern__ int DebugUnload = -1; // env OBJC_DEBUG_UNLOAD
71 __private_extern__ int DebugFragileSuperclasses = -1; // env OBJC_DEBUG_FRAGILE_SUPERCLASSES
72 __private_extern__ int DebugNilSync = -1; // env OBJC_DEBUG_NIL_SYNC
73
74 __private_extern__ int DisableGC = -1; // env OBJC_DISABLE_GC
75 __private_extern__ int DisableVtables = -1; // env OBJC_DISABLE_VTABLES
76 __private_extern__ int DisablePreopt = -1; // env OBJC_DISABLE_PREOPTIMIZATION
77 __private_extern__ int DebugFinalizers = -1; // env OBJC_DEBUG_FINALIZERS
78 #endif
79
80
81 // objc's key for pthread_getspecific
82 static tls_key_t _objc_pthread_key;
83
84 // Selectors
85 __private_extern__ SEL SEL_load = NULL;
86 __private_extern__ SEL SEL_initialize = NULL;
87 __private_extern__ SEL SEL_resolveInstanceMethod = NULL;
88 __private_extern__ SEL SEL_resolveClassMethod = NULL;
89 __private_extern__ SEL SEL_cxx_construct = NULL;
90 __private_extern__ SEL SEL_cxx_destruct = NULL;
91 __private_extern__ SEL SEL_retain = NULL;
92 __private_extern__ SEL SEL_release = NULL;
93 __private_extern__ SEL SEL_autorelease = NULL;
94 __private_extern__ SEL SEL_copy = NULL;
95 __private_extern__ SEL SEL_finalize = NULL;
96
97 __private_extern__ header_info *FirstHeader NOBSS = 0; // NULL means empty list
98 __private_extern__ header_info *LastHeader NOBSS = 0; // NULL means invalid; recompute it
99 __private_extern__ int HeaderCount NOBSS = 0;
100
101
102
103 /***********************************************************************
104 * objc_getClass. Return the id of the named class. If the class does
105 * not exist, call _objc_classLoader and then objc_classHandler, either of
106 * which may create a new class.
107 * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
108 **********************************************************************/
109 id objc_getClass(const char *aClassName)
110 {
111 if (!aClassName) return Nil;
112
113 // NO unconnected, YES class handler
114 return look_up_class(aClassName, NO, YES);
115 }
116
117
118 /***********************************************************************
119 * objc_getRequiredClass.
120 * Same as objc_getClass, but kills the process if the class is not found.
121 * This is used by ZeroLink, where failing to find a class would be a
122 * compile-time link error without ZeroLink.
123 **********************************************************************/
124 id objc_getRequiredClass(const char *aClassName)
125 {
126 id cls = objc_getClass(aClassName);
127 if (!cls) _objc_fatal("link error: class '%s' not found.", aClassName);
128 return cls;
129 }
130
131
132 /***********************************************************************
133 * objc_lookUpClass. Return the id of the named class.
134 * If the class does not exist, call _objc_classLoader, which may create
135 * a new class.
136 *
137 * Formerly objc_getClassWithoutWarning ()
138 **********************************************************************/
139 id objc_lookUpClass(const char *aClassName)
140 {
141 if (!aClassName) return Nil;
142
143 // NO unconnected, NO class handler
144 return look_up_class(aClassName, NO, NO);
145 }
146
147 /***********************************************************************
148 * objc_getFutureClass. Return the id of the named class.
149 * If the class does not exist, return an uninitialized class
150 * structure that will be used for the class when and if it
151 * does get loaded.
152 * Not thread safe.
153 **********************************************************************/
154 Class objc_getFutureClass(const char *name)
155 {
156 Class cls;
157
158 // YES unconnected, NO class handler
159 // (unconnected is OK because it will someday be the real class)
160 cls = (Class)look_up_class(name, YES, NO);
161 if (cls) {
162 if (PrintFuture) {
163 _objc_inform("FUTURE: found %p already in use for %s", cls, name);
164 }
165 return cls;
166 }
167
168 // No class or future class with that name yet. Make one.
169 // fixme not thread-safe with respect to
170 // simultaneous library load or getFutureClass.
171 return _objc_allocateFutureClass(name);
172 }
173
174
175 /***********************************************************************
176 * objc_getMetaClass. Return the id of the meta class the named class.
177 * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
178 **********************************************************************/
179 id objc_getMetaClass(const char *aClassName)
180 {
181 Class cls;
182
183 if (!aClassName) return Nil;
184
185 cls = (Class)objc_getClass (aClassName);
186 if (!cls)
187 {
188 _objc_inform ("class `%s' not linked into application", aClassName);
189 return Nil;
190 }
191
192 return (id)cls->isa;
193 }
194
195
196 /***********************************************************************
197 * _nameForHeader.
198 **********************************************************************/
199 __private_extern__ const char *_nameForHeader(const headerType *header)
200 {
201 return _getObjcHeaderName ((headerType *) header);
202 }
203
204
205 /***********************************************************************
206 * _objc_appendHeader. Add a newly-constructed header_info to the list.
207 **********************************************************************/
208 __private_extern__ void _objc_appendHeader(header_info *hi)
209 {
210 // Add the header to the header list.
211 // The header is appended to the list, to preserve the bottom-up order.
212 HeaderCount++;
213 hi->next = NULL;
214 if (!FirstHeader) {
215 // list is empty
216 FirstHeader = LastHeader = hi;
217 } else {
218 if (!LastHeader) {
219 // list is not empty, but LastHeader is invalid - recompute it
220 LastHeader = FirstHeader;
221 while (LastHeader->next) LastHeader = LastHeader->next;
222 }
223 // LastHeader is now valid
224 LastHeader->next = hi;
225 LastHeader = hi;
226 }
227 }
228
229
230 /***********************************************************************
231 * _objc_RemoveHeader
232 * Remove the given header from the header list.
233 * FirstHeader is updated.
234 * LastHeader is set to NULL. Any code that uses LastHeader must
235 * detect this NULL and recompute LastHeader by traversing the list.
236 **********************************************************************/
237 __private_extern__ void _objc_removeHeader(header_info *hi)
238 {
239 header_info **hiP;
240
241 for (hiP = &FirstHeader; *hiP != NULL; hiP = &(**hiP).next) {
242 if (*hiP == hi) {
243 header_info *deadHead = *hiP;
244
245 // Remove from the linked list (updating FirstHeader if necessary).
246 *hiP = (**hiP).next;
247
248 // Update LastHeader if necessary.
249 if (LastHeader == deadHead) {
250 LastHeader = NULL; // will be recomputed next time it's used
251 }
252
253 HeaderCount--;
254 break;
255 }
256 }
257 }
258
259
260 /***********************************************************************
261 * environ_init
262 * Read environment variables that affect the runtime.
263 * Also print environment variable help, if requested.
264 **********************************************************************/
265 __private_extern__ void environ_init(void)
266 {
267 #ifndef NO_ENVIRON
268 int PrintHelp = (getenv("OBJC_HELP") != NULL);
269 int PrintOptions = (getenv("OBJC_PRINT_OPTIONS") != NULL);
270 int secure = issetugid();
271
272 if (secure) {
273 // All environment variables are ignored when setuid or setgid.
274 // This includes OBJC_HELP and OBJC_PRINT_OPTIONS themselves.
275 }
276 else {
277 if (PrintHelp) {
278 _objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");
279 _objc_inform("OBJC_HELP: describe available environment variables");
280 if (PrintOptions) {
281 _objc_inform("OBJC_HELP is set");
282 }
283 _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
284 }
285 if (PrintOptions) {
286 _objc_inform("OBJC_PRINT_OPTIONS is set");
287 }
288 }
289
290 #define OPTION(var, env, help) \
291 if ( var == -1 ) { \
292 char *value = getenv(#env); \
293 var = value != NULL && !strcmp("YES", value); \
294 if (secure) { \
295 if (var) _objc_inform(#env " ignored when running setuid or setgid"); \
296 var = 0; \
297 } else { \
298 if (PrintHelp) _objc_inform(#env ": " help); \
299 if (PrintOptions && var) _objc_inform(#env " is set"); \
300 } \
301 }
302
303 OPTION(PrintImages, OBJC_PRINT_IMAGES,
304 "log image and library names as they are loaded");
305 OPTION(PrintLoading, OBJC_PRINT_LOAD_METHODS,
306 "log calls to class and category +load methods");
307 OPTION(PrintInitializing, OBJC_PRINT_INITIALIZE_METHODS,
308 "log calls to class +initialize methods");
309 OPTION(PrintResolving, OBJC_PRINT_RESOLVED_METHODS,
310 "log methods created by +resolveClassMethod: and +resolveInstanceMethod:");
311 OPTION(PrintConnecting, OBJC_PRINT_CLASS_SETUP,
312 "log progress of class and category setup");
313 OPTION(PrintProtocols, OBJC_PRINT_PROTOCOL_SETUP,
314 "log progress of protocol setup");
315 OPTION(PrintIvars, OBJC_PRINT_IVAR_SETUP,
316 "log processing of non-fragile ivars");
317 OPTION(PrintVtables, OBJC_PRINT_VTABLE_SETUP,
318 "log processing of class vtables");
319 OPTION(PrintVtableImages, OBJC_PRINT_VTABLE_IMAGES,
320 "print vtable images showing overridden methods");
321 OPTION(PrintCaches, OBJC_PRINT_CACHE_SETUP,
322 "log processing of method caches");
323 OPTION(PrintFuture, OBJC_PRINT_FUTURE_CLASSES,
324 "log use of future classes for toll-free bridging");
325 OPTION(PrintRTP, OBJC_PRINT_RTP,
326 "log initialization of the Objective-C runtime pages");
327 OPTION(PrintGC, OBJC_PRINT_GC,
328 "log some GC operations");
329 OPTION(PrintPreopt, OBJC_PRINT_PREOPTIMIZATION,
330 "log preoptimization courtesy of dyld shared cache");
331 OPTION(PrintCxxCtors, OBJC_PRINT_CXX_CTORS,
332 "log calls to C++ ctors and dtors for instance variables");
333 OPTION(PrintExceptions, OBJC_PRINT_EXCEPTIONS,
334 "log exception handling");
335 OPTION(PrintAltHandlers, OBJC_PRINT_ALT_HANDLERS,
336 "log processing of exception alt handlers");
337 OPTION(PrintReplacedMethods, OBJC_PRINT_REPLACED_METHODS,
338 "log methods replaced by category implementations");
339 OPTION(PrintDeprecation, OBJC_PRINT_DEPRECATION_WARNINGS,
340 "warn about calls to deprecated runtime functions");
341
342 OPTION(DebugUnload, OBJC_DEBUG_UNLOAD,
343 "warn about poorly-behaving bundles when unloaded");
344 OPTION(DebugFragileSuperclasses, OBJC_DEBUG_FRAGILE_SUPERCLASSES,
345 "warn about subclasses that may have been broken by subsequent changes to superclasses");
346 OPTION(DebugFinalizers, OBJC_DEBUG_FINALIZERS,
347 "warn about classes that implement -dealloc but not -finalize");
348 OPTION(DebugNilSync, OBJC_DEBUG_NIL_SYNC,
349 "warn about @synchronized(nil), which does no synchronization");
350
351 OPTION(UseInternalZone, OBJC_USE_INTERNAL_ZONE,
352 "allocate runtime data in a dedicated malloc zone");
353
354 OPTION(DisableGC, OBJC_DISABLE_GC,
355 "force GC OFF, even if the executable wants it on");
356 OPTION(DisableVtables, OBJC_DISABLE_VTABLES,
357 "disable vtable dispatch");
358 OPTION(DisablePreopt, OBJC_DISABLE_PREOPTIMIZATION,
359 "disable preoptimization courtesy of dyld shared cache");
360
361 #undef OPTION
362 #endif
363 }
364
365
366 /***********************************************************************
367 * logReplacedMethod
368 * OBJC_PRINT_REPLACED_METHODS implementation
369 **********************************************************************/
370 __private_extern__ void
371 logReplacedMethod(const char *className, SEL s,
372 BOOL isMeta, const char *catName,
373 IMP oldImp, IMP newImp)
374 {
375 const char *oldImage = "??";
376 const char *newImage = "??";
377
378 // Silently ignore +load replacement because category +load is special
379 if (s == SEL_load) return;
380
381 #if TARGET_OS_WIN32
382 // don't know dladdr()/dli_fname equivalent
383 #else
384 Dl_info dl;
385
386 if (dladdr(oldImp, &dl) && dl.dli_fname) oldImage = dl.dli_fname;
387 if (dladdr(newImp, &dl) && dl.dli_fname) newImage = dl.dli_fname;
388 #endif
389
390 _objc_inform("REPLACED: %c[%s %s] %s%s (IMP was %p (%s), now %p (%s))",
391 isMeta ? '+' : '-', className, sel_getName(s),
392 catName ? "by category " : "", catName ? catName : "",
393 oldImp, oldImage, newImp, newImage);
394 }
395
396
397
398 /***********************************************************************
399 * objc_setMultithreaded.
400 **********************************************************************/
401 void objc_setMultithreaded (BOOL flag)
402 {
403 OBJC_WARN_DEPRECATED;
404
405 // Nothing here. Thread synchronization in the runtime is always active.
406 }
407
408
409 /***********************************************************************
410 * _objc_fetch_pthread_data
411 * Fetch objc's pthread data for this thread.
412 * If the data doesn't exist yet and create is NO, return NULL.
413 * If the data doesn't exist yet and create is YES, allocate and return it.
414 **********************************************************************/
415 __private_extern__ _objc_pthread_data *_objc_fetch_pthread_data(BOOL create)
416 {
417 _objc_pthread_data *data;
418
419 data = tls_get(_objc_pthread_key);
420 if (!data && create) {
421 data = _calloc_internal(1, sizeof(_objc_pthread_data));
422 tls_set(_objc_pthread_key, data);
423 }
424
425 return data;
426 }
427
428
429 /***********************************************************************
430 * _objc_pthread_destroyspecific
431 * Destructor for objc's per-thread data.
432 * arg shouldn't be NULL, but we check anyway.
433 **********************************************************************/
434 extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
435 __private_extern__ void _objc_pthread_destroyspecific(void *arg)
436 {
437 _objc_pthread_data *data = (_objc_pthread_data *)arg;
438 if (data != NULL) {
439 _destroyInitializingClassList(data->initializingClasses);
440 _destroyLockList(data->lockList);
441 _destroySyncCache(data->syncCache);
442 _destroyAltHandlerList(data->handlerList);
443
444 // add further cleanup here...
445
446 _free_internal(data);
447 }
448 }
449
450
451 __private_extern__ void tls_init(void)
452 {
453 #ifdef NO_DIRECT_THREAD_KEYS
454 tls_create(&_objc_pthread_key, &_objc_pthread_destroyspecific);
455 #else
456 _objc_pthread_key = TLS_DIRECT_KEY;
457 pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);
458 #endif
459 }
460
461
462 /***********************************************************************
463 * _objcInit
464 * Former library initializer. This function is now merely a placeholder
465 * for external callers. All runtime initialization has now been moved
466 * to map_images() and _objc_init.
467 **********************************************************************/
468 void _objcInit(void)
469 {
470 // do nothing
471 }
472
473
474 #if !TARGET_OS_WIN32
475 /***********************************************************************
476 * _objc_setNilReceiver
477 **********************************************************************/
478 id _objc_setNilReceiver(id newNilReceiver)
479 {
480 id oldNilReceiver;
481
482 oldNilReceiver = _objc_nilReceiver;
483 _objc_nilReceiver = newNilReceiver;
484
485 return oldNilReceiver;
486 }
487
488 /***********************************************************************
489 * _objc_getNilReceiver
490 **********************************************************************/
491 id _objc_getNilReceiver(void)
492 {
493 return _objc_nilReceiver;
494 }
495 #endif
496
497
498 /***********************************************************************
499 * objc_setForwardHandler
500 **********************************************************************/
501 void objc_setForwardHandler(void *fwd, void *fwd_stret)
502 {
503 _objc_forward_handler = fwd;
504 _objc_forward_stret_handler = fwd_stret;
505 }
506
507
508 #if defined(__ppc__) || defined(__ppc64__)
509
510 // Test to see if either the displacement or destination is within
511 // the +/- 2^25 range needed for a PPC branch immediate instruction.
512 // Shifting the high bit of the displacement (or destination)
513 // left 6 bits and then 6 bits arithmetically to the right does a
514 // sign extend of the 26th bit. If that result is equivalent to the
515 // original value, then the displacement (or destination) will fit
516 // into a simple branch. Otherwise a larger branch sequence is required.
517 // ppc64: max displacement is still +/- 2^25, but intptr_t is bigger
518
519 // tiny: bc*
520 // small: b, ba (unconditional only)
521 // 32: bctr with lis+ori only
522 static BOOL ppc_tiny_displacement(intptr_t displacement)
523 {
524 size_t shift = sizeof(intptr_t) - 16; // ilp32=16, lp64=48
525 return (((displacement << shift) >> shift) == displacement);
526 }
527
528 static BOOL ppc_small_displacement(intptr_t displacement)
529 {
530 size_t shift = sizeof(intptr_t) - 26; // ilp32=6, lp64=38
531 return (((displacement << shift) >> shift) == displacement);
532 }
533
534 #if defined(__ppc64__)
535 // Same as ppc_small_displacement, but decides whether 32 bits is big enough.
536 static BOOL ppc_32bit_displacement(intptr_t displacement)
537 {
538 size_t shift = sizeof(intptr_t) - 32;
539 return (((displacement << shift) >> shift) == displacement);
540 }
541 #endif
542
543 /**********************************************************************
544 * objc_branch_size
545 * Returns the number of instructions needed
546 * for a branch from entry to target.
547 **********************************************************************/
548 __private_extern__ size_t objc_branch_size(void *entry, void *target)
549 {
550 return objc_cond_branch_size(entry, target, COND_ALWAYS);
551 }
552
553 __private_extern__ size_t
554 objc_cond_branch_size(void *entry, void *target, unsigned cond)
555 {
556 intptr_t destination = (intptr_t)target;
557 intptr_t displacement = (intptr_t)destination - (intptr_t)entry;
558
559 if (cond == COND_ALWAYS && ppc_small_displacement(displacement)) {
560 // fits in unconditional relative branch immediate
561 return 1;
562 }
563 if (cond == COND_ALWAYS && ppc_small_displacement(destination)) {
564 // fits in unconditional absolute branch immediate
565 return 1;
566 }
567 if (ppc_tiny_displacement(displacement)) {
568 // fits in conditional relative branch immediate
569 return 1;
570 }
571 if (ppc_tiny_displacement(destination)) {
572 // fits in conditional absolute branch immediate
573 return 1;
574 }
575 #if defined(__ppc64__)
576 if (!ppc_32bit_displacement(destination)) {
577 // fits in 64-bit absolute branch through CTR
578 return 7;
579 }
580 #endif
581
582 // fits in 32-bit absolute branch through CTR
583 return 4;
584 }
585
586 /**********************************************************************
587 * objc_write_branch
588 * Writes at entry a PPC branch instruction sequence that branches to target.
589 * The sequence written will be objc_branch_size(entry, target) instructions.
590 * Returns the number of instructions written.
591 **********************************************************************/
592 __private_extern__ size_t objc_write_branch(void *entry, void *target)
593 {
594 return objc_write_cond_branch(entry, target, COND_ALWAYS);
595 }
596
597 __private_extern__ size_t
598 objc_write_cond_branch(void *entry, void *target, unsigned cond)
599 {
600 unsigned *address = (unsigned *)entry; // location to store the 32 bit PPC instructions
601 intptr_t destination = (intptr_t)target; // destination as an absolute address
602 intptr_t displacement = (intptr_t)destination - (intptr_t)address; // destination as a branch relative offset
603
604 if (cond == COND_ALWAYS && ppc_small_displacement(displacement)) {
605 // use unconditional relative branch with the displacement
606 address[0] = 0x48000000 | (unsigned)(displacement & 0x03fffffc); // b *+displacement
607 // issued 1 instruction
608 return 1;
609 }
610 if (cond == COND_ALWAYS && ppc_small_displacement(destination)) {
611 // use unconditional absolute branch with the destination
612 address[0] = 0x48000000 | (unsigned)(destination & 0x03fffffc) | 2; // ba destination (2 is the absolute flag)
613 // issued 1 instruction
614 return 1;
615 }
616
617 if (ppc_tiny_displacement(displacement)) {
618 // use conditional relative branch with the displacement
619 address[0] = 0x40000000 | cond | (unsigned)(displacement & 0x0000fffc); // b *+displacement
620 // issued 1 instruction
621 return 1;
622 }
623 if (ppc_tiny_displacement(destination)) {
624 // use conditional absolute branch with the destination
625 address[0] = 0x40000000 | cond | (unsigned)(destination & 0x0000fffc) | 2; // ba destination (2 is the absolute flag)
626 // issued 1 instruction
627 return 1;
628 }
629
630
631 // destination is large and far away.
632 // Use an absolute branch via CTR.
633
634 #if defined(__ppc64__)
635 if (!ppc_32bit_displacement(destination)) {
636 uint16_t lo = destination & 0xffff;
637 uint16_t hi = (destination >> 16) & 0xffff;
638 uint16_t hi2 = (destination >> 32) & 0xffff;
639 uint16_t hi3 = (destination >> 48) & 0xffff;
640
641 address[0] = 0x3d800000 | hi3; // lis r12, hi3
642 address[1] = 0x618c0000 | hi2; // ori r12, r12, hi2
643 address[2] = 0x798c07c6; // sldi r12, r12, 32
644 address[3] = 0x658c0000 | hi; // oris r12, r12, hi
645 address[4] = 0x618c0000 | lo; // ori r12, r12, lo
646 address[5] = 0x7d8903a6; // mtctr r12
647 address[6] = 0x4c000420 | cond; // bctr
648 // issued 7 instructions
649 return 7;
650 }
651 #endif
652
653 {
654 uint16_t lo = destination & 0xffff;
655 uint16_t hi = (destination >> 16) & 0xffff;
656
657 address[0] = 0x3d800000 | hi; // lis r12,hi
658 address[1] = 0x618c0000 | lo; // ori r12,r12,lo
659 address[2] = 0x7d8903a6; // mtctr r12
660 address[3] = 0x4c000420 | cond; // bctr
661 // issued 4 instructions
662 return 4;
663 }
664 }
665
666 // defined(__ppc__) || defined(__ppc64__)
667 #endif
668
669 #if defined(__i386__) || defined(__x86_64__)
670
671 /**********************************************************************
672 * objc_branch_size
673 * Returns the number of BYTES needed
674 * for a branch from entry to target.
675 **********************************************************************/
676 __private_extern__ size_t objc_branch_size(void *entry, void *target)
677 {
678 return objc_cond_branch_size(entry, target, COND_ALWAYS);
679 }
680
681 __private_extern__ size_t
682 objc_cond_branch_size(void *entry, void *target, unsigned cond)
683 {
684 // For simplicity, always use 32-bit relative jumps.
685 if (cond == COND_ALWAYS) return 5;
686 else return 6;
687 }
688
689 /**********************************************************************
690 * objc_write_branch
691 * Writes at entry an i386 branch instruction sequence that branches to target.
692 * The sequence written will be objc_branch_size(entry, target) BYTES.
693 * Returns the number of BYTES written.
694 **********************************************************************/
695 __private_extern__ size_t objc_write_branch(void *entry, void *target)
696 {
697 return objc_write_cond_branch(entry, target, COND_ALWAYS);
698 }
699
700 __private_extern__ size_t
701 objc_write_cond_branch(void *entry, void *target, unsigned cond)
702 {
703 uint8_t *address = (uint8_t *)entry; // instructions written to here
704 intptr_t destination = (intptr_t)target; // branch dest as absolute address
705 intptr_t displacement = (intptr_t)destination - ((intptr_t)address + objc_cond_branch_size(entry, target, cond)); // branch dest as relative offset
706
707 // For simplicity, always use 32-bit relative jumps
708 if (cond != COND_ALWAYS) {
709 *address++ = 0x0f; // Jcc prefix
710 }
711 *address++ = cond;
712 *address++ = displacement & 0xff;
713 *address++ = (displacement >> 8) & 0xff;
714 *address++ = (displacement >> 16) & 0xff;
715 *address++ = (displacement >> 24) & 0xff;
716
717 return address - (uint8_t *)entry;
718 }
719
720 // defined __i386__
721 #endif
722
723
724
725
726 #if !__OBJC2__
727 // GrP fixme
728 extern Class _objc_getOrigClass(const char *name);
729 #endif
730 const char *class_getImageName(Class cls)
731 {
732 #if TARGET_OS_WIN32
733 TCHAR *szFileName;
734 DWORD charactersCopied;
735 Class origCls;
736 HMODULE classModule;
737 BOOL res;
738 #endif
739 if (!cls) return NULL;
740
741 #if !__OBJC2__
742 cls = _objc_getOrigClass(_class_getName(cls));
743 #endif
744 #if TARGET_OS_WIN32
745 charactersCopied = 0;
746 szFileName = malloc(MAX_PATH);
747
748 origCls = objc_getOrigClass(class_getName(cls));
749 classModule = NULL;
750 res = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)origCls, &classModule);
751 if (res && classModule) {
752 charactersCopied = GetModuleFileName(classModule, szFileName, MAX_PATH);
753 }
754 if (classModule) FreeLibrary(classModule);
755 if (charactersCopied) {
756 return (const char *)szFileName;
757 } else
758 free(szFileName);
759 return NULL;
760 #else
761 return dyld_image_path_containing_address(cls);
762 #endif
763 }
764
765
766 const char **objc_copyImageNames(unsigned int *outCount)
767 {
768 header_info *hi;
769 int count = 0;
770 int max = HeaderCount;
771 const char **names = calloc(max+1, sizeof(char *));
772
773 for (hi = FirstHeader; hi != NULL && count < max; hi = hi->next) {
774 #if TARGET_OS_WIN32
775 TCHAR *szFileName;
776 DWORD charactersCopied;
777
778 szFileName = malloc(MAX_PATH);
779
780 charactersCopied = GetModuleFileName((HMODULE)(hi->mhdr), szFileName, MAX_PATH);
781 if (charactersCopied)
782 names[count++] = (const char *)szFileName;
783 else
784 free(szFileName);
785 #else
786 if (hi->os.dl_info.dli_fname) {
787 names[count++] = hi->os.dl_info.dli_fname;
788 }
789 #endif
790 }
791 names[count] = NULL;
792
793 if (count == 0) {
794 // Return NULL instead of empty list if there are no images
795 free((void *)names);
796 names = NULL;
797 }
798
799 if (outCount) *outCount = count;
800 return names;
801 }
802
803
804 /**********************************************************************
805 *
806 **********************************************************************/
807 const char **
808 objc_copyClassNamesForImage(const char *image, unsigned int *outCount)
809 {
810 header_info *hi;
811
812 if (!image) {
813 if (outCount) *outCount = 0;
814 return NULL;
815 }
816
817 // Find the image.
818 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
819 #if TARGET_OS_WIN32
820 // fixme
821 #else
822 if (0 == strcmp(image, hi->os.dl_info.dli_fname)) break;
823 #endif
824 }
825
826 if (!hi) {
827 if (outCount) *outCount = 0;
828 return NULL;
829 }
830
831 return _objc_copyClassNamesForImage(hi, outCount);
832 }
833
834
835 /**********************************************************************
836 * Fast Enumeration Support
837 **********************************************************************/
838
839 static void (*enumerationMutationHandler)(id);
840
841 /**********************************************************************
842 * objc_enumerationMutation
843 * called by compiler when a mutation is detected during foreach iteration
844 **********************************************************************/
845 void objc_enumerationMutation(id object) {
846 if (enumerationMutationHandler == nil) {
847 _objc_fatal("mutation detected during 'for(... in ...)' enumeration of object %p.", object);
848 }
849 (*enumerationMutationHandler)(object);
850 }
851
852
853 /**********************************************************************
854 * objc_setEnumerationMutationHandler
855 * an entry point to customize mutation error handing
856 **********************************************************************/
857 void objc_setEnumerationMutationHandler(void (*handler)(id)) {
858 enumerationMutationHandler = handler;
859 }
860
861
862 /**********************************************************************
863 * Debugger mode
864 *
865 * Debugger mode is used when gdb wants to call runtime functions
866 * and other methods while other threads are stopped. The runtime
867 * provides best-effort functionality while avoiding deadlocks
868 * with the stopped threads. gdb is responsible for ensuring that all
869 * threads but one stay stopped.
870 *
871 * When debugger mode starts, the runtime acquires as many locks as
872 * it can. Any locks that can't be acquired are off-limits until
873 * debugger mode ends. The locking functions in objc-os.h check each
874 * operation and halt if a disallowed lock is used; gdb catches that
875 * trap and cleans up.
876 *
877 * Each ABI is responsible for tracking its locks. Any lock not
878 * handled there is a potential gdb deadlock.
879 **********************************************************************/
880
881 #ifndef NO_DEBUGGER_MODE
882
883 __private_extern__ int DebuggerMode = DEBUGGER_OFF;
884 __private_extern__ objc_thread_t DebuggerModeThread = 0;
885 static int DebuggerModeCount;
886
887 /**********************************************************************
888 * gdb_objc_startDebuggerMode
889 * Start debugger mode by taking locks. Return 0 if not enough locks
890 * could be acquired.
891 **********************************************************************/
892 int gdb_objc_startDebuggerMode(uint32_t flags)
893 {
894 BOOL wantFull = flags & OBJC_DEBUGMODE_FULL;
895 if (! DebuggerMode) {
896 // Start debugger mode
897 int mode = startDebuggerMode(); // Do this FIRST
898 if (mode == DEBUGGER_OFF) {
899 // sorry
900 return 0;
901 }
902 else if (mode == DEBUGGER_PARTIAL && wantFull) {
903 // not good enough
904 endDebuggerMode();
905 return 0;
906 }
907 else {
908 // w00t
909 DebuggerMode = mode;
910 DebuggerModeCount = 1;
911 DebuggerModeThread = thread_self();
912 return 1;
913 }
914 }
915 else if (DebuggerMode == DEBUGGER_PARTIAL && wantFull) {
916 // Debugger mode already active, but not as requested - sorry
917 return 0;
918 }
919 else {
920 // Debugger mode already active as requested
921 if (thread_self() == DebuggerModeThread) {
922 DebuggerModeCount++;
923 return 1;
924 } else {
925 _objc_inform("DEBUGGER MODE: debugger is buggy: can't run "
926 "debugger mode from two threads!");
927 return 0;
928 }
929 }
930 }
931
932
933 /**********************************************************************
934 * gdb_objc_endDebuggerMode
935 * Relinquish locks and end debugger mode.
936 **********************************************************************/
937 void gdb_objc_endDebuggerMode(void)
938 {
939 if (DebuggerMode && thread_self() == DebuggerModeThread) {
940 if (--DebuggerModeCount == 0) {
941 DebuggerMode = NO;
942 DebuggerModeThread = 0;
943 endDebuggerMode(); // Do this LAST
944 }
945 } else {
946 _objc_inform("DEBUGGER MODE: debugger is buggy: debugger mode "
947 "not active for this thread!");
948 }
949 }
950
951
952 /**********************************************************************
953 * gdb_objc_debuggerModeFailure
954 * Breakpoint hook for gdb when debugger mode can't finish something
955 **********************************************************************/
956 void gdb_objc_debuggerModeFailure(void)
957 {
958 _objc_fatal("DEBUGGER MODE: failed");
959 }
960
961 // !defined(NO_DEBUGGER_MODE)
962 #endif