1 /* GNU Objective C Runtime message lookup
2 Copyright (C) 1993, 1995, 1996, 1997, 1998,
3 2001, 2002, 2004, 2009, 2010 Free Software Foundation, Inc.
4 Contributed by Kresten Krab Thorup
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under the
9 terms of the GNU General Public License as published by the Free Software
10 Foundation; either version 3, or (at your option) any later version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 /* Uncommented the following line to enable debug logging. Use this
27 only while debugging the runtime. */
30 /* FIXME: This file has no business including tm.h. */
31 /* FIXME: This should be using libffi instead of __builtin_apply
34 #include "objc-private/common.h"
35 #include "objc-private/error.h"
37 #include "coretypes.h"
39 #include "objc/runtime.h"
40 #include "objc/message.h" /* For objc_msg_lookup(), objc_msg_lookup_super(). */
42 #include "objc-private/module-abi-8.h"
43 #include "objc-private/runtime.h"
44 #include "objc-private/hash.h"
45 #include "objc-private/sarray.h"
46 #include "objc-private/selector.h" /* For sel_is_mapped() */
47 #include "runtime-info.h"
48 #include <assert.h> /* For assert */
49 #include <string.h> /* For strlen */
51 /* This is how we hack STRUCT_VALUE to be 1 or 0. */
52 #define gen_rtx(args...) 1
53 #define gen_rtx_MEM(args...) 1
54 #define gen_rtx_REG(args...) 1
55 /* Already defined in gcc/coretypes.h. So prevent double definition warning. */
59 #if ! defined (STRUCT_VALUE) || STRUCT_VALUE == 0
60 #define INVISIBLE_STRUCT_RETURN 1
62 #define INVISIBLE_STRUCT_RETURN 0
65 /* The uninstalled dispatch table. */
66 struct sarray *__objc_uninstalled_dtable = 0; /* !T:MUTEX */
68 /* Two hooks for method forwarding. If either is set, it is invoked to
69 * return a function that performs the real forwarding. If both are
70 * set, the result of __objc_msg_forward2 will be preferred over that
71 * of __objc_msg_forward. If both return NULL or are unset, the
72 * libgcc based functions (__builtin_apply and friends) are used. */
73 IMP (*__objc_msg_forward) (SEL) = NULL;
74 IMP (*__objc_msg_forward2) (id, SEL) = NULL;
76 /* Send +initialize to class. */
77 static void __objc_send_initialize (Class);
79 /* Forward declare some functions */
80 static void __objc_install_dtable_for_class (Class cls);
81 static void __objc_prepare_dtable_for_class (Class cls);
82 static void __objc_install_prepared_dtable_for_class (Class cls);
84 static struct sarray *__objc_prepared_dtable_for_class (Class cls);
85 static IMP __objc_get_prepared_imp (Class cls,SEL sel);
88 /* Various forwarding functions that are used based upon the
89 return type for the selector.
90 __objc_block_forward for structures.
91 __objc_double_forward for floats/doubles.
92 __objc_word_forward for pointers or types that fit in registers. */
93 static double __objc_double_forward (id, SEL, ...);
94 static id __objc_word_forward (id, SEL, ...);
95 typedef struct { id many[8]; } __big;
96 #if INVISIBLE_STRUCT_RETURN
101 __objc_block_forward (id, SEL, ...);
102 static struct objc_method * search_for_method_in_hierarchy (Class class, SEL sel);
103 struct objc_method * search_for_method_in_list (struct objc_method_list * list, SEL op);
104 id nil_method (id, SEL);
106 /* Given a selector, return the proper forwarding implementation. */
109 __objc_get_forward_imp (id rcv, SEL sel)
111 /* If a custom forwarding hook was registered, try getting a
112 forwarding function from it. There are two forward routine hooks,
113 one that takes the receiver as an argument and one that does
115 if (__objc_msg_forward2)
118 if ((result = __objc_msg_forward2 (rcv, sel)) != NULL)
121 if (__objc_msg_forward)
124 if ((result = __objc_msg_forward (sel)) != NULL)
128 /* In all other cases, use the default forwarding functions built
129 using __builtin_apply and friends. */
131 const char *t = sel->sel_types;
133 if (t && (*t == '[' || *t == '(' || *t == '{')
134 #ifdef OBJC_MAX_STRUCT_BY_VALUE
135 && objc_sizeof_type (t) > OBJC_MAX_STRUCT_BY_VALUE
138 return (IMP)__objc_block_forward;
139 else if (t && (*t == 'f' || *t == 'd'))
140 return (IMP)__objc_double_forward;
142 return (IMP)__objc_word_forward;
146 /* Selectors for +resolveClassMethod: and +resolveInstanceMethod:.
147 These are set up at startup. */
148 static SEL selector_resolveClassMethod = NULL;
149 static SEL selector_resolveInstanceMethod = NULL;
151 /* Internal routines use to resolve a class method using
152 +resolveClassMethod:. 'class' is always a non-Nil class (*not* a
153 meta-class), and 'sel' is the selector that we are trying to
154 resolve. This must be called when class is not Nil, and the
155 dispatch table for class methods has already been installed.
157 This routine tries to call +resolveClassMethod: to give an
158 opportunity to resolve the method. If +resolveClassMethod: returns
159 YES, it tries looking up the method again, and if found, it returns
160 it. Else, it returns NULL. */
163 __objc_resolve_class_method (Class class, SEL sel)
165 /* We need to lookup +resolveClassMethod:. */
166 BOOL (*resolveMethodIMP) (id, SEL, SEL);
168 /* The dispatch table for class methods is already installed and we
169 don't want any forwarding to happen when looking up this method,
170 so we just look it up directly. Note that if 'sel' is precisely
171 +resolveClassMethod:, this would look it up yet again and find
172 nothing. That's no problem and there's no recursion. */
173 resolveMethodIMP = (BOOL (*) (id, SEL, SEL))sarray_get_safe
174 (class->class_pointer->dtable, (size_t) selector_resolveClassMethod->sel_id);
176 if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveClassMethod, sel))
178 /* +resolveClassMethod: returned YES. Look the method up again.
179 We already know the dtable is installed. */
181 /* TODO: There is the case where +resolveClassMethod: is buggy
182 and returned YES without actually adding the method. We
183 could maybe print an error message. */
184 return sarray_get_safe (class->class_pointer->dtable, (size_t) sel->sel_id);
190 /* Internal routines use to resolve a instance method using
191 +resolveInstanceMethod:. 'class' is always a non-Nil class, and
192 'sel' is the selector that we are trying to resolve. This must be
193 called when class is not Nil, and the dispatch table for instance
194 methods has already been installed.
196 This routine tries to call +resolveInstanceMethod: to give an
197 opportunity to resolve the method. If +resolveInstanceMethod:
198 returns YES, it tries looking up the method again, and if found, it
199 returns it. Else, it returns NULL. */
202 __objc_resolve_instance_method (Class class, SEL sel)
204 /* We need to lookup +resolveInstanceMethod:. */
205 BOOL (*resolveMethodIMP) (id, SEL, SEL);
207 /* The dispatch table for class methods may not be already installed
208 so we have to install it if needed. */
209 resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable,
210 (size_t) selector_resolveInstanceMethod->sel_id);
211 if (resolveMethodIMP == 0)
213 /* Try again after installing the dtable. */
214 if (class->class_pointer->dtable == __objc_uninstalled_dtable)
216 objc_mutex_lock (__objc_runtime_mutex);
217 if (class->class_pointer->dtable == __objc_uninstalled_dtable)
218 __objc_install_dtable_for_class (class->class_pointer);
219 objc_mutex_unlock (__objc_runtime_mutex);
221 resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable,
222 (size_t) selector_resolveInstanceMethod->sel_id);
225 if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveInstanceMethod, sel))
227 /* +resolveInstanceMethod: returned YES. Look the method up
228 again. We already know the dtable is installed. */
230 /* TODO: There is the case where +resolveInstanceMethod: is
231 buggy and returned YES without actually adding the method.
232 We could maybe print an error message. */
233 return sarray_get_safe (class->dtable, (size_t) sel->sel_id);
239 /* Given a CLASS and selector, return the implementation corresponding
240 to the method of the selector.
242 If CLASS is a class, the instance method is returned.
243 If CLASS is a meta class, the class method is returned.
245 Since this requires the dispatch table to be installed, this function
246 will implicitly invoke +initialize for CLASS if it hasn't been
247 invoked yet. This also insures that +initialize has been invoked
248 when the returned implementation is called directly.
250 The forwarding hooks require the receiver as an argument (if they are to
251 perform dynamic lookup in proxy objects etc), so this function has a
252 receiver argument to be used with those hooks. */
255 get_implementation (id receiver, Class class, SEL sel)
259 if (class->dtable == __objc_uninstalled_dtable)
261 /* The dispatch table needs to be installed. */
262 objc_mutex_lock (__objc_runtime_mutex);
264 /* Double-checked locking pattern: Check
265 __objc_uninstalled_dtable again in case another thread
266 installed the dtable while we were waiting for the lock
268 if (class->dtable == __objc_uninstalled_dtable)
270 __objc_install_dtable_for_class (class);
273 /* If the dispatch table is not yet installed,
274 we are still in the process of executing +initialize.
275 But the implementation pointer should be available
276 in the prepared ispatch table if it exists at all. */
277 if (class->dtable == __objc_uninstalled_dtable)
279 assert (__objc_prepared_dtable_for_class (class) != 0);
280 res = __objc_get_prepared_imp (class, sel);
286 objc_mutex_unlock (__objc_runtime_mutex);
287 /* Call ourselves with the installed dispatch table and get
290 res = get_implementation (receiver, class, sel);
294 /* The dispatch table has been installed. */
295 res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
298 /* The dispatch table has been installed, and the method
299 is not in the dispatch table. So the method just
300 doesn't exist for the class. */
302 /* Try going through the +resolveClassMethod: or
303 +resolveInstanceMethod: process. */
304 if (CLS_ISMETA (class))
306 /* We have the meta class, but we need to invoke the
307 +resolveClassMethod: method on the class. So, we
308 need to obtain the class from the meta class,
309 which we do using the fact that both the class
310 and the meta-class have the same name. */
311 Class realClass = objc_lookUpClass (class->name);
313 res = __objc_resolve_class_method (realClass, sel);
316 res = __objc_resolve_instance_method (class, sel);
320 res = __objc_get_forward_imp (receiver, sel);
329 get_imp (Class class, SEL sel)
331 /* In a vanilla implementation we would first check if the dispatch
332 table is installed. Here instead, to get more speed in the
333 standard case (that the dispatch table is installed) we first try
334 to get the imp using brute force. Only if that fails, we do what
335 we should have been doing from the very beginning, that is, check
336 if the dispatch table needs to be installed, install it if it's
337 not installed, and retrieve the imp from the table if it's
339 void *res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
342 res = get_implementation(nil, class, sel);
347 /* The new name of get_imp(). */
349 class_getMethodImplementation (Class class_, SEL selector)
351 if (class_ == Nil || selector == NULL)
354 /* get_imp is inlined, so we're good. */
355 return get_imp (class_, selector);
358 /* Given a method, return its implementation. This has been replaced
359 by method_getImplementation() in the modern API. */
361 method_get_imp (struct objc_method * method)
363 return (method != (struct objc_method *)0) ? method->method_imp : (IMP)0;
366 /* Query if an object can respond to a selector, returns YES if the
367 object implements the selector otherwise NO. Does not check if the
368 method can be forwarded.
369 Since this requires the dispatch table to installed, this function
370 will implicitly invoke +initialize for the class of OBJECT if it
371 hasn't been invoked yet. */
374 __objc_responds_to (id object, SEL sel)
377 struct sarray *dtable;
379 /* Install dispatch table if need be */
380 dtable = object->class_pointer->dtable;
381 if (dtable == __objc_uninstalled_dtable)
383 objc_mutex_lock (__objc_runtime_mutex);
384 if (object->class_pointer->dtable == __objc_uninstalled_dtable)
385 __objc_install_dtable_for_class (object->class_pointer);
387 /* If the dispatch table is not yet installed,
388 we are still in the process of executing +initialize.
389 Yet the dispatch table should be available. */
390 if (object->class_pointer->dtable == __objc_uninstalled_dtable)
392 dtable = __objc_prepared_dtable_for_class (object->class_pointer);
396 dtable = object->class_pointer->dtable;
398 objc_mutex_unlock (__objc_runtime_mutex);
401 /* Get the method from the dispatch table. */
402 res = sarray_get_safe (dtable, (size_t) sel->sel_id);
403 return (res != 0) ? YES : NO;
407 class_respondsToSelector (Class class_, SEL selector)
409 struct sarray *dtable;
412 if (class_ == Nil || selector == NULL)
415 /* Install dispatch table if need be. */
416 dtable = class_->dtable;
417 if (dtable == __objc_uninstalled_dtable)
419 objc_mutex_lock (__objc_runtime_mutex);
420 if (class_->dtable == __objc_uninstalled_dtable)
422 __objc_install_dtable_for_class (class_);
424 /* If the dispatch table is not yet installed,
425 we are still in the process of executing +initialize.
426 Yet the dispatch table should be available. */
427 if (class_->dtable == __objc_uninstalled_dtable)
429 dtable = __objc_prepared_dtable_for_class (class_);
433 dtable = class_->dtable;
434 objc_mutex_unlock (__objc_runtime_mutex);
437 /* Get the method from the dispatch table. */
438 res = sarray_get_safe (dtable, (size_t) selector->sel_id);
439 return (res != 0) ? YES : NO;
442 /* This is the lookup function. All entries in the table are either a
443 valid method *or* zero. If zero then either the dispatch table
444 needs to be installed or it doesn't exist and forwarding is
447 objc_msg_lookup (id receiver, SEL op)
452 /* First try a quick lookup assuming the dispatch table exists. */
453 result = sarray_get_safe (receiver->class_pointer->dtable,
457 /* Not found ... call get_implementation () to install the dispatch
458 table and call +initialize as required, providing the method
459 implementation or a forwarding function */
460 result = get_implementation (receiver, receiver->class_pointer, op);
465 return (IMP)nil_method;
469 objc_msg_lookup_super (struct objc_super *super, SEL sel)
472 return get_imp (super->super_class, sel);
474 return (IMP)nil_method;
477 /* Temporarily defined here until objc_msg_sendv() goes away. */
478 char *method_get_first_argument (struct objc_method *,
481 char *method_get_next_argument (arglist_t argframe,
483 int method_get_sizeof_arguments (struct objc_method *);
486 class_get_instance_method (Class class, SEL op);
489 objc_msg_sendv (id object, SEL op, arglist_t arg_frame)
491 struct objc_method *m = class_get_instance_method (object->class_pointer, op);
493 *((id *) method_get_first_argument (m, arg_frame, &type)) = object;
494 *((SEL *) method_get_next_argument (arg_frame, &type)) = op;
495 return __builtin_apply ((apply_t) m->method_imp,
497 method_get_sizeof_arguments (m));
501 __objc_init_dispatch_tables ()
503 __objc_uninstalled_dtable = sarray_new (200, 0);
505 /* TODO: It would be cool to register typed selectors here. */
506 selector_resolveClassMethod = sel_registerName ("resolveClassMethod:");
507 selector_resolveInstanceMethod =sel_registerName ("resolveInstanceMethod:");
511 /* Install dummy table for class which causes the first message to
512 that class (or instances hereof) to be initialized properly. */
514 __objc_install_premature_dtable (Class class)
516 assert (__objc_uninstalled_dtable);
517 class->dtable = __objc_uninstalled_dtable;
520 /* Send +initialize to class if not already done. */
522 __objc_send_initialize (Class class)
524 /* This *must* be a class object. */
525 assert (CLS_ISCLASS (class));
526 assert (! CLS_ISMETA (class));
528 /* class_add_method_list/__objc_update_dispatch_table_for_class
529 may have reset the dispatch table. The canonical way to insure
530 that we send +initialize just once, is this flag. */
531 if (! CLS_ISINITIALIZED (class))
533 DEBUG_PRINTF ("+initialize: need to initialize class '%s'\n", class->name);
534 CLS_SETINITIALIZED (class);
535 CLS_SETINITIALIZED (class->class_pointer);
537 /* Create the garbage collector type memory description. */
538 __objc_generate_gc_type_description (class);
540 if (class->super_class)
541 __objc_send_initialize (class->super_class);
544 SEL op = sel_registerName ("initialize");
546 struct objc_method_list * method_list = class->class_pointer->methods;
551 struct objc_method * method;
553 for (i = 0; i < method_list->method_count; i++)
555 method = &(method_list->method_list[i]);
556 if (method->method_name
557 && method->method_name->sel_id == op->sel_id)
559 imp = method->method_imp;
567 method_list = method_list->method_next;
571 DEBUG_PRINTF (" begin of [%s +initialize]\n", class->name);
572 (*imp) ((id) class, op);
573 DEBUG_PRINTF (" end of [%s +initialize]\n", class->name);
578 DEBUG_PRINTF (" class '%s' has no +initialize method\n", class->name);
585 /* Walk on the methods list of class and install the methods in the
586 reverse order of the lists. Since methods added by categories are
587 before the methods of class in the methods list, this allows
588 categories to substitute methods declared in class. However if
589 more than one category replaces the same method nothing is
590 guaranteed about what method will be used. Assumes that
591 __objc_runtime_mutex is locked down. */
593 __objc_install_methods_in_dtable (struct sarray *dtable, struct objc_method_list * method_list)
600 if (method_list->method_next)
601 __objc_install_methods_in_dtable (dtable, method_list->method_next);
603 for (i = 0; i < method_list->method_count; i++)
605 struct objc_method * method = &(method_list->method_list[i]);
606 sarray_at_put_safe (dtable,
607 (sidx) method->method_name->sel_id,
613 __objc_update_dispatch_table_for_class (Class class)
618 DEBUG_PRINTF (" _objc_update_dtable_for_class (%s)\n", class->name);
620 objc_mutex_lock (__objc_runtime_mutex);
622 /* not yet installed -- skip it unless in +initialize */
623 if (class->dtable == __objc_uninstalled_dtable)
625 if (__objc_prepared_dtable_for_class (class))
627 /* There is a prepared table so we must be initialising this
628 class ... we must re-do the table preparation. */
629 __objc_prepare_dtable_for_class (class);
631 objc_mutex_unlock (__objc_runtime_mutex);
636 __objc_install_premature_dtable (class); /* someone might require it... */
637 sarray_free (arr); /* release memory */
639 /* Could have been lazy... */
640 __objc_install_dtable_for_class (class);
642 if (class->subclass_list) /* Traverse subclasses. */
643 for (next = class->subclass_list; next; next = next->sibling_class)
644 __objc_update_dispatch_table_for_class (next);
646 objc_mutex_unlock (__objc_runtime_mutex);
649 /* This function adds a method list to a class. This function is
650 typically called by another function specific to the run-time. As
651 such this function does not worry about thread safe issues.
653 This one is only called for categories. Class objects have their
654 methods installed right away, and their selectors are made into
655 SEL's by the function __objc_register_selectors_from_class. */
657 class_add_method_list (Class class, struct objc_method_list * list)
659 /* Passing of a linked list is not allowed. Do multiple calls. */
660 assert (! list->method_next);
662 __objc_register_selectors_from_list(list);
664 /* Add the methods to the class's method list. */
665 list->method_next = class->methods;
666 class->methods = list;
668 /* Update the dispatch table of class. */
669 __objc_update_dispatch_table_for_class (class);
673 class_get_instance_method (Class class, SEL op)
675 return search_for_method_in_hierarchy (class, op);
679 class_get_class_method (MetaClass class, SEL op)
681 return search_for_method_in_hierarchy (class, op);
685 class_getInstanceMethod (Class class_, SEL selector)
687 struct objc_method *m;
689 if (class_ == Nil || selector == NULL)
692 m = search_for_method_in_hierarchy (class_, selector);
696 /* Try going through +resolveInstanceMethod:, and do the search
697 again if successful. */
698 if (__objc_resolve_instance_method (class_, selector))
699 return search_for_method_in_hierarchy (class_, selector);
705 class_getClassMethod (Class class_, SEL selector)
707 struct objc_method *m;
709 if (class_ == Nil || selector == NULL)
712 m = search_for_method_in_hierarchy (class_->class_pointer,
717 /* Try going through +resolveClassMethod:, and do the search again
719 if (__objc_resolve_class_method (class_, selector))
720 return search_for_method_in_hierarchy (class_->class_pointer,
727 class_addMethod (Class class_, SEL selector, IMP implementation,
728 const char *method_types)
730 struct objc_method_list *method_list;
731 struct objc_method *method;
732 const char *method_name;
734 if (class_ == Nil || selector == NULL || implementation == NULL
735 || method_types == NULL || (strcmp (method_types, "") == 0))
738 method_name = sel_getName (selector);
739 if (method_name == NULL)
742 /* If the method already exists in the class, return NO. It is fine
743 if the method already exists in the superclass; in that case, we
744 are overriding it. */
745 if (CLS_IS_IN_CONSTRUCTION (class_))
747 /* The class only contains a list of methods; they have not been
748 registered yet, ie, the method_name of each of them is still
749 a string, not a selector. Iterate manually over them to
750 check if we have already added the method. */
751 struct objc_method_list * method_list = class_->methods;
756 /* Search the method list. */
757 for (i = 0; i < method_list->method_count; ++i)
759 struct objc_method * method = &method_list->method_list[i];
761 if (method->method_name
762 && strcmp ((char *)method->method_name, method_name) == 0)
766 /* The method wasn't found. Follow the link to the next list of
768 method_list = method_list->method_next;
770 /* The method wasn't found. It's a new one. Go ahead and add
775 /* Do the standard lookup. This assumes the selectors are
777 if (search_for_method_in_list (class_->methods, selector))
781 method_list = (struct objc_method_list *)objc_calloc (1, sizeof (struct objc_method_list));
782 method_list->method_count = 1;
784 method = &(method_list->method_list[0]);
785 method->method_name = objc_malloc (strlen (method_name) + 1);
786 strcpy ((char *)method->method_name, method_name);
788 method->method_types = objc_malloc (strlen (method_types) + 1);
789 strcpy ((char *)method->method_types, method_types);
791 method->method_imp = implementation;
793 if (CLS_IS_IN_CONSTRUCTION (class_))
795 /* We only need to add the method to the list. It will be
796 registered with the runtime when the class pair is registered
798 method_list->method_next = class_->methods;
799 class_->methods = method_list;
803 /* Add the method to a live class. */
804 objc_mutex_lock (__objc_runtime_mutex);
805 class_add_method_list (class_, method_list);
806 objc_mutex_unlock (__objc_runtime_mutex);
813 class_replaceMethod (Class class_, SEL selector, IMP implementation,
814 const char *method_types)
816 struct objc_method * method;
818 if (class_ == Nil || selector == NULL || implementation == NULL
819 || method_types == NULL)
822 method = search_for_method_in_hierarchy (class_, selector);
826 return method_setImplementation (method, implementation);
830 class_addMethod (class_, selector, implementation, method_types);
835 /* Search for a method starting from the current class up its
836 hierarchy. Return a pointer to the method's method structure if
837 found. NULL otherwise. */
838 static struct objc_method *
839 search_for_method_in_hierarchy (Class cls, SEL sel)
841 struct objc_method * method = NULL;
844 if (! sel_is_mapped (sel))
847 /* Scan the method list of the class. If the method isn't found in
848 the list then step to its super class. */
849 for (class = cls; ((! method) && class); class = class->super_class)
850 method = search_for_method_in_list (class->methods, sel);
857 /* Given a linked list of method and a method's name. Search for the
858 named method's method structure. Return a pointer to the method's
859 method structure if found. NULL otherwise. */
861 search_for_method_in_list (struct objc_method_list * list, SEL op)
863 struct objc_method_list * method_list = list;
865 if (! sel_is_mapped (op))
868 /* If not found then we'll search the list. */
873 /* Search the method list. */
874 for (i = 0; i < method_list->method_count; ++i)
876 struct objc_method * method = &method_list->method_list[i];
878 if (method->method_name)
879 if (method->method_name->sel_id == op->sel_id)
883 /* The method wasn't found. Follow the link to the next list of
885 method_list = method_list->method_next;
891 static retval_t __objc_forward (id object, SEL sel, arglist_t args);
893 /* Forwarding pointers/integers through the normal registers. */
895 __objc_word_forward (id rcv, SEL op, ...)
899 args = __builtin_apply_args ();
900 res = __objc_forward (rcv, op, args);
902 __builtin_return (res);
907 /* Specific routine for forwarding floats/double because of
908 architectural differences on some processors. i386s for example
909 which uses a floating point stack versus general registers for
910 floating point numbers. This forward routine makes sure that GCC
911 restores the proper return values. */
913 __objc_double_forward (id rcv, SEL op, ...)
917 args = __builtin_apply_args ();
918 res = __objc_forward (rcv, op, args);
919 __builtin_return (res);
922 #if INVISIBLE_STRUCT_RETURN
927 __objc_block_forward (id rcv, SEL op, ...)
931 args = __builtin_apply_args ();
932 res = __objc_forward (rcv, op, args);
934 __builtin_return (res);
936 #if INVISIBLE_STRUCT_RETURN
937 return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}};
944 /* This function is installed in the dispatch table for all methods
945 which are not implemented. Thus, it is called when a selector is
948 __objc_forward (id object, SEL sel, arglist_t args)
951 static SEL frwd_sel = 0; /* !T:SAFE2 */
954 /* First try if the object understands forward::. */
956 frwd_sel = sel_get_any_uid ("forward::");
958 if (__objc_responds_to (object, frwd_sel))
960 imp = get_implementation (object, object->class_pointer, frwd_sel);
961 return (*imp) (object, frwd_sel, sel, args);
964 /* If the object recognizes the doesNotRecognize: method then we're
966 err_sel = sel_get_any_uid ("doesNotRecognize:");
967 if (__objc_responds_to (object, err_sel))
969 imp = get_implementation (object, object->class_pointer, err_sel);
970 return (*imp) (object, err_sel, sel);
973 /* The object doesn't recognize the method. Check for responding to
974 error:. If it does then sent it. */
976 char msg[256 + strlen ((const char *) sel_getName (sel))
977 + strlen ((const char *) object->class_pointer->name)];
979 sprintf (msg, "(%s) %s does not recognize %s",
980 (CLS_ISMETA (object->class_pointer)
983 object->class_pointer->name, sel_getName (sel));
985 /* TODO: support for error: is surely deprecated ? */
986 err_sel = sel_get_any_uid ("error:");
987 if (__objc_responds_to (object, err_sel))
989 imp = get_implementation (object, object->class_pointer, err_sel);
990 return (*imp) (object, sel_get_any_uid ("error:"), msg);
993 /* The object doesn't respond to doesNotRecognize: or error:;
994 Therefore, a default action is taken. */
995 _objc_abort ("%s\n", msg);
1002 __objc_print_dtable_stats (void)
1006 objc_mutex_lock (__objc_runtime_mutex);
1009 printf ("memory usage: (%s)\n", "2-level sparse arrays");
1011 printf ("memory usage: (%s)\n", "3-level sparse arrays");
1014 printf ("arrays: %d = %ld bytes\n", narrays,
1015 (long) ((size_t) narrays * sizeof (struct sarray)));
1016 total += narrays * sizeof (struct sarray);
1017 printf ("buckets: %d = %ld bytes\n", nbuckets,
1018 (long) ((size_t) nbuckets * sizeof (struct sbucket)));
1019 total += nbuckets * sizeof (struct sbucket);
1021 printf ("idxtables: %d = %ld bytes\n",
1022 idxsize, (long) ((size_t) idxsize * sizeof (void *)));
1023 total += idxsize * sizeof (void *);
1024 printf ("-----------------------------------\n");
1025 printf ("total: %d bytes\n", total);
1026 printf ("===================================\n");
1028 objc_mutex_unlock (__objc_runtime_mutex);
1031 /* Returns the uninstalled dispatch table indicator. If a class'
1032 dispatch table points to __objc_uninstalled_dtable then that means
1033 it needs its dispatch table to be installed. */
1035 objc_get_uninstalled_dtable (void)
1037 return __objc_uninstalled_dtable;
1040 static cache_ptr prepared_dtable_table = 0;
1042 /* This function is called by:
1043 objc_msg_lookup, get_imp and __objc_responds_to
1044 (and the dispatch table installation functions themselves)
1045 to install a dispatch table for a class.
1047 If CLS is a class, it installs instance methods.
1048 If CLS is a meta class, it installs class methods.
1050 In either case +initialize is invoked for the corresponding class.
1052 The implementation must insure that the dispatch table is not
1053 installed until +initialize completes. Otherwise it opens a
1054 potential race since the installation of the dispatch table is
1055 used as gate in regular method dispatch and we need to guarantee
1056 that +initialize is the first method invoked an that no other
1057 thread my dispatch messages to the class before +initialize
1061 __objc_install_dtable_for_class (Class cls)
1063 /* If the class has not yet had its class links resolved, we must
1064 re-compute all class links */
1065 if (! CLS_ISRESOLV (cls))
1066 __objc_resolve_class_links ();
1068 /* Make sure the super class has its dispatch table installed
1069 or is at least preparing.
1070 We do not need to send initialize for the super class since
1071 __objc_send_initialize will insure that.
1073 if (cls->super_class
1074 && cls->super_class->dtable == __objc_uninstalled_dtable
1075 && !__objc_prepared_dtable_for_class (cls->super_class))
1077 __objc_install_dtable_for_class (cls->super_class);
1078 /* The superclass initialisation may have also initialised the
1079 current class, in which case there is no more to do. */
1080 if (cls->dtable != __objc_uninstalled_dtable)
1086 /* We have already been prepared but +initialize hasn't completed.
1087 The +initialize implementation is probably sending 'self' messages.
1088 We rely on _objc_get_prepared_imp to retrieve the implementation
1090 if (__objc_prepared_dtable_for_class (cls))
1095 /* We have this function cache the implementation pointers
1096 for _objc_get_prepared_imp but the dispatch table won't
1097 be initilized until __objc_send_initialize completes. */
1098 __objc_prepare_dtable_for_class (cls);
1100 /* We may have already invoked +initialize but
1101 __objc_update_dispatch_table_for_class invoked by
1102 class_add_method_list may have reset dispatch table. */
1104 /* Call +initialize.
1105 If we are a real class, we are installing instance methods.
1106 If we are a meta class, we are installing class methods.
1107 The __objc_send_initialize itself will insure that the message
1108 is called only once per class. */
1109 if (CLS_ISCLASS (cls))
1110 __objc_send_initialize (cls);
1113 /* Retreive the class from the meta class. */
1114 Class c = objc_getClass (cls->name);
1115 assert (CLS_ISMETA (cls));
1117 __objc_send_initialize (c);
1120 /* We install the dispatch table correctly when +initialize completed. */
1121 __objc_install_prepared_dtable_for_class (cls);
1124 /* Builds the dispatch table for the class CLS and stores
1125 it in a place where it can be retrieved by
1126 __objc_get_prepared_imp until __objc_install_prepared_dtable_for_class
1127 installs it into the class.
1128 The dispatch table should not be installed into the class until
1129 +initialize has completed. */
1131 __objc_prepare_dtable_for_class (Class cls)
1133 struct sarray *dtable;
1134 struct sarray *super_dtable;
1136 /* This table could be initialized in init.c.
1137 We can not use the class name since
1138 the class maintains the instance methods and
1139 the meta class maintains the the class methods yet
1140 both share the same name.
1141 Classes should be unique in any program. */
1142 if (! prepared_dtable_table)
1143 prepared_dtable_table
1145 (hash_func_type) objc_hash_ptr,
1146 (compare_func_type) objc_compare_ptrs);
1148 /* If the class has not yet had its class links resolved, we must
1149 re-compute all class links */
1150 if (! CLS_ISRESOLV (cls))
1151 __objc_resolve_class_links ();
1154 assert (cls->dtable == __objc_uninstalled_dtable);
1156 /* If there is already a prepared dtable for this class, we must replace
1157 it with a new version (since there must have been methods added to or
1158 otherwise modified in the class while executing +initialize, and the
1159 table needs to be recomputed. */
1160 dtable = __objc_prepared_dtable_for_class (cls);
1163 objc_hash_remove (prepared_dtable_table, cls);
1164 sarray_free (dtable);
1167 /* Now prepare the dtable for population. */
1168 assert (cls != cls->super_class);
1169 if (cls->super_class)
1171 /* Inherit the method list from the super class.
1172 Yet the super class may still be initializing
1173 in the case when a class cluster sub class initializes
1174 its super classes. */
1175 if (cls->super_class->dtable == __objc_uninstalled_dtable)
1176 __objc_install_dtable_for_class (cls->super_class);
1178 super_dtable = cls->super_class->dtable;
1179 /* If the dispatch table is not yet installed,
1180 we are still in the process of executing +initialize.
1181 Yet the dispatch table should be available. */
1182 if (super_dtable == __objc_uninstalled_dtable)
1183 super_dtable = __objc_prepared_dtable_for_class (cls->super_class);
1185 assert (super_dtable);
1186 dtable = sarray_lazy_copy (super_dtable);
1189 dtable = sarray_new (__objc_selector_max_index, 0);
1191 __objc_install_methods_in_dtable (dtable, cls->methods);
1193 objc_hash_add (&prepared_dtable_table,
1198 /* This wrapper only exists to allow an easy replacement of
1199 the lookup implementation and it is expected that the compiler
1200 will optimize it away. */
1201 static struct sarray *
1202 __objc_prepared_dtable_for_class (Class cls)
1204 struct sarray *dtable = 0;
1206 if (prepared_dtable_table)
1207 dtable = objc_hash_value_for_key (prepared_dtable_table, cls);
1208 /* dtable my be nil,
1209 since we call this to check whether we are currently preparing
1210 before we start preparing. */
1214 /* Helper function for messages sent to CLS or implementation pointers
1215 retrieved from CLS during +initialize before the dtable is installed.
1216 When a class implicitly initializes another class which in turn
1217 implicitly invokes methods in this class, before the implementation of
1218 +initialize of CLS completes, this returns the expected implementation.
1219 Forwarding remains the responsibility of objc_msg_lookup.
1220 This function should only be called under the global lock.
1223 __objc_get_prepared_imp (Class cls,SEL sel)
1225 struct sarray *dtable;
1230 assert (cls->dtable == __objc_uninstalled_dtable);
1231 dtable = __objc_prepared_dtable_for_class (cls);
1234 assert (dtable != __objc_uninstalled_dtable);
1235 imp = sarray_get_safe (dtable, (size_t) sel->sel_id);
1237 /* imp may be Nil if the method does not exist and we
1238 may fallback to the forwarding implementation later. */
1242 /* When this function is called +initialize should be completed.
1243 So now we are safe to install the dispatch table for the
1244 class so that they become available for other threads
1245 that may be waiting in the lock.
1248 __objc_install_prepared_dtable_for_class (Class cls)
1251 assert (cls->dtable == __objc_uninstalled_dtable);
1252 cls->dtable = __objc_prepared_dtable_for_class (cls);
1254 assert (cls->dtable);
1255 assert (cls->dtable != __objc_uninstalled_dtable);
1256 objc_hash_remove (prepared_dtable_table, cls);