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
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. */
29 /* FIXME: This file has no business including tm.h. */
30 /* FIXME: This should be using libffi instead of __builtin_apply
33 #include "objc-private/common.h"
34 #include "objc-private/error.h"
36 #include "coretypes.h"
38 #include "objc/runtime.h"
39 #include "objc/message.h" /* For objc_msg_lookup(), objc_msg_lookup_super(). */
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. */
58 #if ! defined (STRUCT_VALUE) || STRUCT_VALUE == 0
59 #define INVISIBLE_STRUCT_RETURN 1
61 #define INVISIBLE_STRUCT_RETURN 0
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
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. */
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
120 if (__objc_msg_forward2
)
123 if ((result
= __objc_msg_forward2 (rcv
, sel
)) != NULL
)
126 if (__objc_msg_forward
)
129 if ((result
= __objc_msg_forward (sel
)) != NULL
)
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
143 return (IMP
)__objc_block_forward
;
144 else if (t
&& (*t
== 'f' || *t
== 'd'))
145 return (IMP
)__objc_double_forward
;
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. */
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
);
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. */
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
);
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. */
260 get_implementation (id receiver
, Class
class, SEL sel
)
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
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
280 if (class->dtable
== __objc_uninstalled_dtable
)
282 assert (__objc_prepared_dtable_for_class (class) != 0);
283 res
= __objc_get_prepared_imp (class, sel
);
288 objc_mutex_unlock (__objc_runtime_mutex
);
289 /* Call ourselves with the installed dispatch table and get the
292 res
= get_implementation (receiver
, class, sel
);
296 /* The dispatch table has been installed. */
297 res
= sarray_get_safe (class->dtable
, (size_t) sel
->sel_id
);
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
);
315 res
= __objc_resolve_class_method (realClass
, sel
);
318 res
= __objc_resolve_instance_method (class, sel
);
321 res
= __objc_get_forward_imp (receiver
, sel
);
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
);
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
343 void *res
= sarray_get_safe (class->dtable
, (size_t) sel
->sel_id
);
346 res
= get_implementation(nil
, class, sel
);
351 /* The new name of get_imp(). */
353 class_getMethodImplementation (Class class_
, SEL selector
)
355 if (class_
== Nil
|| selector
== 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. */
377 __objc_responds_to (id object
, SEL sel
)
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
);
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
;
410 class_respondsToSelector (Class class_
, SEL selector
)
412 struct sarray
*dtable
;
415 if (class_
== Nil
|| selector
== NULL
)
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_
);
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
450 objc_msg_lookup (id receiver
, SEL op
)
455 /* First try a quick lookup assuming the dispatch table exists. */
456 result
= sarray_get_safe (receiver
->class_pointer
->dtable
,
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
464 result
= get_implementation (receiver
, receiver
->class_pointer
, op
);
469 return (IMP
)nil_method
;
473 objc_msg_lookup_super (struct objc_super
*super
, SEL sel
)
476 return get_imp (super
->super_class
, sel
);
478 return (IMP
)nil_method
;
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. */
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. */
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
,
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
);
538 DEBUG_PRINTF (" class '%s' has no +initialize method\n", class->name
);
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. */
553 __objc_install_methods_in_dtable (struct sarray
*dtable
, struct objc_method_list
* method_list
)
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
,
573 __objc_update_dispatch_table_for_class (Class
class)
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
);
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. */
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);
633 class_getInstanceMethod (Class class_
, SEL selector
)
635 struct objc_method
*m
;
637 if (class_
== Nil
|| selector
== NULL
)
640 m
= search_for_method_in_hierarchy (class_
, selector
);
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
);
653 class_getClassMethod (Class class_
, SEL selector
)
655 struct objc_method
*m
;
657 if (class_
== Nil
|| selector
== NULL
)
660 m
= search_for_method_in_hierarchy (class_
->class_pointer
,
665 /* Try going through +resolveClassMethod:, and do the search again
667 if (__objc_resolve_class_method (class_
, selector
))
668 return search_for_method_in_hierarchy (class_
->class_pointer
,
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))
686 method_name
= sel_getName (selector
);
687 if (method_name
== NULL
)
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
;
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)
714 /* The method wasn't found. Follow the link to the next list of
716 method_list
= method_list
->method_next
;
718 /* The method wasn't found. It's a new one. Go ahead and add
723 /* Do the standard lookup. This assumes the selectors are
725 if (search_for_method_in_list (class_
->methods
, selector
))
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
746 method_list
->method_next
= class_
->methods
;
747 class_
->methods
= method_list
;
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
);
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
)
770 method
= search_for_method_in_hierarchy (class_
, selector
);
774 return method_setImplementation (method
, implementation
);
778 class_addMethod (class_
, selector
, implementation
, method_types
);
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
;
792 if (! sel_is_mapped (sel
))
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
);
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. */
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
))
816 /* If not found then we'll search the list. */
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
)
831 /* The method wasn't found. Follow the link to the next list of
833 method_list
= method_list
->method_next
;
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. */
846 __objc_word_forward (id rcv
, SEL op
, ...)
850 args
= __builtin_apply_args ();
851 res
= __objc_forward (rcv
, op
, args
);
853 __builtin_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. */
864 __objc_double_forward (id rcv
, SEL op
, ...)
868 args
= __builtin_apply_args ();
869 res
= __objc_forward (rcv
, op
, args
);
870 __builtin_return (res
);
873 #if INVISIBLE_STRUCT_RETURN
878 __objc_block_forward (id rcv
, SEL op
, ...)
882 args
= __builtin_apply_args ();
883 res
= __objc_forward (rcv
, op
, args
);
885 __builtin_return (res
);
887 #if INVISIBLE_STRUCT_RETURN
888 return (__big
) {{0, 0, 0, 0, 0, 0, 0, 0}};
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. */
902 __objc_forward (id object
, SEL sel
, arglist_t args
)
905 static SEL frwd_sel
= 0; /* !T:SAFE2 */
908 /* First try if the object understands forward::. */
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
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
)
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
);
948 __objc_print_dtable_stats (void)
952 objc_mutex_lock (__objc_runtime_mutex
);
955 printf ("memory usage: (%s)\n", "2-level sparse arrays");
957 printf ("memory usage: (%s)\n", "3-level sparse arrays");
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. */
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
)
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
))
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
);
1040 /* Retrieve the class from the meta class. */
1041 Class c
= objc_getClass (cls
->name
);
1042 assert (CLS_ISMETA (cls
));
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. */
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 ();
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
);
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
);
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
,
1121 /* This wrapper only exists to allow an easy replacement of the lookup
1122 implementation and it is expected that the compiler will optimize
1124 static struct sarray
*
1125 __objc_prepared_dtable_for_class (Class cls
)
1127 struct sarray
*dtable
= 0;
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. */
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
1145 __objc_get_prepared_imp (Class cls
,SEL sel
)
1147 struct sarray
*dtable
;
1152 assert (cls
->dtable
== __objc_uninstalled_dtable
);
1153 dtable
= __objc_prepared_dtable_for_class (cls
);
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. */
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
1169 __objc_install_prepared_dtable_for_class (Class 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
);