1 /* GNU Objective C Runtime message lookup
2 Copyright (C) 1993-2024 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 should be using libffi instead of __builtin_apply
32 #include "objc-private/common.h"
33 #include "objc-private/error.h"
35 #include "coretypes.h"
36 #include "objc/runtime.h"
37 #include "objc/message.h" /* For objc_msg_lookup(), objc_msg_lookup_super(). */
39 #include "objc-private/module-abi-8.h"
40 #include "objc-private/runtime.h"
41 #include "objc-private/hash.h"
42 #include "objc-private/sarray.h"
43 #include "objc-private/selector.h" /* For sel_is_mapped() */
44 #include "runtime-info.h"
45 #include <assert.h> /* For assert */
46 #include <string.h> /* For strlen */
48 #define INVISIBLE_STRUCT_RETURN 1
50 /* The uninstalled dispatch table. If a class' dispatch table points
51 to __objc_uninstalled_dtable then that means it needs its dispatch
52 table to be installed. */
53 struct sarray
*__objc_uninstalled_dtable
= 0; /* !T:MUTEX */
55 /* Two hooks for method forwarding. If either is set, it is invoked to
56 * return a function that performs the real forwarding. If both are
57 * set, the result of __objc_msg_forward2 will be preferred over that
58 * of __objc_msg_forward. If both return NULL or are unset, the
59 * libgcc based functions (__builtin_apply and friends) are used. */
60 IMP (*__objc_msg_forward
) (SEL
) = NULL
;
61 IMP (*__objc_msg_forward2
) (id
, SEL
) = NULL
;
63 /* Send +initialize to class. */
64 static void __objc_send_initialize (Class
);
66 /* Forward declare some functions */
67 static void __objc_install_dtable_for_class (Class cls
);
68 static void __objc_prepare_dtable_for_class (Class cls
);
69 static void __objc_install_prepared_dtable_for_class (Class cls
);
71 static struct sarray
*__objc_prepared_dtable_for_class (Class cls
);
72 static IMP
__objc_get_prepared_imp (Class cls
,SEL sel
);
75 /* Various forwarding functions that are used based upon the
76 return type for the selector.
77 __objc_block_forward for structures.
78 __objc_double_forward for floats/doubles.
79 __objc_word_forward for pointers or types that fit in registers. */
80 static double __objc_double_forward (id
, SEL
, ...);
81 static id
__objc_word_forward (id
, SEL
, ...);
82 typedef struct { id many
[8]; } __big
;
83 #if INVISIBLE_STRUCT_RETURN
88 __objc_block_forward (id
, SEL
, ...);
89 static struct objc_method
* search_for_method_in_hierarchy (Class
class, SEL sel
);
90 struct objc_method
* search_for_method_in_list (struct objc_method_list
* list
, SEL op
);
91 id
nil_method (id
, SEL
);
93 /* Make sure this inline function is exported regardless of GNU89 or C99
94 inlining semantics as it is part of the libobjc ABI. */
95 extern IMP
__objc_get_forward_imp (id
, SEL
);
97 /* Given a selector, return the proper forwarding implementation. */
100 __objc_get_forward_imp (id rcv
, SEL sel
)
102 /* If a custom forwarding hook was registered, try getting a
103 forwarding function from it. There are two forward routine hooks,
104 one that takes the receiver as an argument and one that does
106 if (__objc_msg_forward2
)
109 if ((result
= __objc_msg_forward2 (rcv
, sel
)) != NULL
)
112 if (__objc_msg_forward
)
115 if ((result
= __objc_msg_forward (sel
)) != NULL
)
119 /* In all other cases, use the default forwarding functions built
120 using __builtin_apply and friends. */
122 const char *t
= sel
->sel_types
;
124 if (t
&& (*t
== '[' || *t
== '(' || *t
== '{')
125 #ifdef OBJC_MAX_STRUCT_BY_VALUE
126 && objc_sizeof_type (t
) > OBJC_MAX_STRUCT_BY_VALUE
129 return (IMP
)__objc_block_forward
;
130 else if (t
&& (*t
== 'f' || *t
== 'd'))
131 return (IMP
)__objc_double_forward
;
133 return (IMP
)__objc_word_forward
;
137 /* Selectors for +resolveClassMethod: and +resolveInstanceMethod:.
138 These are set up at startup. */
139 static SEL selector_resolveClassMethod
= NULL
;
140 static SEL selector_resolveInstanceMethod
= NULL
;
142 /* Internal routines use to resolve a class method using
143 +resolveClassMethod:. 'class' is always a non-Nil class (*not* a
144 meta-class), and 'sel' is the selector that we are trying to
145 resolve. This must be called when class is not Nil, and the
146 dispatch table for class methods has already been installed.
148 This routine tries to call +resolveClassMethod: to give an
149 opportunity to resolve the method. If +resolveClassMethod: returns
150 YES, it tries looking up the method again, and if found, it returns
151 it. Else, it returns NULL. */
154 __objc_resolve_class_method (Class
class, SEL sel
)
156 /* We need to lookup +resolveClassMethod:. */
157 BOOL (*resolveMethodIMP
) (id
, SEL
, SEL
);
159 /* The dispatch table for class methods is already installed and we
160 don't want any forwarding to happen when looking up this method,
161 so we just look it up directly. Note that if 'sel' is precisely
162 +resolveClassMethod:, this would look it up yet again and find
163 nothing. That's no problem and there's no recursion. */
164 resolveMethodIMP
= (BOOL (*) (id
, SEL
, SEL
))sarray_get_safe
165 (class->class_pointer
->dtable
, (size_t) selector_resolveClassMethod
->sel_id
);
167 if (resolveMethodIMP
&& resolveMethodIMP ((id
)class, selector_resolveClassMethod
, sel
))
169 /* +resolveClassMethod: returned YES. Look the method up again.
170 We already know the dtable is installed. */
172 /* TODO: There is the case where +resolveClassMethod: is buggy
173 and returned YES without actually adding the method. We
174 could maybe print an error message. */
175 return sarray_get_safe (class->class_pointer
->dtable
, (size_t) sel
->sel_id
);
181 /* Internal routines use to resolve a instance method using
182 +resolveInstanceMethod:. 'class' is always a non-Nil class, and
183 'sel' is the selector that we are trying to resolve. This must be
184 called when class is not Nil, and the dispatch table for instance
185 methods has already been installed.
187 This routine tries to call +resolveInstanceMethod: to give an
188 opportunity to resolve the method. If +resolveInstanceMethod:
189 returns YES, it tries looking up the method again, and if found, it
190 returns it. Else, it returns NULL. */
193 __objc_resolve_instance_method (Class
class, SEL sel
)
195 /* We need to lookup +resolveInstanceMethod:. */
196 BOOL (*resolveMethodIMP
) (id
, SEL
, SEL
);
198 /* The dispatch table for class methods may not be already installed
199 so we have to install it if needed. */
200 resolveMethodIMP
= sarray_get_safe (class->class_pointer
->dtable
,
201 (size_t) selector_resolveInstanceMethod
->sel_id
);
202 if (resolveMethodIMP
== 0)
204 /* Try again after installing the dtable. */
205 if (class->class_pointer
->dtable
== __objc_uninstalled_dtable
)
207 objc_mutex_lock (__objc_runtime_mutex
);
208 if (class->class_pointer
->dtable
== __objc_uninstalled_dtable
)
209 __objc_install_dtable_for_class (class->class_pointer
);
210 objc_mutex_unlock (__objc_runtime_mutex
);
212 resolveMethodIMP
= sarray_get_safe (class->class_pointer
->dtable
,
213 (size_t) selector_resolveInstanceMethod
->sel_id
);
216 if (resolveMethodIMP
&& resolveMethodIMP ((id
)class, selector_resolveInstanceMethod
, sel
))
218 /* +resolveInstanceMethod: returned YES. Look the method up
219 again. We already know the dtable is installed. */
221 /* TODO: There is the case where +resolveInstanceMethod: is
222 buggy and returned YES without actually adding the method.
223 We could maybe print an error message. */
224 return sarray_get_safe (class->dtable
, (size_t) sel
->sel_id
);
230 /* Given a CLASS and selector, return the implementation corresponding
231 to the method of the selector.
233 If CLASS is a class, the instance method is returned.
234 If CLASS is a meta class, the class method is returned.
236 Since this requires the dispatch table to be installed, this function
237 will implicitly invoke +initialize for CLASS if it hasn't been
238 invoked yet. This also insures that +initialize has been invoked
239 when the returned implementation is called directly.
241 The forwarding hooks require the receiver as an argument (if they are to
242 perform dynamic lookup in proxy objects etc), so this function has a
243 receiver argument to be used with those hooks. */
246 get_implementation (id receiver
, Class
class, SEL sel
)
250 if (class->dtable
== __objc_uninstalled_dtable
)
252 /* The dispatch table needs to be installed. */
253 objc_mutex_lock (__objc_runtime_mutex
);
255 /* Double-checked locking pattern: Check
256 __objc_uninstalled_dtable again in case another thread
257 installed the dtable while we were waiting for the lock to be
259 if (class->dtable
== __objc_uninstalled_dtable
)
260 __objc_install_dtable_for_class (class);
262 /* If the dispatch table is not yet installed, we are still in
263 the process of executing +initialize. But the implementation
264 pointer should be available in the prepared ispatch table if
266 if (class->dtable
== __objc_uninstalled_dtable
)
268 assert (__objc_prepared_dtable_for_class (class) != 0);
269 res
= __objc_get_prepared_imp (class, sel
);
274 objc_mutex_unlock (__objc_runtime_mutex
);
275 /* Call ourselves with the installed dispatch table and get the
278 res
= get_implementation (receiver
, class, sel
);
282 /* The dispatch table has been installed. */
283 res
= sarray_get_safe (class->dtable
, (size_t) sel
->sel_id
);
286 /* The dispatch table has been installed, and the method is
287 not in the dispatch table. So the method just doesn't
288 exist for the class. */
290 /* Try going through the +resolveClassMethod: or
291 +resolveInstanceMethod: process. */
292 if (CLS_ISMETA (class))
294 /* We have the meta class, but we need to invoke the
295 +resolveClassMethod: method on the class. So, we
296 need to obtain the class from the meta class, which
297 we do using the fact that both the class and the
298 meta-class have the same name. */
299 Class realClass
= objc_lookUpClass (class->name
);
301 res
= __objc_resolve_class_method (realClass
, sel
);
304 res
= __objc_resolve_instance_method (class, sel
);
307 res
= __objc_get_forward_imp (receiver
, sel
);
313 /* Make sure this inline function is exported regardless of GNU89 or C99
314 inlining semantics as it is part of the libobjc ABI. */
315 extern IMP
get_imp (Class
, SEL
);
319 get_imp (Class
class, SEL sel
)
321 /* In a vanilla implementation we would first check if the dispatch
322 table is installed. Here instead, to get more speed in the
323 standard case (that the dispatch table is installed) we first try
324 to get the imp using brute force. Only if that fails, we do what
325 we should have been doing from the very beginning, that is, check
326 if the dispatch table needs to be installed, install it if it's
327 not installed, and retrieve the imp from the table if it's
329 void *res
= sarray_get_safe (class->dtable
, (size_t) sel
->sel_id
);
332 res
= get_implementation(nil
, class, sel
);
337 /* The new name of get_imp(). */
339 class_getMethodImplementation (Class class_
, SEL selector
)
341 if (class_
== Nil
|| selector
== NULL
)
344 /* get_imp is inlined, so we're good. */
345 return get_imp (class_
, selector
);
348 /* Given a method, return its implementation. This has been replaced
349 by method_getImplementation() in the modern API. */
351 method_get_imp (struct objc_method
* method
)
353 return (method
!= (struct objc_method
*)0) ? method
->method_imp
: (IMP
)0;
356 /* Query if an object can respond to a selector, returns YES if the
357 object implements the selector otherwise NO. Does not check if the
358 method can be forwarded. Since this requires the dispatch table to
359 installed, this function will implicitly invoke +initialize for the
360 class of OBJECT if it hasn't been invoked yet. */
363 __objc_responds_to (id object
, SEL sel
)
366 struct sarray
*dtable
;
368 /* Install dispatch table if need be */
369 dtable
= object
->class_pointer
->dtable
;
370 if (dtable
== __objc_uninstalled_dtable
)
372 objc_mutex_lock (__objc_runtime_mutex
);
373 if (object
->class_pointer
->dtable
== __objc_uninstalled_dtable
)
374 __objc_install_dtable_for_class (object
->class_pointer
);
376 /* If the dispatch table is not yet installed, we are still in
377 the process of executing +initialize. Yet the dispatch table
378 should be available. */
379 if (object
->class_pointer
->dtable
== __objc_uninstalled_dtable
)
381 dtable
= __objc_prepared_dtable_for_class (object
->class_pointer
);
385 dtable
= object
->class_pointer
->dtable
;
387 objc_mutex_unlock (__objc_runtime_mutex
);
390 /* Get the method from the dispatch table. */
391 res
= sarray_get_safe (dtable
, (size_t) sel
->sel_id
);
392 return (res
!= 0) ? YES
: NO
;
396 class_respondsToSelector (Class class_
, SEL selector
)
398 struct sarray
*dtable
;
401 if (class_
== Nil
|| selector
== NULL
)
404 /* Install dispatch table if need be. */
405 dtable
= class_
->dtable
;
406 if (dtable
== __objc_uninstalled_dtable
)
408 objc_mutex_lock (__objc_runtime_mutex
);
409 if (class_
->dtable
== __objc_uninstalled_dtable
)
410 __objc_install_dtable_for_class (class_
);
412 /* If the dispatch table is not yet installed,
413 we are still in the process of executing +initialize.
414 Yet the dispatch table should be available. */
415 if (class_
->dtable
== __objc_uninstalled_dtable
)
417 dtable
= __objc_prepared_dtable_for_class (class_
);
421 dtable
= class_
->dtable
;
423 objc_mutex_unlock (__objc_runtime_mutex
);
426 /* Get the method from the dispatch table. */
427 res
= sarray_get_safe (dtable
, (size_t) selector
->sel_id
);
428 return (res
!= 0) ? YES
: NO
;
431 /* This is the lookup function. All entries in the table are either a
432 valid method *or* zero. If zero then either the dispatch table
433 needs to be installed or it doesn't exist and forwarding is
436 objc_msg_lookup (id receiver
, SEL op
)
441 /* First try a quick lookup assuming the dispatch table exists. */
442 result
= sarray_get_safe (receiver
->class_pointer
->dtable
,
446 /* Not found ... call get_implementation () to install the
447 dispatch table and call +initialize as required,
448 providing the method implementation or a forwarding
450 result
= get_implementation (receiver
, receiver
->class_pointer
, op
);
455 return (IMP
)nil_method
;
459 objc_msg_lookup_super (struct objc_super
*super
, SEL sel
)
462 return get_imp (super
->super_class
, sel
);
464 return (IMP
)nil_method
;
468 __objc_init_dispatch_tables ()
470 __objc_uninstalled_dtable
= sarray_new (200, 0);
472 /* TODO: It would be cool to register typed selectors here. */
473 selector_resolveClassMethod
= sel_registerName ("resolveClassMethod:");
474 selector_resolveInstanceMethod
= sel_registerName ("resolveInstanceMethod:");
478 /* Install dummy table for class which causes the first message to
479 that class (or instances hereof) to be initialized properly. */
481 __objc_install_premature_dtable (Class
class)
483 assert (__objc_uninstalled_dtable
);
484 class->dtable
= __objc_uninstalled_dtable
;
487 /* Send +initialize to class if not already done. */
489 __objc_send_initialize (Class
class)
491 /* This *must* be a class object. */
492 assert (CLS_ISCLASS (class));
493 assert (! CLS_ISMETA (class));
495 /* class_add_method_list/__objc_update_dispatch_table_for_class may
496 have reset the dispatch table. The canonical way to insure that
497 we send +initialize just once, is this flag. */
498 if (! CLS_ISINITIALIZED (class))
500 DEBUG_PRINTF ("+initialize: need to initialize class '%s'\n", class->name
);
501 CLS_SETINITIALIZED (class);
502 CLS_SETINITIALIZED (class->class_pointer
);
504 /* Create the garbage collector type memory description. */
505 __objc_generate_gc_type_description (class);
507 if (class->super_class
)
508 __objc_send_initialize (class->super_class
);
511 SEL op
= sel_registerName ("initialize");
512 struct objc_method
*method
= search_for_method_in_hierarchy (class->class_pointer
,
517 DEBUG_PRINTF (" begin of [%s +initialize]\n", class->name
);
518 (*method
->method_imp
) ((id
)class, op
);
519 DEBUG_PRINTF (" end of [%s +initialize]\n", class->name
);
524 DEBUG_PRINTF (" class '%s' has no +initialize method\n", class->name
);
531 /* Walk on the methods list of class and install the methods in the
532 reverse order of the lists. Since methods added by categories are
533 before the methods of class in the methods list, this allows
534 categories to substitute methods declared in class. However if
535 more than one category replaces the same method nothing is
536 guaranteed about what method will be used. Assumes that
537 __objc_runtime_mutex is locked down. */
539 __objc_install_methods_in_dtable (struct sarray
*dtable
, struct objc_method_list
* method_list
)
546 if (method_list
->method_next
)
547 __objc_install_methods_in_dtable (dtable
, method_list
->method_next
);
549 for (i
= 0; i
< method_list
->method_count
; i
++)
551 struct objc_method
* method
= &(method_list
->method_list
[i
]);
552 sarray_at_put_safe (dtable
,
553 (sidx
) method
->method_name
->sel_id
,
559 __objc_update_dispatch_table_for_class (Class
class)
564 DEBUG_PRINTF (" _objc_update_dtable_for_class (%s)\n", class->name
);
566 objc_mutex_lock (__objc_runtime_mutex
);
568 /* Not yet installed -- skip it unless in +initialize. */
569 if (class->dtable
== __objc_uninstalled_dtable
)
571 if (__objc_prepared_dtable_for_class (class))
573 /* There is a prepared table so we must be initialising this
574 class ... we must re-do the table preparation. */
575 __objc_prepare_dtable_for_class (class);
577 objc_mutex_unlock (__objc_runtime_mutex
);
582 __objc_install_premature_dtable (class); /* someone might require it... */
583 sarray_free (arr
); /* release memory */
585 /* Could have been lazy... */
586 __objc_install_dtable_for_class (class);
588 if (class->subclass_list
) /* Traverse subclasses. */
589 for (next
= class->subclass_list
; next
; next
= next
->sibling_class
)
590 __objc_update_dispatch_table_for_class (next
);
592 objc_mutex_unlock (__objc_runtime_mutex
);
595 /* This function adds a method list to a class. This function is
596 typically called by another function specific to the run-time. As
597 such this function does not worry about thread safe issues.
599 This one is only called for categories. Class objects have their
600 methods installed right away, and their selectors are made into
601 SEL's by the function __objc_register_selectors_from_class. */
603 class_add_method_list (Class
class, struct objc_method_list
* list
)
605 /* Passing of a linked list is not allowed. Do multiple calls. */
606 assert (! list
->method_next
);
608 __objc_register_selectors_from_list(list
);
610 /* Add the methods to the class's method list. */
611 list
->method_next
= class->methods
;
612 class->methods
= list
;
614 /* Update the dispatch table of class. */
615 __objc_update_dispatch_table_for_class (class);
619 class_getInstanceMethod (Class class_
, SEL selector
)
621 struct objc_method
*m
;
623 if (class_
== Nil
|| selector
== NULL
)
626 m
= search_for_method_in_hierarchy (class_
, selector
);
630 /* Try going through +resolveInstanceMethod:, and do the search
631 again if successful. */
632 if (__objc_resolve_instance_method (class_
, selector
))
633 return search_for_method_in_hierarchy (class_
, selector
);
639 class_getClassMethod (Class class_
, SEL selector
)
641 struct objc_method
*m
;
643 if (class_
== Nil
|| selector
== NULL
)
646 m
= search_for_method_in_hierarchy (class_
->class_pointer
,
651 /* Try going through +resolveClassMethod:, and do the search again
653 if (__objc_resolve_class_method (class_
, selector
))
654 return search_for_method_in_hierarchy (class_
->class_pointer
,
661 class_addMethod (Class class_
, SEL selector
, IMP implementation
,
662 const char *method_types
)
664 struct objc_method_list
*method_list
;
665 struct objc_method
*method
;
666 const char *method_name
;
668 if (class_
== Nil
|| selector
== NULL
|| implementation
== NULL
669 || method_types
== NULL
|| (strcmp (method_types
, "") == 0))
672 method_name
= sel_getName (selector
);
673 if (method_name
== NULL
)
676 /* If the method already exists in the class, return NO. It is fine
677 if the method already exists in the superclass; in that case, we
678 are overriding it. */
679 if (CLS_IS_IN_CONSTRUCTION (class_
))
681 /* The class only contains a list of methods; they have not been
682 registered yet, ie, the method_name of each of them is still
683 a string, not a selector. Iterate manually over them to
684 check if we have already added the method. */
685 struct objc_method_list
* method_list
= class_
->methods
;
690 /* Search the method list. */
691 for (i
= 0; i
< method_list
->method_count
; ++i
)
693 struct objc_method
* method
= &method_list
->method_list
[i
];
695 if (method
->method_name
696 && strcmp ((char *)method
->method_name
, method_name
) == 0)
700 /* The method wasn't found. Follow the link to the next list of
702 method_list
= method_list
->method_next
;
704 /* The method wasn't found. It's a new one. Go ahead and add
709 /* Do the standard lookup. This assumes the selectors are
711 if (search_for_method_in_list (class_
->methods
, selector
))
715 method_list
= (struct objc_method_list
*)objc_calloc (1, sizeof (struct objc_method_list
));
716 method_list
->method_count
= 1;
718 method
= &(method_list
->method_list
[0]);
719 method
->method_name
= objc_malloc (strlen (method_name
) + 1);
720 strcpy ((char *)method
->method_name
, method_name
);
722 method
->method_types
= objc_malloc (strlen (method_types
) + 1);
723 strcpy ((char *)method
->method_types
, method_types
);
725 method
->method_imp
= implementation
;
727 if (CLS_IS_IN_CONSTRUCTION (class_
))
729 /* We only need to add the method to the list. It will be
730 registered with the runtime when the class pair is registered
732 method_list
->method_next
= class_
->methods
;
733 class_
->methods
= method_list
;
737 /* Add the method to a live class. */
738 objc_mutex_lock (__objc_runtime_mutex
);
739 class_add_method_list (class_
, method_list
);
740 objc_mutex_unlock (__objc_runtime_mutex
);
747 class_replaceMethod (Class class_
, SEL selector
, IMP implementation
,
748 const char *method_types
)
750 struct objc_method
* method
;
752 if (class_
== Nil
|| selector
== NULL
|| implementation
== NULL
753 || method_types
== NULL
)
756 method
= search_for_method_in_hierarchy (class_
, selector
);
760 return method_setImplementation (method
, implementation
);
764 class_addMethod (class_
, selector
, implementation
, method_types
);
769 /* Search for a method starting from the current class up its
770 hierarchy. Return a pointer to the method's method structure if
771 found. NULL otherwise. */
772 static struct objc_method
*
773 search_for_method_in_hierarchy (Class cls
, SEL sel
)
775 struct objc_method
* method
= NULL
;
778 if (! sel_is_mapped (sel
))
781 /* Scan the method list of the class. If the method isn't found in
782 the list then step to its super class. */
783 for (class = cls
; ((! method
) && class); class = class->super_class
)
784 method
= search_for_method_in_list (class->methods
, sel
);
791 /* Given a linked list of method and a method's name. Search for the
792 named method's method structure. Return a pointer to the method's
793 method structure if found. NULL otherwise. */
795 search_for_method_in_list (struct objc_method_list
* list
, SEL op
)
797 struct objc_method_list
* method_list
= list
;
799 if (! sel_is_mapped (op
))
802 /* If not found then we'll search the list. */
807 /* Search the method list. */
808 for (i
= 0; i
< method_list
->method_count
; ++i
)
810 struct objc_method
* method
= &method_list
->method_list
[i
];
812 if (method
->method_name
)
813 if (method
->method_name
->sel_id
== op
->sel_id
)
817 /* The method wasn't found. Follow the link to the next list of
819 method_list
= method_list
->method_next
;
825 typedef void * retval_t
;
826 typedef void * arglist_t
;
828 static retval_t
__objc_forward (id object
, SEL sel
, arglist_t args
);
830 /* Forwarding pointers/integers through the normal registers. */
832 __objc_word_forward (id rcv
, SEL op
, ...)
836 args
= __builtin_apply_args ();
837 res
= __objc_forward (rcv
, op
, args
);
839 __builtin_return (res
);
844 /* Specific routine for forwarding floats/double because of
845 architectural differences on some processors. i386s for example
846 which uses a floating point stack versus general registers for
847 floating point numbers. This forward routine makes sure that GCC
848 restores the proper return values. */
850 __objc_double_forward (id rcv
, SEL op
, ...)
854 args
= __builtin_apply_args ();
855 res
= __objc_forward (rcv
, op
, args
);
856 __builtin_return (res
);
859 #if INVISIBLE_STRUCT_RETURN
864 __objc_block_forward (id rcv
, SEL op
, ...)
868 args
= __builtin_apply_args ();
869 res
= __objc_forward (rcv
, op
, args
);
871 __builtin_return (res
);
873 #if INVISIBLE_STRUCT_RETURN
874 return (__big
) {{0, 0, 0, 0, 0, 0, 0, 0}};
881 /* This function is called for methods which are not implemented,
882 unless a custom forwarding routine has been installed. Please note
883 that most serious users of libobjc (eg, GNUstep base) do install
884 their own forwarding routines, and hence this is never actually
885 used. But, if no custom forwarding routine is installed, this is
886 called when a selector is not recognized. */
888 __objc_forward (id object
, SEL sel
, arglist_t args
)
891 static SEL frwd_sel
= 0; /* !T:SAFE2 */
894 /* First try if the object understands forward::. */
896 frwd_sel
= sel_get_any_uid ("forward::");
898 if (__objc_responds_to (object
, frwd_sel
))
900 imp
= get_implementation (object
, object
->class_pointer
, frwd_sel
);
901 return (*imp
) (object
, frwd_sel
, sel
, args
);
904 /* If the object recognizes the doesNotRecognize: method then we're
906 err_sel
= sel_get_any_uid ("doesNotRecognize:");
907 if (__objc_responds_to (object
, err_sel
))
909 imp
= get_implementation (object
, object
->class_pointer
, err_sel
);
910 return (*imp
) (object
, err_sel
, sel
);
913 /* The object doesn't recognize the method. Check for responding to
914 error:. If it does then sent it. */
916 char msg
[256 + strlen ((const char *) sel_getName (sel
))
917 + strlen ((const char *) object
->class_pointer
->name
)];
919 sprintf (msg
, "(%s) %s does not recognize %s",
920 (CLS_ISMETA (object
->class_pointer
)
923 object
->class_pointer
->name
, sel_getName (sel
));
925 /* The object doesn't respond to doesNotRecognize:. Therefore, a
926 default action is taken. */
927 _objc_abort ("%s\n", msg
);
934 __objc_print_dtable_stats (void)
938 objc_mutex_lock (__objc_runtime_mutex
);
941 printf ("memory usage: (%s)\n", "2-level sparse arrays");
943 printf ("memory usage: (%s)\n", "3-level sparse arrays");
946 printf ("arrays: %d = %ld bytes\n", narrays
,
947 (long) ((size_t) narrays
* sizeof (struct sarray
)));
948 total
+= narrays
* sizeof (struct sarray
);
949 printf ("buckets: %d = %ld bytes\n", nbuckets
,
950 (long) ((size_t) nbuckets
* sizeof (struct sbucket
)));
951 total
+= nbuckets
* sizeof (struct sbucket
);
953 printf ("idxtables: %d = %ld bytes\n",
954 idxsize
, (long) ((size_t) idxsize
* sizeof (void *)));
955 total
+= idxsize
* sizeof (void *);
956 printf ("-----------------------------------\n");
957 printf ("total: %d bytes\n", total
);
958 printf ("===================================\n");
960 objc_mutex_unlock (__objc_runtime_mutex
);
963 static cache_ptr prepared_dtable_table
= 0;
965 /* This function is called by: objc_msg_lookup, get_imp and
966 __objc_responds_to (and the dispatch table installation functions
967 themselves) to install a dispatch table for a class.
969 If CLS is a class, it installs instance methods.
970 If CLS is a meta class, it installs class methods.
972 In either case +initialize is invoked for the corresponding class.
974 The implementation must insure that the dispatch table is not
975 installed until +initialize completes. Otherwise it opens a
976 potential race since the installation of the dispatch table is used
977 as gate in regular method dispatch and we need to guarantee that
978 +initialize is the first method invoked an that no other thread my
979 dispatch messages to the class before +initialize completes. */
981 __objc_install_dtable_for_class (Class cls
)
983 /* If the class has not yet had its class links resolved, we must
984 re-compute all class links. */
985 if (! CLS_ISRESOLV (cls
))
986 __objc_resolve_class_links ();
988 /* Make sure the super class has its dispatch table installed or is
989 at least preparing. We do not need to send initialize for the
990 super class since __objc_send_initialize will insure that. */
992 && cls
->super_class
->dtable
== __objc_uninstalled_dtable
993 && !__objc_prepared_dtable_for_class (cls
->super_class
))
995 __objc_install_dtable_for_class (cls
->super_class
);
996 /* The superclass initialisation may have also initialised the
997 current class, in which case there is no more to do. */
998 if (cls
->dtable
!= __objc_uninstalled_dtable
)
1002 /* We have already been prepared but +initialize hasn't completed.
1003 The +initialize implementation is probably sending 'self'
1004 messages. We rely on _objc_get_prepared_imp to retrieve the
1005 implementation pointers. */
1006 if (__objc_prepared_dtable_for_class (cls
))
1009 /* We have this function cache the implementation pointers for
1010 _objc_get_prepared_imp but the dispatch table won't be initilized
1011 until __objc_send_initialize completes. */
1012 __objc_prepare_dtable_for_class (cls
);
1014 /* We may have already invoked +initialize but
1015 __objc_update_dispatch_table_for_class invoked by
1016 class_add_method_list may have reset dispatch table. */
1018 /* Call +initialize. If we are a real class, we are installing
1019 instance methods. If we are a meta class, we are installing
1020 class methods. The __objc_send_initialize itself will insure
1021 that the message is called only once per class. */
1022 if (CLS_ISCLASS (cls
))
1023 __objc_send_initialize (cls
);
1026 /* Retrieve the class from the meta class. */
1027 Class c
= objc_getClass (cls
->name
);
1028 assert (CLS_ISMETA (cls
));
1030 __objc_send_initialize (c
);
1033 /* We install the dispatch table correctly when +initialize completed. */
1034 __objc_install_prepared_dtable_for_class (cls
);
1037 /* Builds the dispatch table for the class CLS and stores it in a
1038 place where it can be retrieved by __objc_get_prepared_imp until
1039 __objc_install_prepared_dtable_for_class installs it into the
1040 class. The dispatch table should not be installed into the class
1041 until +initialize has completed. */
1043 __objc_prepare_dtable_for_class (Class cls
)
1045 struct sarray
*dtable
;
1046 struct sarray
*super_dtable
;
1048 /* This table could be initialized in init.c. We cannot use the
1049 class name since the class maintains the instance methods and the
1050 meta class maintains the class methods yet both share the
1051 same name. Classes should be unique in any program. */
1052 if (! prepared_dtable_table
)
1053 prepared_dtable_table
1054 = objc_hash_new (32,
1055 (hash_func_type
) objc_hash_ptr
,
1056 (compare_func_type
) objc_compare_ptrs
);
1058 /* If the class has not yet had its class links resolved, we must
1059 re-compute all class links. */
1060 if (! CLS_ISRESOLV (cls
))
1061 __objc_resolve_class_links ();
1064 assert (cls
->dtable
== __objc_uninstalled_dtable
);
1066 /* If there is already a prepared dtable for this class, we must
1067 replace it with a new version (since there must have been methods
1068 added to or otherwise modified in the class while executing
1069 +initialize, and the table needs to be recomputed. */
1070 dtable
= __objc_prepared_dtable_for_class (cls
);
1073 objc_hash_remove (prepared_dtable_table
, cls
);
1074 sarray_free (dtable
);
1077 /* Now prepare the dtable for population. */
1078 assert (cls
!= cls
->super_class
);
1079 if (cls
->super_class
)
1081 /* Inherit the method list from the super class. Yet the super
1082 class may still be initializing in the case when a class
1083 cluster sub class initializes its super classes. */
1084 if (cls
->super_class
->dtable
== __objc_uninstalled_dtable
)
1085 __objc_install_dtable_for_class (cls
->super_class
);
1087 super_dtable
= cls
->super_class
->dtable
;
1088 /* If the dispatch table is not yet installed, we are still in
1089 the process of executing +initialize. Yet the dispatch table
1090 should be available. */
1091 if (super_dtable
== __objc_uninstalled_dtable
)
1092 super_dtable
= __objc_prepared_dtable_for_class (cls
->super_class
);
1094 assert (super_dtable
);
1095 dtable
= sarray_lazy_copy (super_dtable
);
1098 dtable
= sarray_new (__objc_selector_max_index
, 0);
1100 __objc_install_methods_in_dtable (dtable
, cls
->methods
);
1102 objc_hash_add (&prepared_dtable_table
,
1107 /* This wrapper only exists to allow an easy replacement of the lookup
1108 implementation and it is expected that the compiler will optimize
1110 static struct sarray
*
1111 __objc_prepared_dtable_for_class (Class cls
)
1113 struct sarray
*dtable
= 0;
1115 if (prepared_dtable_table
)
1116 dtable
= objc_hash_value_for_key (prepared_dtable_table
, cls
);
1117 /* dtable my be nil, since we call this to check whether we are
1118 currently preparing before we start preparing. */
1122 /* Helper function for messages sent to CLS or implementation pointers
1123 retrieved from CLS during +initialize before the dtable is
1124 installed. When a class implicitly initializes another class which
1125 in turn implicitly invokes methods in this class, before the
1126 implementation of +initialize of CLS completes, this returns the
1127 expected implementation. Forwarding remains the responsibility of
1128 objc_msg_lookup. This function should only be called under the
1131 __objc_get_prepared_imp (Class cls
,SEL sel
)
1133 struct sarray
*dtable
;
1138 assert (cls
->dtable
== __objc_uninstalled_dtable
);
1139 dtable
= __objc_prepared_dtable_for_class (cls
);
1142 assert (dtable
!= __objc_uninstalled_dtable
);
1143 imp
= sarray_get_safe (dtable
, (size_t) sel
->sel_id
);
1145 /* imp may be Nil if the method does not exist and we may fallback
1146 to the forwarding implementation later. */
1150 /* When this function is called +initialize should be completed. So
1151 now we are safe to install the dispatch table for the class so that
1152 they become available for other threads that may be waiting in the
1155 __objc_install_prepared_dtable_for_class (Class cls
)
1158 assert (cls
->dtable
== __objc_uninstalled_dtable
);
1159 cls
->dtable
= __objc_prepared_dtable_for_class (cls
);
1161 assert (cls
->dtable
);
1162 assert (cls
->dtable
!= __objc_uninstalled_dtable
);
1163 objc_hash_remove (prepared_dtable_table
, cls
);