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 to be
268 if (class->dtable == __objc_uninstalled_dtable)
269 __objc_install_dtable_for_class (class);
271 /* If the dispatch table is not yet installed, we are still in
272 the process of executing +initialize. But the implementation
273 pointer should be available in the prepared ispatch table if
275 if (class->dtable == __objc_uninstalled_dtable)
277 assert (__objc_prepared_dtable_for_class (class) != 0);
278 res = __objc_get_prepared_imp (class, sel);
283 objc_mutex_unlock (__objc_runtime_mutex);
284 /* Call ourselves with the installed dispatch table and get the
287 res = get_implementation (receiver, class, sel);
291 /* The dispatch table has been installed. */
292 res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
295 /* The dispatch table has been installed, and the method is
296 not in the dispatch table. So the method just doesn't
297 exist for the class. */
299 /* Try going through the +resolveClassMethod: or
300 +resolveInstanceMethod: process. */
301 if (CLS_ISMETA (class))
303 /* We have the meta class, but we need to invoke the
304 +resolveClassMethod: method on the class. So, we
305 need to obtain the class from the meta class, which
306 we do using the fact that both the class and the
307 meta-class have the same name. */
308 Class realClass = objc_lookUpClass (class->name);
310 res = __objc_resolve_class_method (realClass, sel);
313 res = __objc_resolve_instance_method (class, sel);
316 res = __objc_get_forward_imp (receiver, sel);
324 get_imp (Class class, SEL sel)
326 /* In a vanilla implementation we would first check if the dispatch
327 table is installed. Here instead, to get more speed in the
328 standard case (that the dispatch table is installed) we first try
329 to get the imp using brute force. Only if that fails, we do what
330 we should have been doing from the very beginning, that is, check
331 if the dispatch table needs to be installed, install it if it's
332 not installed, and retrieve the imp from the table if it's
334 void *res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
337 res = get_implementation(nil, class, sel);
342 /* The new name of get_imp(). */
344 class_getMethodImplementation (Class class_, SEL selector)
346 if (class_ == Nil || selector == NULL)
349 /* get_imp is inlined, so we're good. */
350 return get_imp (class_, selector);
353 /* Given a method, return its implementation. This has been replaced
354 by method_getImplementation() in the modern API. */
356 method_get_imp (struct objc_method * method)
358 return (method != (struct objc_method *)0) ? method->method_imp : (IMP)0;
361 /* Query if an object can respond to a selector, returns YES if the
362 object implements the selector otherwise NO. Does not check if the
363 method can be forwarded. Since this requires the dispatch table to
364 installed, this function will implicitly invoke +initialize for the
365 class of OBJECT if it hasn't been invoked yet. */
368 __objc_responds_to (id object, SEL sel)
371 struct sarray *dtable;
373 /* Install dispatch table if need be */
374 dtable = object->class_pointer->dtable;
375 if (dtable == __objc_uninstalled_dtable)
377 objc_mutex_lock (__objc_runtime_mutex);
378 if (object->class_pointer->dtable == __objc_uninstalled_dtable)
379 __objc_install_dtable_for_class (object->class_pointer);
381 /* If the dispatch table is not yet installed, we are still in
382 the process of executing +initialize. Yet the dispatch table
383 should be available. */
384 if (object->class_pointer->dtable == __objc_uninstalled_dtable)
386 dtable = __objc_prepared_dtable_for_class (object->class_pointer);
390 dtable = object->class_pointer->dtable;
392 objc_mutex_unlock (__objc_runtime_mutex);
395 /* Get the method from the dispatch table. */
396 res = sarray_get_safe (dtable, (size_t) sel->sel_id);
397 return (res != 0) ? YES : NO;
401 class_respondsToSelector (Class class_, SEL selector)
403 struct sarray *dtable;
406 if (class_ == Nil || selector == NULL)
409 /* Install dispatch table if need be. */
410 dtable = class_->dtable;
411 if (dtable == __objc_uninstalled_dtable)
413 objc_mutex_lock (__objc_runtime_mutex);
414 if (class_->dtable == __objc_uninstalled_dtable)
415 __objc_install_dtable_for_class (class_);
417 /* If the dispatch table is not yet installed,
418 we are still in the process of executing +initialize.
419 Yet the dispatch table should be available. */
420 if (class_->dtable == __objc_uninstalled_dtable)
422 dtable = __objc_prepared_dtable_for_class (class_);
426 dtable = class_->dtable;
428 objc_mutex_unlock (__objc_runtime_mutex);
431 /* Get the method from the dispatch table. */
432 res = sarray_get_safe (dtable, (size_t) selector->sel_id);
433 return (res != 0) ? YES : NO;
436 /* This is the lookup function. All entries in the table are either a
437 valid method *or* zero. If zero then either the dispatch table
438 needs to be installed or it doesn't exist and forwarding is
441 objc_msg_lookup (id receiver, SEL op)
446 /* First try a quick lookup assuming the dispatch table exists. */
447 result = sarray_get_safe (receiver->class_pointer->dtable,
451 /* Not found ... call get_implementation () to install the
452 dispatch table and call +initialize as required,
453 providing the method implementation or a forwarding
455 result = get_implementation (receiver, receiver->class_pointer, op);
460 return (IMP)nil_method;
464 objc_msg_lookup_super (struct objc_super *super, SEL sel)
467 return get_imp (super->super_class, sel);
469 return (IMP)nil_method;
473 class_get_instance_method (Class class, SEL op);
476 __objc_init_dispatch_tables ()
478 __objc_uninstalled_dtable = sarray_new (200, 0);
480 /* TODO: It would be cool to register typed selectors here. */
481 selector_resolveClassMethod = sel_registerName ("resolveClassMethod:");
482 selector_resolveInstanceMethod = sel_registerName ("resolveInstanceMethod:");
486 /* Install dummy table for class which causes the first message to
487 that class (or instances hereof) to be initialized properly. */
489 __objc_install_premature_dtable (Class class)
491 assert (__objc_uninstalled_dtable);
492 class->dtable = __objc_uninstalled_dtable;
495 /* Send +initialize to class if not already done. */
497 __objc_send_initialize (Class class)
499 /* This *must* be a class object. */
500 assert (CLS_ISCLASS (class));
501 assert (! CLS_ISMETA (class));
503 /* class_add_method_list/__objc_update_dispatch_table_for_class may
504 have reset the dispatch table. The canonical way to insure that
505 we send +initialize just once, is this flag. */
506 if (! CLS_ISINITIALIZED (class))
508 DEBUG_PRINTF ("+initialize: need to initialize class '%s'\n", class->name);
509 CLS_SETINITIALIZED (class);
510 CLS_SETINITIALIZED (class->class_pointer);
512 /* Create the garbage collector type memory description. */
513 __objc_generate_gc_type_description (class);
515 if (class->super_class)
516 __objc_send_initialize (class->super_class);
519 SEL op = sel_registerName ("initialize");
521 struct objc_method_list * method_list = class->class_pointer->methods;
526 struct objc_method * method;
528 for (i = 0; i < method_list->method_count; i++)
530 method = &(method_list->method_list[i]);
531 if (method->method_name
532 && method->method_name->sel_id == op->sel_id)
534 imp = method->method_imp;
542 method_list = method_list->method_next;
546 DEBUG_PRINTF (" begin of [%s +initialize]\n", class->name);
547 (*imp) ((id) class, op);
548 DEBUG_PRINTF (" end of [%s +initialize]\n", class->name);
553 DEBUG_PRINTF (" class '%s' has no +initialize method\n", class->name);
560 /* Walk on the methods list of class and install the methods in the
561 reverse order of the lists. Since methods added by categories are
562 before the methods of class in the methods list, this allows
563 categories to substitute methods declared in class. However if
564 more than one category replaces the same method nothing is
565 guaranteed about what method will be used. Assumes that
566 __objc_runtime_mutex is locked down. */
568 __objc_install_methods_in_dtable (struct sarray *dtable, struct objc_method_list * method_list)
575 if (method_list->method_next)
576 __objc_install_methods_in_dtable (dtable, method_list->method_next);
578 for (i = 0; i < method_list->method_count; i++)
580 struct objc_method * method = &(method_list->method_list[i]);
581 sarray_at_put_safe (dtable,
582 (sidx) method->method_name->sel_id,
588 __objc_update_dispatch_table_for_class (Class class)
593 DEBUG_PRINTF (" _objc_update_dtable_for_class (%s)\n", class->name);
595 objc_mutex_lock (__objc_runtime_mutex);
597 /* Not yet installed -- skip it unless in +initialize. */
598 if (class->dtable == __objc_uninstalled_dtable)
600 if (__objc_prepared_dtable_for_class (class))
602 /* There is a prepared table so we must be initialising this
603 class ... we must re-do the table preparation. */
604 __objc_prepare_dtable_for_class (class);
606 objc_mutex_unlock (__objc_runtime_mutex);
611 __objc_install_premature_dtable (class); /* someone might require it... */
612 sarray_free (arr); /* release memory */
614 /* Could have been lazy... */
615 __objc_install_dtable_for_class (class);
617 if (class->subclass_list) /* Traverse subclasses. */
618 for (next = class->subclass_list; next; next = next->sibling_class)
619 __objc_update_dispatch_table_for_class (next);
621 objc_mutex_unlock (__objc_runtime_mutex);
624 /* This function adds a method list to a class. This function is
625 typically called by another function specific to the run-time. As
626 such this function does not worry about thread safe issues.
628 This one is only called for categories. Class objects have their
629 methods installed right away, and their selectors are made into
630 SEL's by the function __objc_register_selectors_from_class. */
632 class_add_method_list (Class class, struct objc_method_list * list)
634 /* Passing of a linked list is not allowed. Do multiple calls. */
635 assert (! list->method_next);
637 __objc_register_selectors_from_list(list);
639 /* Add the methods to the class's method list. */
640 list->method_next = class->methods;
641 class->methods = list;
643 /* Update the dispatch table of class. */
644 __objc_update_dispatch_table_for_class (class);
648 class_get_instance_method (Class class, SEL op)
650 return search_for_method_in_hierarchy (class, op);
654 class_get_class_method (Class class, SEL op)
656 return search_for_method_in_hierarchy (class, op);
660 class_getInstanceMethod (Class class_, SEL selector)
662 struct objc_method *m;
664 if (class_ == Nil || selector == NULL)
667 m = search_for_method_in_hierarchy (class_, selector);
671 /* Try going through +resolveInstanceMethod:, and do the search
672 again if successful. */
673 if (__objc_resolve_instance_method (class_, selector))
674 return search_for_method_in_hierarchy (class_, selector);
680 class_getClassMethod (Class class_, SEL selector)
682 struct objc_method *m;
684 if (class_ == Nil || selector == NULL)
687 m = search_for_method_in_hierarchy (class_->class_pointer,
692 /* Try going through +resolveClassMethod:, and do the search again
694 if (__objc_resolve_class_method (class_, selector))
695 return search_for_method_in_hierarchy (class_->class_pointer,
702 class_addMethod (Class class_, SEL selector, IMP implementation,
703 const char *method_types)
705 struct objc_method_list *method_list;
706 struct objc_method *method;
707 const char *method_name;
709 if (class_ == Nil || selector == NULL || implementation == NULL
710 || method_types == NULL || (strcmp (method_types, "") == 0))
713 method_name = sel_getName (selector);
714 if (method_name == NULL)
717 /* If the method already exists in the class, return NO. It is fine
718 if the method already exists in the superclass; in that case, we
719 are overriding it. */
720 if (CLS_IS_IN_CONSTRUCTION (class_))
722 /* The class only contains a list of methods; they have not been
723 registered yet, ie, the method_name of each of them is still
724 a string, not a selector. Iterate manually over them to
725 check if we have already added the method. */
726 struct objc_method_list * method_list = class_->methods;
731 /* Search the method list. */
732 for (i = 0; i < method_list->method_count; ++i)
734 struct objc_method * method = &method_list->method_list[i];
736 if (method->method_name
737 && strcmp ((char *)method->method_name, method_name) == 0)
741 /* The method wasn't found. Follow the link to the next list of
743 method_list = method_list->method_next;
745 /* The method wasn't found. It's a new one. Go ahead and add
750 /* Do the standard lookup. This assumes the selectors are
752 if (search_for_method_in_list (class_->methods, selector))
756 method_list = (struct objc_method_list *)objc_calloc (1, sizeof (struct objc_method_list));
757 method_list->method_count = 1;
759 method = &(method_list->method_list[0]);
760 method->method_name = objc_malloc (strlen (method_name) + 1);
761 strcpy ((char *)method->method_name, method_name);
763 method->method_types = objc_malloc (strlen (method_types) + 1);
764 strcpy ((char *)method->method_types, method_types);
766 method->method_imp = implementation;
768 if (CLS_IS_IN_CONSTRUCTION (class_))
770 /* We only need to add the method to the list. It will be
771 registered with the runtime when the class pair is registered
773 method_list->method_next = class_->methods;
774 class_->methods = method_list;
778 /* Add the method to a live class. */
779 objc_mutex_lock (__objc_runtime_mutex);
780 class_add_method_list (class_, method_list);
781 objc_mutex_unlock (__objc_runtime_mutex);
788 class_replaceMethod (Class class_, SEL selector, IMP implementation,
789 const char *method_types)
791 struct objc_method * method;
793 if (class_ == Nil || selector == NULL || implementation == NULL
794 || method_types == NULL)
797 method = search_for_method_in_hierarchy (class_, selector);
801 return method_setImplementation (method, implementation);
805 class_addMethod (class_, selector, implementation, method_types);
810 /* Search for a method starting from the current class up its
811 hierarchy. Return a pointer to the method's method structure if
812 found. NULL otherwise. */
813 static struct objc_method *
814 search_for_method_in_hierarchy (Class cls, SEL sel)
816 struct objc_method * method = NULL;
819 if (! sel_is_mapped (sel))
822 /* Scan the method list of the class. If the method isn't found in
823 the list then step to its super class. */
824 for (class = cls; ((! method) && class); class = class->super_class)
825 method = search_for_method_in_list (class->methods, sel);
832 /* Given a linked list of method and a method's name. Search for the
833 named method's method structure. Return a pointer to the method's
834 method structure if found. NULL otherwise. */
836 search_for_method_in_list (struct objc_method_list * list, SEL op)
838 struct objc_method_list * method_list = list;
840 if (! sel_is_mapped (op))
843 /* If not found then we'll search the list. */
848 /* Search the method list. */
849 for (i = 0; i < method_list->method_count; ++i)
851 struct objc_method * method = &method_list->method_list[i];
853 if (method->method_name)
854 if (method->method_name->sel_id == op->sel_id)
858 /* The method wasn't found. Follow the link to the next list of
860 method_list = method_list->method_next;
866 typedef void * retval_t;
867 typedef void * arglist_t;
869 static retval_t __objc_forward (id object, SEL sel, arglist_t args);
871 /* Forwarding pointers/integers through the normal registers. */
873 __objc_word_forward (id rcv, SEL op, ...)
877 args = __builtin_apply_args ();
878 res = __objc_forward (rcv, op, args);
880 __builtin_return (res);
885 /* Specific routine for forwarding floats/double because of
886 architectural differences on some processors. i386s for example
887 which uses a floating point stack versus general registers for
888 floating point numbers. This forward routine makes sure that GCC
889 restores the proper return values. */
891 __objc_double_forward (id rcv, SEL op, ...)
895 args = __builtin_apply_args ();
896 res = __objc_forward (rcv, op, args);
897 __builtin_return (res);
900 #if INVISIBLE_STRUCT_RETURN
905 __objc_block_forward (id rcv, SEL op, ...)
909 args = __builtin_apply_args ();
910 res = __objc_forward (rcv, op, args);
912 __builtin_return (res);
914 #if INVISIBLE_STRUCT_RETURN
915 return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}};
922 /* This function is called for methods which are not implemented,
923 unless a custom forwarding routine has been installed. Please note
924 that most serious users of libobjc (eg, GNUstep base) do install
925 their own forwarding routines, and hence this is never actually
926 used. But, if no custom forwarding routine is installed, this is
927 called when a selector is not recognized. */
929 __objc_forward (id object, SEL sel, arglist_t args)
932 static SEL frwd_sel = 0; /* !T:SAFE2 */
935 /* First try if the object understands forward::. */
937 frwd_sel = sel_get_any_uid ("forward::");
939 if (__objc_responds_to (object, frwd_sel))
941 imp = get_implementation (object, object->class_pointer, frwd_sel);
942 return (*imp) (object, frwd_sel, sel, args);
945 /* If the object recognizes the doesNotRecognize: method then we're
947 err_sel = sel_get_any_uid ("doesNotRecognize:");
948 if (__objc_responds_to (object, err_sel))
950 imp = get_implementation (object, object->class_pointer, err_sel);
951 return (*imp) (object, err_sel, sel);
954 /* The object doesn't recognize the method. Check for responding to
955 error:. If it does then sent it. */
957 char msg[256 + strlen ((const char *) sel_getName (sel))
958 + strlen ((const char *) object->class_pointer->name)];
960 sprintf (msg, "(%s) %s does not recognize %s",
961 (CLS_ISMETA (object->class_pointer)
964 object->class_pointer->name, sel_getName (sel));
966 /* The object doesn't respond to doesNotRecognize:. Therefore, a
967 default action is taken. */
968 _objc_abort ("%s\n", msg);
975 __objc_print_dtable_stats (void)
979 objc_mutex_lock (__objc_runtime_mutex);
982 printf ("memory usage: (%s)\n", "2-level sparse arrays");
984 printf ("memory usage: (%s)\n", "3-level sparse arrays");
987 printf ("arrays: %d = %ld bytes\n", narrays,
988 (long) ((size_t) narrays * sizeof (struct sarray)));
989 total += narrays * sizeof (struct sarray);
990 printf ("buckets: %d = %ld bytes\n", nbuckets,
991 (long) ((size_t) nbuckets * sizeof (struct sbucket)));
992 total += nbuckets * sizeof (struct sbucket);
994 printf ("idxtables: %d = %ld bytes\n",
995 idxsize, (long) ((size_t) idxsize * sizeof (void *)));
996 total += idxsize * sizeof (void *);
997 printf ("-----------------------------------\n");
998 printf ("total: %d bytes\n", total);
999 printf ("===================================\n");
1001 objc_mutex_unlock (__objc_runtime_mutex);
1004 /* Returns the uninstalled dispatch table indicator. If a class'
1005 dispatch table points to __objc_uninstalled_dtable then that means
1006 it needs its dispatch table to be installed. */
1008 objc_get_uninstalled_dtable (void)
1010 return __objc_uninstalled_dtable;
1013 static cache_ptr prepared_dtable_table = 0;
1015 /* This function is called by: objc_msg_lookup, get_imp and
1016 __objc_responds_to (and the dispatch table installation functions
1017 themselves) to install a dispatch table for a class.
1019 If CLS is a class, it installs instance methods.
1020 If CLS is a meta class, it installs class methods.
1022 In either case +initialize is invoked for the corresponding class.
1024 The implementation must insure that the dispatch table is not
1025 installed until +initialize completes. Otherwise it opens a
1026 potential race since the installation of the dispatch table is used
1027 as gate in regular method dispatch and we need to guarantee that
1028 +initialize is the first method invoked an that no other thread my
1029 dispatch messages to the class before +initialize completes. */
1031 __objc_install_dtable_for_class (Class cls)
1033 /* If the class has not yet had its class links resolved, we must
1034 re-compute all class links. */
1035 if (! CLS_ISRESOLV (cls))
1036 __objc_resolve_class_links ();
1038 /* Make sure the super class has its dispatch table installed or is
1039 at least preparing. We do not need to send initialize for the
1040 super class since __objc_send_initialize will insure that. */
1041 if (cls->super_class
1042 && cls->super_class->dtable == __objc_uninstalled_dtable
1043 && !__objc_prepared_dtable_for_class (cls->super_class))
1045 __objc_install_dtable_for_class (cls->super_class);
1046 /* The superclass initialisation may have also initialised the
1047 current class, in which case there is no more to do. */
1048 if (cls->dtable != __objc_uninstalled_dtable)
1052 /* We have already been prepared but +initialize hasn't completed.
1053 The +initialize implementation is probably sending 'self'
1054 messages. We rely on _objc_get_prepared_imp to retrieve the
1055 implementation pointers. */
1056 if (__objc_prepared_dtable_for_class (cls))
1059 /* We have this function cache the implementation pointers for
1060 _objc_get_prepared_imp but the dispatch table won't be initilized
1061 until __objc_send_initialize completes. */
1062 __objc_prepare_dtable_for_class (cls);
1064 /* We may have already invoked +initialize but
1065 __objc_update_dispatch_table_for_class invoked by
1066 class_add_method_list may have reset dispatch table. */
1068 /* Call +initialize. If we are a real class, we are installing
1069 instance methods. If we are a meta class, we are installing
1070 class methods. The __objc_send_initialize itself will insure
1071 that the message is called only once per class. */
1072 if (CLS_ISCLASS (cls))
1073 __objc_send_initialize (cls);
1076 /* Retrieve the class from the meta class. */
1077 Class c = objc_getClass (cls->name);
1078 assert (CLS_ISMETA (cls));
1080 __objc_send_initialize (c);
1083 /* We install the dispatch table correctly when +initialize completed. */
1084 __objc_install_prepared_dtable_for_class (cls);
1087 /* Builds the dispatch table for the class CLS and stores it in a
1088 place where it can be retrieved by __objc_get_prepared_imp until
1089 __objc_install_prepared_dtable_for_class installs it into the
1090 class. The dispatch table should not be installed into the class
1091 until +initialize has completed. */
1093 __objc_prepare_dtable_for_class (Class cls)
1095 struct sarray *dtable;
1096 struct sarray *super_dtable;
1098 /* This table could be initialized in init.c. We can not use the
1099 class name since the class maintains the instance methods and the
1100 meta class maintains the the class methods yet both share the
1101 same name. Classes should be unique in any program. */
1102 if (! prepared_dtable_table)
1103 prepared_dtable_table
1104 = objc_hash_new (32,
1105 (hash_func_type) objc_hash_ptr,
1106 (compare_func_type) objc_compare_ptrs);
1108 /* If the class has not yet had its class links resolved, we must
1109 re-compute all class links. */
1110 if (! CLS_ISRESOLV (cls))
1111 __objc_resolve_class_links ();
1114 assert (cls->dtable == __objc_uninstalled_dtable);
1116 /* If there is already a prepared dtable for this class, we must
1117 replace it with a new version (since there must have been methods
1118 added to or otherwise modified in the class while executing
1119 +initialize, and the table needs to be recomputed. */
1120 dtable = __objc_prepared_dtable_for_class (cls);
1123 objc_hash_remove (prepared_dtable_table, cls);
1124 sarray_free (dtable);
1127 /* Now prepare the dtable for population. */
1128 assert (cls != cls->super_class);
1129 if (cls->super_class)
1131 /* Inherit the method list from the super class. Yet the super
1132 class may still be initializing in the case when a class
1133 cluster sub class initializes its super classes. */
1134 if (cls->super_class->dtable == __objc_uninstalled_dtable)
1135 __objc_install_dtable_for_class (cls->super_class);
1137 super_dtable = cls->super_class->dtable;
1138 /* If the dispatch table is not yet installed, we are still in
1139 the process of executing +initialize. Yet the dispatch table
1140 should be available. */
1141 if (super_dtable == __objc_uninstalled_dtable)
1142 super_dtable = __objc_prepared_dtable_for_class (cls->super_class);
1144 assert (super_dtable);
1145 dtable = sarray_lazy_copy (super_dtable);
1148 dtable = sarray_new (__objc_selector_max_index, 0);
1150 __objc_install_methods_in_dtable (dtable, cls->methods);
1152 objc_hash_add (&prepared_dtable_table,
1157 /* This wrapper only exists to allow an easy replacement of the lookup
1158 implementation and it is expected that the compiler will optimize
1160 static struct sarray *
1161 __objc_prepared_dtable_for_class (Class cls)
1163 struct sarray *dtable = 0;
1165 if (prepared_dtable_table)
1166 dtable = objc_hash_value_for_key (prepared_dtable_table, cls);
1167 /* dtable my be nil, since we call this to check whether we are
1168 currently preparing before we start preparing. */
1172 /* Helper function for messages sent to CLS or implementation pointers
1173 retrieved from CLS during +initialize before the dtable is
1174 installed. When a class implicitly initializes another class which
1175 in turn implicitly invokes methods in this class, before the
1176 implementation of +initialize of CLS completes, this returns the
1177 expected implementation. Forwarding remains the responsibility of
1178 objc_msg_lookup. This function should only be called under the
1181 __objc_get_prepared_imp (Class cls,SEL sel)
1183 struct sarray *dtable;
1188 assert (cls->dtable == __objc_uninstalled_dtable);
1189 dtable = __objc_prepared_dtable_for_class (cls);
1192 assert (dtable != __objc_uninstalled_dtable);
1193 imp = sarray_get_safe (dtable, (size_t) sel->sel_id);
1195 /* imp may be Nil if the method does not exist and we may fallback
1196 to the forwarding implementation later. */
1200 /* When this function is called +initialize should be completed. So
1201 now we are safe to install the dispatch table for the class so that
1202 they become available for other threads that may be waiting in the
1205 __objc_install_prepared_dtable_for_class (Class cls)
1208 assert (cls->dtable == __objc_uninstalled_dtable);
1209 cls->dtable = __objc_prepared_dtable_for_class (cls);
1211 assert (cls->dtable);
1212 assert (cls->dtable != __objc_uninstalled_dtable);
1213 objc_hash_remove (prepared_dtable_table, cls);