sendmsg.c: Add prototypes for __objc_get_forward_imp and get_imp.
[official-gcc.git] / libobjc / sendmsg.c
blob8e347dfede3e8eb81e221c8488d64c633fdf5f2a
1 /* GNU Objective C Runtime message lookup
2 Copyright (C) 1993-2015 Free Software Foundation, Inc.
3 Contributed by Kresten Krab Thorup
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 3, or (at your option) any later version.
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 details.
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
25 /* Uncommented the following line to enable debug logging. Use this
26 only while debugging the runtime. */
27 /* #define DEBUG 1 */
29 /* FIXME: This file has no business including tm.h. */
30 /* FIXME: This should be using libffi instead of __builtin_apply
31 and friends. */
33 #include "objc-private/common.h"
34 #include "objc-private/error.h"
35 #include "tconfig.h"
36 #include "coretypes.h"
37 #include "tm.h"
38 #include "objc/runtime.h"
39 #include "objc/message.h" /* For objc_msg_lookup(), objc_msg_lookup_super(). */
40 #include "objc/thr.h"
41 #include "objc-private/module-abi-8.h"
42 #include "objc-private/runtime.h"
43 #include "objc-private/hash.h"
44 #include "objc-private/sarray.h"
45 #include "objc-private/selector.h" /* For sel_is_mapped() */
46 #include "runtime-info.h"
47 #include <assert.h> /* For assert */
48 #include <string.h> /* For strlen */
50 /* This is how we hack STRUCT_VALUE to be 1 or 0. */
51 #define gen_rtx(args...) 1
52 #define gen_rtx_MEM(args...) 1
53 #define gen_rtx_REG(args...) 1
54 /* Already defined in gcc/coretypes.h. So prevent double definition warning. */
55 #undef rtx
56 #define rtx int
58 #if ! defined (STRUCT_VALUE) || STRUCT_VALUE == 0
59 #define INVISIBLE_STRUCT_RETURN 1
60 #else
61 #define INVISIBLE_STRUCT_RETURN 0
62 #endif
64 /* The uninstalled dispatch table. If a class' dispatch table points
65 to __objc_uninstalled_dtable then that means it needs its dispatch
66 table to be installed. */
67 struct sarray *__objc_uninstalled_dtable = 0; /* !T:MUTEX */
69 /* Two hooks for method forwarding. If either is set, it is invoked to
70 * return a function that performs the real forwarding. If both are
71 * set, the result of __objc_msg_forward2 will be preferred over that
72 * of __objc_msg_forward. If both return NULL or are unset, the
73 * libgcc based functions (__builtin_apply and friends) are used. */
74 IMP (*__objc_msg_forward) (SEL) = NULL;
75 IMP (*__objc_msg_forward2) (id, SEL) = NULL;
77 /* Send +initialize to class. */
78 static void __objc_send_initialize (Class);
80 /* Forward declare some functions */
81 static void __objc_install_dtable_for_class (Class cls);
82 static void __objc_prepare_dtable_for_class (Class cls);
83 static void __objc_install_prepared_dtable_for_class (Class cls);
85 static struct sarray *__objc_prepared_dtable_for_class (Class cls);
86 static IMP __objc_get_prepared_imp (Class cls,SEL sel);
89 /* Various forwarding functions that are used based upon the
90 return type for the selector.
91 __objc_block_forward for structures.
92 __objc_double_forward for floats/doubles.
93 __objc_word_forward for pointers or types that fit in registers. */
94 static double __objc_double_forward (id, SEL, ...);
95 static id __objc_word_forward (id, SEL, ...);
96 typedef struct { id many[8]; } __big;
97 #if INVISIBLE_STRUCT_RETURN
98 static __big
99 #else
100 static id
101 #endif
102 __objc_block_forward (id, SEL, ...);
103 static struct objc_method * search_for_method_in_hierarchy (Class class, SEL sel);
104 struct objc_method * search_for_method_in_list (struct objc_method_list * list, SEL op);
105 id nil_method (id, SEL);
107 /* Make sure this inline function is exported regardless of GNU89 or C99
108 inlining semantics as it is part of the libobjc ABI. */
109 extern IMP __objc_get_forward_imp (id, SEL);
111 /* Given a selector, return the proper forwarding implementation. */
112 inline
114 __objc_get_forward_imp (id rcv, SEL sel)
116 /* If a custom forwarding hook was registered, try getting a
117 forwarding function from it. There are two forward routine hooks,
118 one that takes the receiver as an argument and one that does
119 not. */
120 if (__objc_msg_forward2)
122 IMP result;
123 if ((result = __objc_msg_forward2 (rcv, sel)) != NULL)
124 return result;
126 if (__objc_msg_forward)
128 IMP result;
129 if ((result = __objc_msg_forward (sel)) != NULL)
130 return result;
133 /* In all other cases, use the default forwarding functions built
134 using __builtin_apply and friends. */
136 const char *t = sel->sel_types;
138 if (t && (*t == '[' || *t == '(' || *t == '{')
139 #ifdef OBJC_MAX_STRUCT_BY_VALUE
140 && objc_sizeof_type (t) > OBJC_MAX_STRUCT_BY_VALUE
141 #endif
143 return (IMP)__objc_block_forward;
144 else if (t && (*t == 'f' || *t == 'd'))
145 return (IMP)__objc_double_forward;
146 else
147 return (IMP)__objc_word_forward;
151 /* Selectors for +resolveClassMethod: and +resolveInstanceMethod:.
152 These are set up at startup. */
153 static SEL selector_resolveClassMethod = NULL;
154 static SEL selector_resolveInstanceMethod = NULL;
156 /* Internal routines use to resolve a class method using
157 +resolveClassMethod:. 'class' is always a non-Nil class (*not* a
158 meta-class), and 'sel' is the selector that we are trying to
159 resolve. This must be called when class is not Nil, and the
160 dispatch table for class methods has already been installed.
162 This routine tries to call +resolveClassMethod: to give an
163 opportunity to resolve the method. If +resolveClassMethod: returns
164 YES, it tries looking up the method again, and if found, it returns
165 it. Else, it returns NULL. */
166 static inline
168 __objc_resolve_class_method (Class class, SEL sel)
170 /* We need to lookup +resolveClassMethod:. */
171 BOOL (*resolveMethodIMP) (id, SEL, SEL);
173 /* The dispatch table for class methods is already installed and we
174 don't want any forwarding to happen when looking up this method,
175 so we just look it up directly. Note that if 'sel' is precisely
176 +resolveClassMethod:, this would look it up yet again and find
177 nothing. That's no problem and there's no recursion. */
178 resolveMethodIMP = (BOOL (*) (id, SEL, SEL))sarray_get_safe
179 (class->class_pointer->dtable, (size_t) selector_resolveClassMethod->sel_id);
181 if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveClassMethod, sel))
183 /* +resolveClassMethod: returned YES. Look the method up again.
184 We already know the dtable is installed. */
186 /* TODO: There is the case where +resolveClassMethod: is buggy
187 and returned YES without actually adding the method. We
188 could maybe print an error message. */
189 return sarray_get_safe (class->class_pointer->dtable, (size_t) sel->sel_id);
192 return NULL;
195 /* Internal routines use to resolve a instance method using
196 +resolveInstanceMethod:. 'class' is always a non-Nil class, and
197 'sel' is the selector that we are trying to resolve. This must be
198 called when class is not Nil, and the dispatch table for instance
199 methods has already been installed.
201 This routine tries to call +resolveInstanceMethod: to give an
202 opportunity to resolve the method. If +resolveInstanceMethod:
203 returns YES, it tries looking up the method again, and if found, it
204 returns it. Else, it returns NULL. */
205 static inline
207 __objc_resolve_instance_method (Class class, SEL sel)
209 /* We need to lookup +resolveInstanceMethod:. */
210 BOOL (*resolveMethodIMP) (id, SEL, SEL);
212 /* The dispatch table for class methods may not be already installed
213 so we have to install it if needed. */
214 resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable,
215 (size_t) selector_resolveInstanceMethod->sel_id);
216 if (resolveMethodIMP == 0)
218 /* Try again after installing the dtable. */
219 if (class->class_pointer->dtable == __objc_uninstalled_dtable)
221 objc_mutex_lock (__objc_runtime_mutex);
222 if (class->class_pointer->dtable == __objc_uninstalled_dtable)
223 __objc_install_dtable_for_class (class->class_pointer);
224 objc_mutex_unlock (__objc_runtime_mutex);
226 resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable,
227 (size_t) selector_resolveInstanceMethod->sel_id);
230 if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveInstanceMethod, sel))
232 /* +resolveInstanceMethod: returned YES. Look the method up
233 again. We already know the dtable is installed. */
235 /* TODO: There is the case where +resolveInstanceMethod: is
236 buggy and returned YES without actually adding the method.
237 We could maybe print an error message. */
238 return sarray_get_safe (class->dtable, (size_t) sel->sel_id);
241 return NULL;
244 /* Given a CLASS and selector, return the implementation corresponding
245 to the method of the selector.
247 If CLASS is a class, the instance method is returned.
248 If CLASS is a meta class, the class method is returned.
250 Since this requires the dispatch table to be installed, this function
251 will implicitly invoke +initialize for CLASS if it hasn't been
252 invoked yet. This also insures that +initialize has been invoked
253 when the returned implementation is called directly.
255 The forwarding hooks require the receiver as an argument (if they are to
256 perform dynamic lookup in proxy objects etc), so this function has a
257 receiver argument to be used with those hooks. */
258 static inline
260 get_implementation (id receiver, Class class, SEL sel)
262 void *res;
264 if (class->dtable == __objc_uninstalled_dtable)
266 /* The dispatch table needs to be installed. */
267 objc_mutex_lock (__objc_runtime_mutex);
269 /* Double-checked locking pattern: Check
270 __objc_uninstalled_dtable again in case another thread
271 installed the dtable while we were waiting for the lock to be
272 released. */
273 if (class->dtable == __objc_uninstalled_dtable)
274 __objc_install_dtable_for_class (class);
276 /* If the dispatch table is not yet installed, we are still in
277 the process of executing +initialize. But the implementation
278 pointer should be available in the prepared ispatch table if
279 it exists at all. */
280 if (class->dtable == __objc_uninstalled_dtable)
282 assert (__objc_prepared_dtable_for_class (class) != 0);
283 res = __objc_get_prepared_imp (class, sel);
285 else
286 res = 0;
288 objc_mutex_unlock (__objc_runtime_mutex);
289 /* Call ourselves with the installed dispatch table and get the
290 real method. */
291 if (!res)
292 res = get_implementation (receiver, class, sel);
294 else
296 /* The dispatch table has been installed. */
297 res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
298 if (res == 0)
300 /* The dispatch table has been installed, and the method is
301 not in the dispatch table. So the method just doesn't
302 exist for the class. */
304 /* Try going through the +resolveClassMethod: or
305 +resolveInstanceMethod: process. */
306 if (CLS_ISMETA (class))
308 /* We have the meta class, but we need to invoke the
309 +resolveClassMethod: method on the class. So, we
310 need to obtain the class from the meta class, which
311 we do using the fact that both the class and the
312 meta-class have the same name. */
313 Class realClass = objc_lookUpClass (class->name);
314 if (realClass)
315 res = __objc_resolve_class_method (realClass, sel);
317 else
318 res = __objc_resolve_instance_method (class, sel);
320 if (res == 0)
321 res = __objc_get_forward_imp (receiver, sel);
324 return res;
327 /* Make sure this inline function is exported regardless of GNU89 or C99
328 inlining semantics as it is part of the libobjc ABI. */
329 extern IMP get_imp (Class, SEL);
331 inline
333 get_imp (Class class, SEL sel)
335 /* In a vanilla implementation we would first check if the dispatch
336 table is installed. Here instead, to get more speed in the
337 standard case (that the dispatch table is installed) we first try
338 to get the imp using brute force. Only if that fails, we do what
339 we should have been doing from the very beginning, that is, check
340 if the dispatch table needs to be installed, install it if it's
341 not installed, and retrieve the imp from the table if it's
342 installed. */
343 void *res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
344 if (res == 0)
346 res = get_implementation(nil, class, sel);
348 return res;
351 /* The new name of get_imp(). */
353 class_getMethodImplementation (Class class_, SEL selector)
355 if (class_ == Nil || selector == NULL)
356 return NULL;
358 /* get_imp is inlined, so we're good. */
359 return get_imp (class_, selector);
362 /* Given a method, return its implementation. This has been replaced
363 by method_getImplementation() in the modern API. */
365 method_get_imp (struct objc_method * method)
367 return (method != (struct objc_method *)0) ? method->method_imp : (IMP)0;
370 /* Query if an object can respond to a selector, returns YES if the
371 object implements the selector otherwise NO. Does not check if the
372 method can be forwarded. Since this requires the dispatch table to
373 installed, this function will implicitly invoke +initialize for the
374 class of OBJECT if it hasn't been invoked yet. */
375 inline
376 BOOL
377 __objc_responds_to (id object, SEL sel)
379 void *res;
380 struct sarray *dtable;
382 /* Install dispatch table if need be */
383 dtable = object->class_pointer->dtable;
384 if (dtable == __objc_uninstalled_dtable)
386 objc_mutex_lock (__objc_runtime_mutex);
387 if (object->class_pointer->dtable == __objc_uninstalled_dtable)
388 __objc_install_dtable_for_class (object->class_pointer);
390 /* If the dispatch table is not yet installed, we are still in
391 the process of executing +initialize. Yet the dispatch table
392 should be available. */
393 if (object->class_pointer->dtable == __objc_uninstalled_dtable)
395 dtable = __objc_prepared_dtable_for_class (object->class_pointer);
396 assert (dtable);
398 else
399 dtable = object->class_pointer->dtable;
401 objc_mutex_unlock (__objc_runtime_mutex);
404 /* Get the method from the dispatch table. */
405 res = sarray_get_safe (dtable, (size_t) sel->sel_id);
406 return (res != 0) ? YES : NO;
409 BOOL
410 class_respondsToSelector (Class class_, SEL selector)
412 struct sarray *dtable;
413 void *res;
415 if (class_ == Nil || selector == NULL)
416 return NO;
418 /* Install dispatch table if need be. */
419 dtable = class_->dtable;
420 if (dtable == __objc_uninstalled_dtable)
422 objc_mutex_lock (__objc_runtime_mutex);
423 if (class_->dtable == __objc_uninstalled_dtable)
424 __objc_install_dtable_for_class (class_);
426 /* If the dispatch table is not yet installed,
427 we are still in the process of executing +initialize.
428 Yet the dispatch table should be available. */
429 if (class_->dtable == __objc_uninstalled_dtable)
431 dtable = __objc_prepared_dtable_for_class (class_);
432 assert (dtable);
434 else
435 dtable = class_->dtable;
437 objc_mutex_unlock (__objc_runtime_mutex);
440 /* Get the method from the dispatch table. */
441 res = sarray_get_safe (dtable, (size_t) selector->sel_id);
442 return (res != 0) ? YES : NO;
445 /* This is the lookup function. All entries in the table are either a
446 valid method *or* zero. If zero then either the dispatch table
447 needs to be installed or it doesn't exist and forwarding is
448 attempted. */
450 objc_msg_lookup (id receiver, SEL op)
452 IMP result;
453 if (receiver)
455 /* First try a quick lookup assuming the dispatch table exists. */
456 result = sarray_get_safe (receiver->class_pointer->dtable,
457 (sidx)op->sel_id);
458 if (result == 0)
460 /* Not found ... call get_implementation () to install the
461 dispatch table and call +initialize as required,
462 providing the method implementation or a forwarding
463 function. */
464 result = get_implementation (receiver, receiver->class_pointer, op);
466 return result;
468 else
469 return (IMP)nil_method;
473 objc_msg_lookup_super (struct objc_super *super, SEL sel)
475 if (super->self)
476 return get_imp (super->super_class, sel);
477 else
478 return (IMP)nil_method;
481 void
482 __objc_init_dispatch_tables ()
484 __objc_uninstalled_dtable = sarray_new (200, 0);
486 /* TODO: It would be cool to register typed selectors here. */
487 selector_resolveClassMethod = sel_registerName ("resolveClassMethod:");
488 selector_resolveInstanceMethod = sel_registerName ("resolveInstanceMethod:");
492 /* Install dummy table for class which causes the first message to
493 that class (or instances hereof) to be initialized properly. */
494 void
495 __objc_install_premature_dtable (Class class)
497 assert (__objc_uninstalled_dtable);
498 class->dtable = __objc_uninstalled_dtable;
501 /* Send +initialize to class if not already done. */
502 static void
503 __objc_send_initialize (Class class)
505 /* This *must* be a class object. */
506 assert (CLS_ISCLASS (class));
507 assert (! CLS_ISMETA (class));
509 /* class_add_method_list/__objc_update_dispatch_table_for_class may
510 have reset the dispatch table. The canonical way to insure that
511 we send +initialize just once, is this flag. */
512 if (! CLS_ISINITIALIZED (class))
514 DEBUG_PRINTF ("+initialize: need to initialize class '%s'\n", class->name);
515 CLS_SETINITIALIZED (class);
516 CLS_SETINITIALIZED (class->class_pointer);
518 /* Create the garbage collector type memory description. */
519 __objc_generate_gc_type_description (class);
521 if (class->super_class)
522 __objc_send_initialize (class->super_class);
525 SEL op = sel_registerName ("initialize");
526 struct objc_method *method = search_for_method_in_hierarchy (class->class_pointer,
527 op);
529 if (method)
531 DEBUG_PRINTF (" begin of [%s +initialize]\n", class->name);
532 (*method->method_imp) ((id)class, op);
533 DEBUG_PRINTF (" end of [%s +initialize]\n", class->name);
535 #ifdef DEBUG
536 else
538 DEBUG_PRINTF (" class '%s' has no +initialize method\n", class->name);
540 #endif
545 /* Walk on the methods list of class and install the methods in the
546 reverse order of the lists. Since methods added by categories are
547 before the methods of class in the methods list, this allows
548 categories to substitute methods declared in class. However if
549 more than one category replaces the same method nothing is
550 guaranteed about what method will be used. Assumes that
551 __objc_runtime_mutex is locked down. */
552 static void
553 __objc_install_methods_in_dtable (struct sarray *dtable, struct objc_method_list * method_list)
555 int i;
557 if (! method_list)
558 return;
560 if (method_list->method_next)
561 __objc_install_methods_in_dtable (dtable, method_list->method_next);
563 for (i = 0; i < method_list->method_count; i++)
565 struct objc_method * method = &(method_list->method_list[i]);
566 sarray_at_put_safe (dtable,
567 (sidx) method->method_name->sel_id,
568 method->method_imp);
572 void
573 __objc_update_dispatch_table_for_class (Class class)
575 Class next;
576 struct sarray *arr;
578 DEBUG_PRINTF (" _objc_update_dtable_for_class (%s)\n", class->name);
580 objc_mutex_lock (__objc_runtime_mutex);
582 /* Not yet installed -- skip it unless in +initialize. */
583 if (class->dtable == __objc_uninstalled_dtable)
585 if (__objc_prepared_dtable_for_class (class))
587 /* There is a prepared table so we must be initialising this
588 class ... we must re-do the table preparation. */
589 __objc_prepare_dtable_for_class (class);
591 objc_mutex_unlock (__objc_runtime_mutex);
592 return;
595 arr = class->dtable;
596 __objc_install_premature_dtable (class); /* someone might require it... */
597 sarray_free (arr); /* release memory */
599 /* Could have been lazy... */
600 __objc_install_dtable_for_class (class);
602 if (class->subclass_list) /* Traverse subclasses. */
603 for (next = class->subclass_list; next; next = next->sibling_class)
604 __objc_update_dispatch_table_for_class (next);
606 objc_mutex_unlock (__objc_runtime_mutex);
609 /* This function adds a method list to a class. This function is
610 typically called by another function specific to the run-time. As
611 such this function does not worry about thread safe issues.
613 This one is only called for categories. Class objects have their
614 methods installed right away, and their selectors are made into
615 SEL's by the function __objc_register_selectors_from_class. */
616 void
617 class_add_method_list (Class class, struct objc_method_list * list)
619 /* Passing of a linked list is not allowed. Do multiple calls. */
620 assert (! list->method_next);
622 __objc_register_selectors_from_list(list);
624 /* Add the methods to the class's method list. */
625 list->method_next = class->methods;
626 class->methods = list;
628 /* Update the dispatch table of class. */
629 __objc_update_dispatch_table_for_class (class);
632 struct objc_method *
633 class_getInstanceMethod (Class class_, SEL selector)
635 struct objc_method *m;
637 if (class_ == Nil || selector == NULL)
638 return NULL;
640 m = search_for_method_in_hierarchy (class_, selector);
641 if (m)
642 return m;
644 /* Try going through +resolveInstanceMethod:, and do the search
645 again if successful. */
646 if (__objc_resolve_instance_method (class_, selector))
647 return search_for_method_in_hierarchy (class_, selector);
649 return NULL;
652 struct objc_method *
653 class_getClassMethod (Class class_, SEL selector)
655 struct objc_method *m;
657 if (class_ == Nil || selector == NULL)
658 return NULL;
660 m = search_for_method_in_hierarchy (class_->class_pointer,
661 selector);
662 if (m)
663 return m;
665 /* Try going through +resolveClassMethod:, and do the search again
666 if successful. */
667 if (__objc_resolve_class_method (class_, selector))
668 return search_for_method_in_hierarchy (class_->class_pointer,
669 selector);
671 return NULL;
674 BOOL
675 class_addMethod (Class class_, SEL selector, IMP implementation,
676 const char *method_types)
678 struct objc_method_list *method_list;
679 struct objc_method *method;
680 const char *method_name;
682 if (class_ == Nil || selector == NULL || implementation == NULL
683 || method_types == NULL || (strcmp (method_types, "") == 0))
684 return NO;
686 method_name = sel_getName (selector);
687 if (method_name == NULL)
688 return NO;
690 /* If the method already exists in the class, return NO. It is fine
691 if the method already exists in the superclass; in that case, we
692 are overriding it. */
693 if (CLS_IS_IN_CONSTRUCTION (class_))
695 /* The class only contains a list of methods; they have not been
696 registered yet, ie, the method_name of each of them is still
697 a string, not a selector. Iterate manually over them to
698 check if we have already added the method. */
699 struct objc_method_list * method_list = class_->methods;
700 while (method_list)
702 int i;
704 /* Search the method list. */
705 for (i = 0; i < method_list->method_count; ++i)
707 struct objc_method * method = &method_list->method_list[i];
709 if (method->method_name
710 && strcmp ((char *)method->method_name, method_name) == 0)
711 return NO;
714 /* The method wasn't found. Follow the link to the next list of
715 methods. */
716 method_list = method_list->method_next;
718 /* The method wasn't found. It's a new one. Go ahead and add
719 it. */
721 else
723 /* Do the standard lookup. This assumes the selectors are
724 mapped. */
725 if (search_for_method_in_list (class_->methods, selector))
726 return NO;
729 method_list = (struct objc_method_list *)objc_calloc (1, sizeof (struct objc_method_list));
730 method_list->method_count = 1;
732 method = &(method_list->method_list[0]);
733 method->method_name = objc_malloc (strlen (method_name) + 1);
734 strcpy ((char *)method->method_name, method_name);
736 method->method_types = objc_malloc (strlen (method_types) + 1);
737 strcpy ((char *)method->method_types, method_types);
739 method->method_imp = implementation;
741 if (CLS_IS_IN_CONSTRUCTION (class_))
743 /* We only need to add the method to the list. It will be
744 registered with the runtime when the class pair is registered
745 (if ever). */
746 method_list->method_next = class_->methods;
747 class_->methods = method_list;
749 else
751 /* Add the method to a live class. */
752 objc_mutex_lock (__objc_runtime_mutex);
753 class_add_method_list (class_, method_list);
754 objc_mutex_unlock (__objc_runtime_mutex);
757 return YES;
761 class_replaceMethod (Class class_, SEL selector, IMP implementation,
762 const char *method_types)
764 struct objc_method * method;
766 if (class_ == Nil || selector == NULL || implementation == NULL
767 || method_types == NULL)
768 return NULL;
770 method = search_for_method_in_hierarchy (class_, selector);
772 if (method)
774 return method_setImplementation (method, implementation);
776 else
778 class_addMethod (class_, selector, implementation, method_types);
779 return NULL;
783 /* Search for a method starting from the current class up its
784 hierarchy. Return a pointer to the method's method structure if
785 found. NULL otherwise. */
786 static struct objc_method *
787 search_for_method_in_hierarchy (Class cls, SEL sel)
789 struct objc_method * method = NULL;
790 Class class;
792 if (! sel_is_mapped (sel))
793 return NULL;
795 /* Scan the method list of the class. If the method isn't found in
796 the list then step to its super class. */
797 for (class = cls; ((! method) && class); class = class->super_class)
798 method = search_for_method_in_list (class->methods, sel);
800 return method;
805 /* Given a linked list of method and a method's name. Search for the
806 named method's method structure. Return a pointer to the method's
807 method structure if found. NULL otherwise. */
808 struct objc_method *
809 search_for_method_in_list (struct objc_method_list * list, SEL op)
811 struct objc_method_list * method_list = list;
813 if (! sel_is_mapped (op))
814 return NULL;
816 /* If not found then we'll search the list. */
817 while (method_list)
819 int i;
821 /* Search the method list. */
822 for (i = 0; i < method_list->method_count; ++i)
824 struct objc_method * method = &method_list->method_list[i];
826 if (method->method_name)
827 if (method->method_name->sel_id == op->sel_id)
828 return method;
831 /* The method wasn't found. Follow the link to the next list of
832 methods. */
833 method_list = method_list->method_next;
836 return NULL;
839 typedef void * retval_t;
840 typedef void * arglist_t;
842 static retval_t __objc_forward (id object, SEL sel, arglist_t args);
844 /* Forwarding pointers/integers through the normal registers. */
845 static id
846 __objc_word_forward (id rcv, SEL op, ...)
848 void *args, *res;
850 args = __builtin_apply_args ();
851 res = __objc_forward (rcv, op, args);
852 if (res)
853 __builtin_return (res);
854 else
855 return res;
858 /* Specific routine for forwarding floats/double because of
859 architectural differences on some processors. i386s for example
860 which uses a floating point stack versus general registers for
861 floating point numbers. This forward routine makes sure that GCC
862 restores the proper return values. */
863 static double
864 __objc_double_forward (id rcv, SEL op, ...)
866 void *args, *res;
868 args = __builtin_apply_args ();
869 res = __objc_forward (rcv, op, args);
870 __builtin_return (res);
873 #if INVISIBLE_STRUCT_RETURN
874 static __big
875 #else
876 static id
877 #endif
878 __objc_block_forward (id rcv, SEL op, ...)
880 void *args, *res;
882 args = __builtin_apply_args ();
883 res = __objc_forward (rcv, op, args);
884 if (res)
885 __builtin_return (res);
886 else
887 #if INVISIBLE_STRUCT_RETURN
888 return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}};
889 #else
890 return nil;
891 #endif
895 /* This function is called for methods which are not implemented,
896 unless a custom forwarding routine has been installed. Please note
897 that most serious users of libobjc (eg, GNUstep base) do install
898 their own forwarding routines, and hence this is never actually
899 used. But, if no custom forwarding routine is installed, this is
900 called when a selector is not recognized. */
901 static retval_t
902 __objc_forward (id object, SEL sel, arglist_t args)
904 IMP imp;
905 static SEL frwd_sel = 0; /* !T:SAFE2 */
906 SEL err_sel;
908 /* First try if the object understands forward::. */
909 if (! frwd_sel)
910 frwd_sel = sel_get_any_uid ("forward::");
912 if (__objc_responds_to (object, frwd_sel))
914 imp = get_implementation (object, object->class_pointer, frwd_sel);
915 return (*imp) (object, frwd_sel, sel, args);
918 /* If the object recognizes the doesNotRecognize: method then we're
919 going to send it. */
920 err_sel = sel_get_any_uid ("doesNotRecognize:");
921 if (__objc_responds_to (object, err_sel))
923 imp = get_implementation (object, object->class_pointer, err_sel);
924 return (*imp) (object, err_sel, sel);
927 /* The object doesn't recognize the method. Check for responding to
928 error:. If it does then sent it. */
930 char msg[256 + strlen ((const char *) sel_getName (sel))
931 + strlen ((const char *) object->class_pointer->name)];
933 sprintf (msg, "(%s) %s does not recognize %s",
934 (CLS_ISMETA (object->class_pointer)
935 ? "class"
936 : "instance" ),
937 object->class_pointer->name, sel_getName (sel));
939 /* The object doesn't respond to doesNotRecognize:. Therefore, a
940 default action is taken. */
941 _objc_abort ("%s\n", msg);
943 return 0;
947 void
948 __objc_print_dtable_stats (void)
950 int total = 0;
952 objc_mutex_lock (__objc_runtime_mutex);
954 #ifdef OBJC_SPARSE2
955 printf ("memory usage: (%s)\n", "2-level sparse arrays");
956 #else
957 printf ("memory usage: (%s)\n", "3-level sparse arrays");
958 #endif
960 printf ("arrays: %d = %ld bytes\n", narrays,
961 (long) ((size_t) narrays * sizeof (struct sarray)));
962 total += narrays * sizeof (struct sarray);
963 printf ("buckets: %d = %ld bytes\n", nbuckets,
964 (long) ((size_t) nbuckets * sizeof (struct sbucket)));
965 total += nbuckets * sizeof (struct sbucket);
967 printf ("idxtables: %d = %ld bytes\n",
968 idxsize, (long) ((size_t) idxsize * sizeof (void *)));
969 total += idxsize * sizeof (void *);
970 printf ("-----------------------------------\n");
971 printf ("total: %d bytes\n", total);
972 printf ("===================================\n");
974 objc_mutex_unlock (__objc_runtime_mutex);
977 static cache_ptr prepared_dtable_table = 0;
979 /* This function is called by: objc_msg_lookup, get_imp and
980 __objc_responds_to (and the dispatch table installation functions
981 themselves) to install a dispatch table for a class.
983 If CLS is a class, it installs instance methods.
984 If CLS is a meta class, it installs class methods.
986 In either case +initialize is invoked for the corresponding class.
988 The implementation must insure that the dispatch table is not
989 installed until +initialize completes. Otherwise it opens a
990 potential race since the installation of the dispatch table is used
991 as gate in regular method dispatch and we need to guarantee that
992 +initialize is the first method invoked an that no other thread my
993 dispatch messages to the class before +initialize completes. */
994 static void
995 __objc_install_dtable_for_class (Class cls)
997 /* If the class has not yet had its class links resolved, we must
998 re-compute all class links. */
999 if (! CLS_ISRESOLV (cls))
1000 __objc_resolve_class_links ();
1002 /* Make sure the super class has its dispatch table installed or is
1003 at least preparing. We do not need to send initialize for the
1004 super class since __objc_send_initialize will insure that. */
1005 if (cls->super_class
1006 && cls->super_class->dtable == __objc_uninstalled_dtable
1007 && !__objc_prepared_dtable_for_class (cls->super_class))
1009 __objc_install_dtable_for_class (cls->super_class);
1010 /* The superclass initialisation may have also initialised the
1011 current class, in which case there is no more to do. */
1012 if (cls->dtable != __objc_uninstalled_dtable)
1013 return;
1016 /* We have already been prepared but +initialize hasn't completed.
1017 The +initialize implementation is probably sending 'self'
1018 messages. We rely on _objc_get_prepared_imp to retrieve the
1019 implementation pointers. */
1020 if (__objc_prepared_dtable_for_class (cls))
1021 return;
1023 /* We have this function cache the implementation pointers for
1024 _objc_get_prepared_imp but the dispatch table won't be initilized
1025 until __objc_send_initialize completes. */
1026 __objc_prepare_dtable_for_class (cls);
1028 /* We may have already invoked +initialize but
1029 __objc_update_dispatch_table_for_class invoked by
1030 class_add_method_list may have reset dispatch table. */
1032 /* Call +initialize. If we are a real class, we are installing
1033 instance methods. If we are a meta class, we are installing
1034 class methods. The __objc_send_initialize itself will insure
1035 that the message is called only once per class. */
1036 if (CLS_ISCLASS (cls))
1037 __objc_send_initialize (cls);
1038 else
1040 /* Retrieve the class from the meta class. */
1041 Class c = objc_getClass (cls->name);
1042 assert (CLS_ISMETA (cls));
1043 assert (c);
1044 __objc_send_initialize (c);
1047 /* We install the dispatch table correctly when +initialize completed. */
1048 __objc_install_prepared_dtable_for_class (cls);
1051 /* Builds the dispatch table for the class CLS and stores it in a
1052 place where it can be retrieved by __objc_get_prepared_imp until
1053 __objc_install_prepared_dtable_for_class installs it into the
1054 class. The dispatch table should not be installed into the class
1055 until +initialize has completed. */
1056 static void
1057 __objc_prepare_dtable_for_class (Class cls)
1059 struct sarray *dtable;
1060 struct sarray *super_dtable;
1062 /* This table could be initialized in init.c. We can not use the
1063 class name since the class maintains the instance methods and the
1064 meta class maintains the the class methods yet both share the
1065 same name. Classes should be unique in any program. */
1066 if (! prepared_dtable_table)
1067 prepared_dtable_table
1068 = objc_hash_new (32,
1069 (hash_func_type) objc_hash_ptr,
1070 (compare_func_type) objc_compare_ptrs);
1072 /* If the class has not yet had its class links resolved, we must
1073 re-compute all class links. */
1074 if (! CLS_ISRESOLV (cls))
1075 __objc_resolve_class_links ();
1077 assert (cls);
1078 assert (cls->dtable == __objc_uninstalled_dtable);
1080 /* If there is already a prepared dtable for this class, we must
1081 replace it with a new version (since there must have been methods
1082 added to or otherwise modified in the class while executing
1083 +initialize, and the table needs to be recomputed. */
1084 dtable = __objc_prepared_dtable_for_class (cls);
1085 if (dtable != 0)
1087 objc_hash_remove (prepared_dtable_table, cls);
1088 sarray_free (dtable);
1091 /* Now prepare the dtable for population. */
1092 assert (cls != cls->super_class);
1093 if (cls->super_class)
1095 /* Inherit the method list from the super class. Yet the super
1096 class may still be initializing in the case when a class
1097 cluster sub class initializes its super classes. */
1098 if (cls->super_class->dtable == __objc_uninstalled_dtable)
1099 __objc_install_dtable_for_class (cls->super_class);
1101 super_dtable = cls->super_class->dtable;
1102 /* If the dispatch table is not yet installed, we are still in
1103 the process of executing +initialize. Yet the dispatch table
1104 should be available. */
1105 if (super_dtable == __objc_uninstalled_dtable)
1106 super_dtable = __objc_prepared_dtable_for_class (cls->super_class);
1108 assert (super_dtable);
1109 dtable = sarray_lazy_copy (super_dtable);
1111 else
1112 dtable = sarray_new (__objc_selector_max_index, 0);
1114 __objc_install_methods_in_dtable (dtable, cls->methods);
1116 objc_hash_add (&prepared_dtable_table,
1117 cls,
1118 dtable);
1121 /* This wrapper only exists to allow an easy replacement of the lookup
1122 implementation and it is expected that the compiler will optimize
1123 it away. */
1124 static struct sarray *
1125 __objc_prepared_dtable_for_class (Class cls)
1127 struct sarray *dtable = 0;
1128 assert (cls);
1129 if (prepared_dtable_table)
1130 dtable = objc_hash_value_for_key (prepared_dtable_table, cls);
1131 /* dtable my be nil, since we call this to check whether we are
1132 currently preparing before we start preparing. */
1133 return dtable;
1136 /* Helper function for messages sent to CLS or implementation pointers
1137 retrieved from CLS during +initialize before the dtable is
1138 installed. When a class implicitly initializes another class which
1139 in turn implicitly invokes methods in this class, before the
1140 implementation of +initialize of CLS completes, this returns the
1141 expected implementation. Forwarding remains the responsibility of
1142 objc_msg_lookup. This function should only be called under the
1143 global lock. */
1144 static IMP
1145 __objc_get_prepared_imp (Class cls,SEL sel)
1147 struct sarray *dtable;
1148 IMP imp;
1150 assert (cls);
1151 assert (sel);
1152 assert (cls->dtable == __objc_uninstalled_dtable);
1153 dtable = __objc_prepared_dtable_for_class (cls);
1155 assert (dtable);
1156 assert (dtable != __objc_uninstalled_dtable);
1157 imp = sarray_get_safe (dtable, (size_t) sel->sel_id);
1159 /* imp may be Nil if the method does not exist and we may fallback
1160 to the forwarding implementation later. */
1161 return imp;
1164 /* When this function is called +initialize should be completed. So
1165 now we are safe to install the dispatch table for the class so that
1166 they become available for other threads that may be waiting in the
1167 lock. */
1168 static void
1169 __objc_install_prepared_dtable_for_class (Class cls)
1171 assert (cls);
1172 assert (cls->dtable == __objc_uninstalled_dtable);
1173 cls->dtable = __objc_prepared_dtable_for_class (cls);
1175 assert (cls->dtable);
1176 assert (cls->dtable != __objc_uninstalled_dtable);
1177 objc_hash_remove (prepared_dtable_table, cls);