OSDN Git Service

In libobjc/:
[pf3gnuchains/gcc-fork.git] / libobjc / sendmsg.c
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
5
6 This file is part of GCC.
7
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.
11
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
15 details.
16
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.
20
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/>.  */
25
26 /* Uncommented the following line to enable debug logging.  Use this
27    only while debugging the runtime.  */
28 /* #define DEBUG 1 */
29
30 /* FIXME: This file has no business including tm.h.  */
31 /* FIXME: This should be using libffi instead of __builtin_apply
32    and friends.  */
33
34 #include "objc-private/common.h"
35 #include "objc-private/error.h"
36 #include "tconfig.h"
37 #include "coretypes.h"
38 #include "tm.h"
39 #include "objc/runtime.h"
40 #include "objc/message.h"          /* For objc_msg_lookup(), objc_msg_lookup_super().  */
41 #include "objc/thr.h"
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 */
50
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.  */
56 #undef rtx
57 #define rtx int
58
59 #if ! defined (STRUCT_VALUE) || STRUCT_VALUE == 0
60 #define INVISIBLE_STRUCT_RETURN 1
61 #else
62 #define INVISIBLE_STRUCT_RETURN 0
63 #endif
64
65 /* The uninstalled dispatch table.  */
66 struct sarray *__objc_uninstalled_dtable = 0;   /* !T:MUTEX */
67
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;
75
76 /* Send +initialize to class.  */
77 static void __objc_send_initialize (Class);
78
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);
83
84 static struct sarray *__objc_prepared_dtable_for_class (Class cls);
85 static IMP __objc_get_prepared_imp (Class cls,SEL sel);
86   
87
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 
97 static __big 
98 #else
99 static id
100 #endif
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);
105
106 /* Given a selector, return the proper forwarding implementation.  */
107 inline
108 IMP
109 __objc_get_forward_imp (id rcv, SEL sel)
110 {
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
114      not.  */
115   if (__objc_msg_forward2)
116     {
117       IMP result;
118       if ((result = __objc_msg_forward2 (rcv, sel)) != NULL)
119        return result;
120     }
121   if (__objc_msg_forward)
122     {
123       IMP result;
124       if ((result = __objc_msg_forward (sel)) != NULL) 
125         return result;
126     }
127
128   /* In all other cases, use the default forwarding functions built
129      using __builtin_apply and friends.  */
130     {
131       const char *t = sel->sel_types;
132       
133       if (t && (*t == '[' || *t == '(' || *t == '{')
134 #ifdef OBJC_MAX_STRUCT_BY_VALUE
135           && objc_sizeof_type (t) > OBJC_MAX_STRUCT_BY_VALUE
136 #endif
137           )
138         return (IMP)__objc_block_forward;
139       else if (t && (*t == 'f' || *t == 'd'))
140         return (IMP)__objc_double_forward;
141       else
142         return (IMP)__objc_word_forward;
143     }
144 }
145
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;
150
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.
156
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.  */
161 static inline
162 IMP
163 __objc_resolve_class_method (Class class, SEL sel)
164 {
165   /* We need to lookup +resolveClassMethod:.  */
166   BOOL (*resolveMethodIMP) (id, SEL, SEL);
167
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);
175
176   if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveClassMethod, sel))
177     {
178       /* +resolveClassMethod: returned YES.  Look the method up again.
179          We already know the dtable is installed.  */
180       
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);
185     }
186
187   return NULL;
188 }
189
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.
195
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.  */
200 static inline
201 IMP
202 __objc_resolve_instance_method (Class class, SEL sel)
203 {
204   /* We need to lookup +resolveInstanceMethod:.  */
205   BOOL (*resolveMethodIMP) (id, SEL, SEL);
206
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)
212     {
213       /* Try again after installing the dtable.  */
214       if (class->class_pointer->dtable == __objc_uninstalled_dtable)
215         {
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);
220         }
221       resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable,
222                                           (size_t) selector_resolveInstanceMethod->sel_id);           
223     }
224
225   if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveInstanceMethod, sel))
226     {
227       /* +resolveInstanceMethod: returned YES.  Look the method up
228          again.  We already know the dtable is installed.  */
229       
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);     
234     }
235
236   return NULL;
237 }
238
239 /* Given a CLASS and selector, return the implementation corresponding
240    to the method of the selector.
241
242    If CLASS is a class, the instance method is returned.
243    If CLASS is a meta class, the class method is returned.
244
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.
249
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.  */
253 static inline
254 IMP
255 get_implementation (id receiver, Class class, SEL sel)
256 {
257   void *res;
258
259   if (class->dtable == __objc_uninstalled_dtable)
260     {
261       /* The dispatch table needs to be installed.  */
262       objc_mutex_lock (__objc_runtime_mutex);
263
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
267          to be released.  */
268       if (class->dtable == __objc_uninstalled_dtable)
269         {
270           __objc_install_dtable_for_class (class);
271         }
272
273       /* If the dispatch table is not yet installed,
274         we are still in the process of executing +initialize.
275         But the implementation pointer should be available
276         in the prepared ispatch table if it exists at all.  */
277       if (class->dtable == __objc_uninstalled_dtable)
278         {
279           assert (__objc_prepared_dtable_for_class (class) != 0);
280           res = __objc_get_prepared_imp (class, sel);
281         }
282       else
283         {
284           res = 0;
285         }
286       objc_mutex_unlock (__objc_runtime_mutex);
287       /* Call ourselves with the installed dispatch table and get
288          the real method.  */
289       if (!res)
290         res = get_implementation (receiver, class, sel);
291     }
292   else
293     {
294       /* The dispatch table has been installed.  */
295       res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
296       if (res == 0)
297         {
298           /* The dispatch table has been installed, and the method
299              is not in the dispatch table.  So the method just
300              doesn't exist for the class.  */
301
302           /* Try going through the +resolveClassMethod: or
303              +resolveInstanceMethod: process.  */
304           if (CLS_ISMETA (class))
305             {
306               /* We have the meta class, but we need to invoke the
307                  +resolveClassMethod: method on the class.  So, we
308                  need to obtain the class from the meta class,
309                  which we do using the fact that both the class
310                  and the meta-class have the same name.  */
311               Class realClass = objc_lookUpClass (class->name);
312               if (realClass)
313                 res = __objc_resolve_class_method (realClass, sel);
314             }
315           else
316             res = __objc_resolve_instance_method (class, sel);
317
318           if (res == 0)
319             {
320               res = __objc_get_forward_imp (receiver, sel);
321             }
322         }
323     }
324   return res;
325 }
326
327 inline
328 IMP
329 get_imp (Class class, SEL sel)
330 {
331   /* In a vanilla implementation we would first check if the dispatch
332      table is installed.  Here instead, to get more speed in the
333      standard case (that the dispatch table is installed) we first try
334      to get the imp using brute force.  Only if that fails, we do what
335      we should have been doing from the very beginning, that is, check
336      if the dispatch table needs to be installed, install it if it's
337      not installed, and retrieve the imp from the table if it's
338      installed.  */
339   void *res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
340   if (res == 0)
341     {
342       res = get_implementation(nil, class, sel);
343     }
344   return res;
345 }
346
347 /* The new name of get_imp().  */
348 IMP
349 class_getMethodImplementation (Class class_, SEL selector)
350 {
351   if (class_ == Nil  ||  selector == NULL)
352     return NULL;
353
354   /* get_imp is inlined, so we're good.  */
355   return get_imp (class_, selector);
356 }
357
358 /* Given a method, return its implementation.  This has been replaced
359    by method_getImplementation() in the modern API.  */
360 IMP
361 method_get_imp (struct objc_method * method)
362 {
363   return (method != (struct objc_method *)0) ? method->method_imp : (IMP)0;
364 }
365
366 /* Query if an object can respond to a selector, returns YES if the
367    object implements the selector otherwise NO.  Does not check if the
368    method can be forwarded.
369    Since this requires the dispatch table to installed, this function
370    will implicitly invoke +initialize for the class of OBJECT if it
371    hasn't been invoked yet.  */
372 inline
373 BOOL
374 __objc_responds_to (id object, SEL sel)
375 {
376   void *res;
377   struct sarray *dtable;
378
379   /* Install dispatch table if need be */
380   dtable = object->class_pointer->dtable;
381   if (dtable == __objc_uninstalled_dtable)
382     {
383       objc_mutex_lock (__objc_runtime_mutex);
384       if (object->class_pointer->dtable == __objc_uninstalled_dtable)
385         __objc_install_dtable_for_class (object->class_pointer);
386
387       /* If the dispatch table is not yet installed,
388          we are still in the process of executing +initialize.
389          Yet the dispatch table should be available.  */
390       if (object->class_pointer->dtable == __objc_uninstalled_dtable)
391         {
392           dtable = __objc_prepared_dtable_for_class (object->class_pointer);
393           assert (dtable);
394         }
395       else
396         dtable = object->class_pointer->dtable;
397
398       objc_mutex_unlock (__objc_runtime_mutex);
399     }
400
401   /* Get the method from the dispatch table.  */
402   res = sarray_get_safe (dtable, (size_t) sel->sel_id);
403   return (res != 0) ? YES : NO;
404 }
405
406 BOOL
407 class_respondsToSelector (Class class_, SEL selector)
408 {
409   struct sarray *dtable;
410   void *res;
411
412   if (class_ == Nil  ||  selector == NULL)
413     return NO;
414
415   /* Install dispatch table if need be.  */
416   dtable = class_->dtable;
417   if (dtable == __objc_uninstalled_dtable)
418     {
419       objc_mutex_lock (__objc_runtime_mutex);
420       if (class_->dtable == __objc_uninstalled_dtable)
421         {
422           __objc_install_dtable_for_class (class_);
423         }
424       /* If the dispatch table is not yet installed,
425          we are still in the process of executing +initialize.
426          Yet the dispatch table should be available.  */
427       if (class_->dtable == __objc_uninstalled_dtable)
428         {
429           dtable = __objc_prepared_dtable_for_class (class_);
430           assert (dtable);
431         }
432       else
433         dtable = class_->dtable;
434       objc_mutex_unlock (__objc_runtime_mutex);
435     }
436
437   /* Get the method from the dispatch table.  */
438   res = sarray_get_safe (dtable, (size_t) selector->sel_id);
439   return (res != 0) ? YES : NO;
440 }
441
442 /* This is the lookup function.  All entries in the table are either a
443    valid method *or* zero.  If zero then either the dispatch table
444    needs to be installed or it doesn't exist and forwarding is
445    attempted.  */
446 IMP
447 objc_msg_lookup (id receiver, SEL op)
448 {
449   IMP result;
450   if (receiver)
451     {
452       /* First try a quick lookup assuming the dispatch table exists.  */
453       result = sarray_get_safe (receiver->class_pointer->dtable, 
454                                 (sidx)op->sel_id);
455       if (result == 0)
456         {
457           /* Not found ... call get_implementation () to install the dispatch
458              table and call +initialize as required, providing the method
459              implementation or a forwarding function */
460           result = get_implementation (receiver, receiver->class_pointer, op);
461         }
462       return result;
463     }
464   else
465     return (IMP)nil_method;
466 }
467
468 IMP
469 objc_msg_lookup_super (struct objc_super *super, SEL sel)
470 {
471   if (super->self)
472     return get_imp (super->super_class, sel);
473   else
474     return (IMP)nil_method;
475 }
476
477 /* Temporarily defined here until objc_msg_sendv() goes away.  */
478 char *method_get_first_argument (struct objc_method *,
479                                  arglist_t argframe, 
480                                  const char **type);
481 char *method_get_next_argument (arglist_t argframe, 
482                                 const char **type);
483 int method_get_sizeof_arguments (struct objc_method *);
484
485 struct objc_method *
486 class_get_instance_method (Class class, SEL op);
487
488 retval_t
489 objc_msg_sendv (id object, SEL op, arglist_t arg_frame)
490 {
491   struct objc_method *m = class_get_instance_method (object->class_pointer, op);
492   const char *type;
493   *((id *) method_get_first_argument (m, arg_frame, &type)) = object;
494   *((SEL *) method_get_next_argument (arg_frame, &type)) = op;
495   return __builtin_apply ((apply_t) m->method_imp, 
496                           arg_frame,
497                           method_get_sizeof_arguments (m));
498 }
499
500 void
501 __objc_init_dispatch_tables ()
502 {
503   __objc_uninstalled_dtable = sarray_new (200, 0);
504
505   /* TODO: It would be cool to register typed selectors here.  */
506   selector_resolveClassMethod = sel_registerName ("resolveClassMethod:");
507   selector_resolveInstanceMethod  =sel_registerName ("resolveInstanceMethod:");
508 }
509
510
511 /* Install dummy table for class which causes the first message to
512    that class (or instances hereof) to be initialized properly.  */
513 void
514 __objc_install_premature_dtable (Class class)
515 {
516   assert (__objc_uninstalled_dtable);
517   class->dtable = __objc_uninstalled_dtable;
518 }   
519
520 /* Send +initialize to class if not already done.  */
521 static void
522 __objc_send_initialize (Class class)
523 {
524   /* This *must* be a class object.  */
525   assert (CLS_ISCLASS (class));
526   assert (! CLS_ISMETA (class));
527
528   /* class_add_method_list/__objc_update_dispatch_table_for_class
529      may have reset the dispatch table.  The canonical way to insure
530      that we send +initialize just once, is this flag.  */
531   if (! CLS_ISINITIALIZED (class))
532     {
533       DEBUG_PRINTF ("+initialize: need to initialize class '%s'\n", class->name);
534       CLS_SETINITIALIZED (class);
535       CLS_SETINITIALIZED (class->class_pointer);
536
537       /* Create the garbage collector type memory description.  */
538       __objc_generate_gc_type_description (class);
539
540       if (class->super_class)
541         __objc_send_initialize (class->super_class);
542
543       {
544         SEL op = sel_registerName ("initialize");
545         IMP imp = 0;
546         struct objc_method_list * method_list = class->class_pointer->methods;
547         
548         while (method_list)
549           {
550             int i;
551             struct objc_method * method;
552             
553             for (i = 0; i < method_list->method_count; i++)
554               {
555                 method = &(method_list->method_list[i]);
556                 if (method->method_name
557                     && method->method_name->sel_id == op->sel_id)
558                   {
559                     imp = method->method_imp;
560                     break;
561                   }
562               }
563             
564             if (imp)
565               break;
566             
567             method_list = method_list->method_next;
568           }
569         if (imp)
570           {
571             DEBUG_PRINTF (" begin of [%s +initialize]\n", class->name);
572             (*imp) ((id) class, op);
573             DEBUG_PRINTF (" end of [%s +initialize]\n", class->name);
574           }
575 #ifdef DEBUG
576         else
577           {
578             DEBUG_PRINTF (" class '%s' has no +initialize method\n", class->name);          
579           }
580 #endif
581       }
582     }
583 }
584
585 /* Walk on the methods list of class and install the methods in the
586    reverse order of the lists.  Since methods added by categories are
587    before the methods of class in the methods list, this allows
588    categories to substitute methods declared in class.  However if
589    more than one category replaces the same method nothing is
590    guaranteed about what method will be used.  Assumes that
591    __objc_runtime_mutex is locked down.  */
592 static void
593 __objc_install_methods_in_dtable (struct sarray *dtable, struct objc_method_list * method_list)
594 {
595   int i;
596   
597   if (! method_list)
598     return;
599   
600   if (method_list->method_next)
601     __objc_install_methods_in_dtable (dtable, method_list->method_next);
602   
603   for (i = 0; i < method_list->method_count; i++)
604     {
605       struct objc_method * method = &(method_list->method_list[i]);
606       sarray_at_put_safe (dtable,
607                           (sidx) method->method_name->sel_id,
608                           method->method_imp);
609     }
610 }
611
612 void
613 __objc_update_dispatch_table_for_class (Class class)
614 {
615   Class next;
616   struct sarray *arr;
617
618   DEBUG_PRINTF (" _objc_update_dtable_for_class (%s)\n", class->name);
619
620   objc_mutex_lock (__objc_runtime_mutex);
621
622   /* not yet installed -- skip it unless in +initialize */
623   if (class->dtable == __objc_uninstalled_dtable) 
624     {
625       if (__objc_prepared_dtable_for_class (class))
626         {
627           /* There is a prepared table so we must be initialising this
628              class ... we must re-do the table preparation. */
629           __objc_prepare_dtable_for_class (class);
630         }
631       objc_mutex_unlock (__objc_runtime_mutex);
632       return;
633     }
634
635   arr = class->dtable;
636   __objc_install_premature_dtable (class); /* someone might require it... */
637   sarray_free (arr);                       /* release memory */
638   
639   /* Could have been lazy...  */
640   __objc_install_dtable_for_class (class); 
641
642   if (class->subclass_list)     /* Traverse subclasses.  */
643     for (next = class->subclass_list; next; next = next->sibling_class)
644       __objc_update_dispatch_table_for_class (next);
645
646   objc_mutex_unlock (__objc_runtime_mutex);
647 }
648
649 /* This function adds a method list to a class.  This function is
650    typically called by another function specific to the run-time.  As
651    such this function does not worry about thread safe issues.
652
653    This one is only called for categories. Class objects have their
654    methods installed right away, and their selectors are made into
655    SEL's by the function __objc_register_selectors_from_class.  */
656 void
657 class_add_method_list (Class class, struct objc_method_list * list)
658 {
659   /* Passing of a linked list is not allowed.  Do multiple calls.  */
660   assert (! list->method_next);
661
662   __objc_register_selectors_from_list(list);
663
664   /* Add the methods to the class's method list.  */
665   list->method_next = class->methods;
666   class->methods = list;
667
668   /* Update the dispatch table of class.  */
669   __objc_update_dispatch_table_for_class (class);
670 }
671
672 struct objc_method *
673 class_get_instance_method (Class class, SEL op)
674 {
675   return search_for_method_in_hierarchy (class, op);
676 }
677
678 struct objc_method *
679 class_get_class_method (MetaClass class, SEL op)
680 {
681   return search_for_method_in_hierarchy (class, op);
682 }
683
684 struct objc_method *
685 class_getInstanceMethod (Class class_, SEL selector)
686 {
687   struct objc_method *m;
688
689   if (class_ == Nil  ||  selector == NULL)
690     return NULL;
691
692   m = search_for_method_in_hierarchy (class_, selector);
693   if (m)
694     return m;
695
696   /* Try going through +resolveInstanceMethod:, and do the search
697      again if successful.  */
698   if (__objc_resolve_instance_method (class_, selector))
699     return search_for_method_in_hierarchy (class_, selector);
700
701   return NULL;
702 }
703
704 struct objc_method *
705 class_getClassMethod (Class class_, SEL selector)
706 {
707   struct objc_method *m;
708
709   if (class_ == Nil  ||  selector == NULL)
710     return NULL;
711   
712   m = search_for_method_in_hierarchy (class_->class_pointer, 
713                                       selector);
714   if (m)
715     return m;
716
717   /* Try going through +resolveClassMethod:, and do the search again
718      if successful.  */
719   if (__objc_resolve_class_method (class_, selector))
720     return search_for_method_in_hierarchy (class_->class_pointer, 
721                                            selector);    
722
723   return NULL;
724 }
725
726 BOOL
727 class_addMethod (Class class_, SEL selector, IMP implementation,
728                  const char *method_types)
729 {
730   struct objc_method_list *method_list;
731   struct objc_method *method;
732   const char *method_name;
733
734   if (class_ == Nil  ||  selector == NULL  ||  implementation == NULL  
735       || method_types == NULL  || (strcmp (method_types, "") == 0))
736     return NO;
737
738   method_name = sel_getName (selector);
739   if (method_name == NULL)
740     return NO;
741
742   /* If the method already exists in the class, return NO.  It is fine
743      if the method already exists in the superclass; in that case, we
744      are overriding it.  */
745   if (CLS_IS_IN_CONSTRUCTION (class_))
746     {
747       /* The class only contains a list of methods; they have not been
748          registered yet, ie, the method_name of each of them is still
749          a string, not a selector.  Iterate manually over them to
750          check if we have already added the method.  */
751       struct objc_method_list * method_list = class_->methods;
752       while (method_list)
753         {
754           int i;
755           
756           /* Search the method list.  */
757           for (i = 0; i < method_list->method_count; ++i)
758             {
759               struct objc_method * method = &method_list->method_list[i];
760               
761               if (method->method_name
762                   && strcmp ((char *)method->method_name, method_name) == 0)
763                 return NO;
764             }
765           
766           /* The method wasn't found.  Follow the link to the next list of
767              methods.  */
768           method_list = method_list->method_next;
769         }
770       /* The method wasn't found.  It's a new one.  Go ahead and add
771          it.  */
772     }
773   else
774     {
775       /* Do the standard lookup.  This assumes the selectors are
776          mapped.  */
777       if (search_for_method_in_list (class_->methods, selector))
778         return NO;
779     }
780
781   method_list = (struct objc_method_list *)objc_calloc (1, sizeof (struct objc_method_list));
782   method_list->method_count = 1;
783
784   method = &(method_list->method_list[0]);
785   method->method_name = objc_malloc (strlen (method_name) + 1);
786   strcpy ((char *)method->method_name, method_name);
787
788   method->method_types = objc_malloc (strlen (method_types) + 1);
789   strcpy ((char *)method->method_types, method_types);
790   
791   method->method_imp = implementation;
792   
793   if (CLS_IS_IN_CONSTRUCTION (class_))
794     {
795       /* We only need to add the method to the list.  It will be
796          registered with the runtime when the class pair is registered
797          (if ever).  */
798       method_list->method_next = class_->methods;
799       class_->methods = method_list;
800     }
801   else
802     {
803       /* Add the method to a live class.  */
804       objc_mutex_lock (__objc_runtime_mutex);
805       class_add_method_list (class_, method_list);
806       objc_mutex_unlock (__objc_runtime_mutex);
807     }
808
809   return YES;
810 }
811
812 IMP
813 class_replaceMethod (Class class_, SEL selector, IMP implementation,
814                      const char *method_types)
815 {
816   struct objc_method * method;
817
818   if (class_ == Nil  ||  selector == NULL  ||  implementation == NULL
819       || method_types == NULL)
820     return NULL;
821
822   method = search_for_method_in_hierarchy (class_, selector);
823
824   if (method)
825     {
826       return method_setImplementation (method, implementation);
827     }
828   else
829     {
830       class_addMethod (class_, selector, implementation, method_types);
831       return NULL;
832     }
833 }
834
835 /* Search for a method starting from the current class up its
836    hierarchy.  Return a pointer to the method's method structure if
837    found.  NULL otherwise.  */
838 static struct objc_method *
839 search_for_method_in_hierarchy (Class cls, SEL sel)
840 {
841   struct objc_method * method = NULL;
842   Class class;
843
844   if (! sel_is_mapped (sel))
845     return NULL;
846
847   /* Scan the method list of the class.  If the method isn't found in
848      the list then step to its super class.  */
849   for (class = cls; ((! method) && class); class = class->super_class)
850     method = search_for_method_in_list (class->methods, sel);
851
852   return method;
853 }
854
855
856
857 /* Given a linked list of method and a method's name.  Search for the
858    named method's method structure.  Return a pointer to the method's
859    method structure if found.  NULL otherwise.  */  
860 struct objc_method *
861 search_for_method_in_list (struct objc_method_list * list, SEL op)
862 {
863   struct objc_method_list * method_list = list;
864
865   if (! sel_is_mapped (op))
866     return NULL;
867
868   /* If not found then we'll search the list.  */
869   while (method_list)
870     {
871       int i;
872
873       /* Search the method list.  */
874       for (i = 0; i < method_list->method_count; ++i)
875         {
876           struct objc_method * method = &method_list->method_list[i];
877
878           if (method->method_name)
879             if (method->method_name->sel_id == op->sel_id)
880               return method;
881         }
882
883       /* The method wasn't found.  Follow the link to the next list of
884          methods.  */
885       method_list = method_list->method_next;
886     }
887
888   return NULL;
889 }
890
891 static retval_t __objc_forward (id object, SEL sel, arglist_t args);
892
893 /* Forwarding pointers/integers through the normal registers.  */
894 static id
895 __objc_word_forward (id rcv, SEL op, ...)
896 {
897   void *args, *res;
898
899   args = __builtin_apply_args ();
900   res = __objc_forward (rcv, op, args);
901   if (res)
902     __builtin_return (res);
903   else
904     return res;
905 }
906
907 /* Specific routine for forwarding floats/double because of
908    architectural differences on some processors.  i386s for example
909    which uses a floating point stack versus general registers for
910    floating point numbers.  This forward routine makes sure that GCC
911    restores the proper return values.  */
912 static double
913 __objc_double_forward (id rcv, SEL op, ...)
914 {
915   void *args, *res;
916
917   args = __builtin_apply_args ();
918   res = __objc_forward (rcv, op, args);
919   __builtin_return (res);
920 }
921
922 #if INVISIBLE_STRUCT_RETURN
923 static __big
924 #else
925 static id
926 #endif
927 __objc_block_forward (id rcv, SEL op, ...)
928 {
929   void *args, *res;
930
931   args = __builtin_apply_args ();
932   res = __objc_forward (rcv, op, args);
933   if (res)
934     __builtin_return (res);
935   else
936 #if INVISIBLE_STRUCT_RETURN
937     return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}};
938 #else
939     return nil;
940 #endif
941 }
942
943
944 /* This function is installed in the dispatch table for all methods
945    which are not implemented.  Thus, it is called when a selector is
946    not recognized.  */
947 static retval_t
948 __objc_forward (id object, SEL sel, arglist_t args)
949 {
950   IMP imp;
951   static SEL frwd_sel = 0;                      /* !T:SAFE2 */
952   SEL err_sel;
953
954   /* First try if the object understands forward::.  */
955   if (! frwd_sel)
956     frwd_sel = sel_get_any_uid ("forward::");
957
958   if (__objc_responds_to (object, frwd_sel))
959     {
960       imp = get_implementation (object, object->class_pointer, frwd_sel);
961       return (*imp) (object, frwd_sel, sel, args);
962     }
963
964   /* If the object recognizes the doesNotRecognize: method then we're
965      going to send it.  */
966   err_sel = sel_get_any_uid ("doesNotRecognize:");
967   if (__objc_responds_to (object, err_sel))
968     {
969       imp = get_implementation (object, object->class_pointer, err_sel);
970       return (*imp) (object, err_sel, sel);
971     }
972   
973   /* The object doesn't recognize the method.  Check for responding to
974      error:.  If it does then sent it.  */
975   {
976     char msg[256 + strlen ((const char *) sel_getName (sel))
977              + strlen ((const char *) object->class_pointer->name)];
978
979     sprintf (msg, "(%s) %s does not recognize %s",
980              (CLS_ISMETA (object->class_pointer)
981               ? "class"
982               : "instance" ),
983              object->class_pointer->name, sel_getName (sel));
984
985     /* TODO: support for error: is surely deprecated ? */
986     err_sel = sel_get_any_uid ("error:");
987     if (__objc_responds_to (object, err_sel))
988       {
989         imp = get_implementation (object, object->class_pointer, err_sel);
990         return (*imp) (object, sel_get_any_uid ("error:"), msg);
991       }
992
993     /* The object doesn't respond to doesNotRecognize: or error:;
994        Therefore, a default action is taken.  */
995     _objc_abort ("%s\n", msg);
996
997     return 0;
998   }
999 }
1000
1001 void
1002 __objc_print_dtable_stats (void)
1003 {
1004   int total = 0;
1005
1006   objc_mutex_lock (__objc_runtime_mutex);
1007
1008 #ifdef OBJC_SPARSE2
1009   printf ("memory usage: (%s)\n", "2-level sparse arrays");
1010 #else
1011   printf ("memory usage: (%s)\n", "3-level sparse arrays");
1012 #endif
1013
1014   printf ("arrays: %d = %ld bytes\n", narrays, 
1015           (long) ((size_t) narrays * sizeof (struct sarray)));
1016   total += narrays * sizeof (struct sarray);
1017   printf ("buckets: %d = %ld bytes\n", nbuckets, 
1018           (long) ((size_t) nbuckets * sizeof (struct sbucket)));
1019   total += nbuckets * sizeof (struct sbucket);
1020
1021   printf ("idxtables: %d = %ld bytes\n",
1022           idxsize, (long) ((size_t) idxsize * sizeof (void *)));
1023   total += idxsize * sizeof (void *);
1024   printf ("-----------------------------------\n");
1025   printf ("total: %d bytes\n", total);
1026   printf ("===================================\n");
1027
1028   objc_mutex_unlock (__objc_runtime_mutex);
1029 }
1030
1031 /* Returns the uninstalled dispatch table indicator.  If a class'
1032    dispatch table points to __objc_uninstalled_dtable then that means
1033    it needs its dispatch table to be installed.  */
1034 struct sarray *
1035 objc_get_uninstalled_dtable (void)
1036 {
1037   return __objc_uninstalled_dtable;
1038 }
1039
1040 static cache_ptr prepared_dtable_table = 0;
1041
1042 /* This function is called by:
1043    objc_msg_lookup, get_imp and __objc_responds_to
1044    (and the dispatch table installation functions themselves)
1045    to install a dispatch table for a class.
1046
1047    If CLS is a class, it installs instance methods.
1048    If CLS is a meta class, it installs class methods.
1049
1050    In either case +initialize is invoked for the corresponding class.
1051
1052    The implementation must insure that the dispatch table is not
1053    installed until +initialize completes.  Otherwise it opens a
1054    potential race since the installation of the dispatch table is
1055    used as gate in regular method dispatch and we need to guarantee
1056    that +initialize is the first method invoked an that no other
1057    thread my dispatch messages to the class before +initialize
1058    completes.
1059  */
1060 static void
1061 __objc_install_dtable_for_class (Class cls)
1062 {
1063   /* If the class has not yet had its class links resolved, we must 
1064      re-compute all class links */
1065   if (! CLS_ISRESOLV (cls))
1066     __objc_resolve_class_links ();
1067
1068   /* Make sure the super class has its dispatch table installed
1069      or is at least preparing.
1070      We do not need to send initialize for the super class since
1071      __objc_send_initialize will insure that.
1072    */
1073   if (cls->super_class
1074     && cls->super_class->dtable == __objc_uninstalled_dtable
1075     && !__objc_prepared_dtable_for_class (cls->super_class))
1076     {
1077       __objc_install_dtable_for_class (cls->super_class);
1078       /* The superclass initialisation may have also initialised the
1079          current class, in which case there is no more to do. */
1080       if (cls->dtable != __objc_uninstalled_dtable)
1081         {
1082           return;
1083         }
1084     }
1085
1086   /* We have already been prepared but +initialize hasn't completed.
1087      The +initialize implementation is probably sending 'self' messages.
1088      We rely on _objc_get_prepared_imp to retrieve the implementation
1089      pointers.  */
1090   if (__objc_prepared_dtable_for_class (cls))
1091     {
1092       return;
1093     }
1094
1095   /* We have this function cache the implementation pointers
1096      for _objc_get_prepared_imp but the dispatch table won't
1097      be initilized until __objc_send_initialize completes.  */
1098   __objc_prepare_dtable_for_class (cls);
1099
1100   /* We may have already invoked +initialize but 
1101      __objc_update_dispatch_table_for_class  invoked by
1102      class_add_method_list may have reset dispatch table.  */
1103
1104   /* Call +initialize.
1105      If we are a real class, we are installing instance methods.
1106      If we are a meta class, we are installing class methods.
1107      The __objc_send_initialize itself will insure that the message
1108      is called only once per class.  */
1109   if (CLS_ISCLASS (cls))
1110     __objc_send_initialize (cls);
1111   else
1112     {
1113       /* Retreive the class from the meta class.  */
1114       Class c = objc_getClass (cls->name);
1115       assert (CLS_ISMETA (cls));
1116       assert (c);
1117       __objc_send_initialize (c);
1118     }
1119
1120   /* We install the dispatch table correctly when +initialize completed.  */
1121   __objc_install_prepared_dtable_for_class (cls);
1122 }
1123
1124 /* Builds the dispatch table for the class CLS and stores
1125    it in a place where it can be retrieved by
1126    __objc_get_prepared_imp until __objc_install_prepared_dtable_for_class
1127    installs it into the class.
1128    The dispatch table should not be installed into the class until
1129    +initialize has completed.  */
1130 static void
1131 __objc_prepare_dtable_for_class (Class cls)
1132 {
1133   struct sarray *dtable;
1134   struct sarray *super_dtable;
1135
1136   /* This table could be initialized in init.c. 
1137      We can not use the class name since
1138      the class maintains the instance methods and
1139      the meta class maintains the the class methods yet
1140      both share the same name.  
1141      Classes should be unique in any program.  */
1142   if (! prepared_dtable_table)
1143     prepared_dtable_table 
1144       = objc_hash_new(32,
1145                       (hash_func_type) objc_hash_ptr,
1146                       (compare_func_type) objc_compare_ptrs);
1147
1148   /* If the class has not yet had its class links resolved, we must 
1149      re-compute all class links */
1150   if (! CLS_ISRESOLV (cls))
1151     __objc_resolve_class_links ();
1152
1153   assert (cls);
1154   assert (cls->dtable == __objc_uninstalled_dtable);
1155
1156   /* If there is already a prepared dtable for this class, we must replace
1157      it with a new version (since there must have been methods added to or
1158      otherwise modified in the class while executing +initialize, and the
1159      table needs to be recomputed.  */
1160   dtable = __objc_prepared_dtable_for_class (cls);
1161   if (0 != dtable)
1162     {
1163       objc_hash_remove (prepared_dtable_table, cls);
1164       sarray_free (dtable);
1165     }
1166
1167   /* Now prepare the dtable for population.  */
1168   assert (cls != cls->super_class);
1169   if (cls->super_class)
1170     {
1171       /* Inherit the method list from the super class.
1172          Yet the super class may still be initializing
1173          in the case when a class cluster sub class initializes
1174          its super classes.  */
1175       if (cls->super_class->dtable == __objc_uninstalled_dtable)
1176         __objc_install_dtable_for_class (cls->super_class);
1177
1178       super_dtable = cls->super_class->dtable;
1179       /* If the dispatch table is not yet installed,
1180          we are still in the process of executing +initialize.
1181          Yet the dispatch table should be available.  */
1182       if (super_dtable == __objc_uninstalled_dtable)
1183         super_dtable = __objc_prepared_dtable_for_class (cls->super_class);
1184
1185       assert (super_dtable);
1186       dtable = sarray_lazy_copy (super_dtable);
1187     }
1188   else
1189     dtable = sarray_new (__objc_selector_max_index, 0);
1190
1191   __objc_install_methods_in_dtable (dtable, cls->methods);
1192
1193   objc_hash_add (&prepared_dtable_table,
1194                  cls,
1195                  dtable);
1196 }
1197
1198 /* This wrapper only exists to allow an easy replacement of
1199    the lookup implementation and it is expected that the compiler
1200    will optimize it away.  */
1201 static struct sarray *
1202 __objc_prepared_dtable_for_class (Class cls)
1203 {
1204   struct sarray *dtable = 0;
1205   assert (cls);
1206   if (prepared_dtable_table)
1207     dtable = objc_hash_value_for_key (prepared_dtable_table, cls);
1208   /* dtable my be nil, 
1209      since we call this to check whether we are currently preparing
1210      before we start preparing.  */
1211   return dtable;
1212 }
1213
1214 /* Helper function for messages sent to CLS or implementation pointers
1215    retrieved from CLS during +initialize before the dtable is installed.
1216    When a class implicitly initializes another class which in turn
1217    implicitly invokes methods in this class, before the implementation of
1218    +initialize of CLS completes, this returns the expected implementation.
1219    Forwarding remains the responsibility of objc_msg_lookup.
1220    This function should only be called under the global lock.
1221  */
1222 static IMP
1223 __objc_get_prepared_imp (Class cls,SEL sel)
1224 {
1225   struct sarray *dtable;
1226   IMP imp;
1227
1228   assert (cls);
1229   assert (sel);
1230   assert (cls->dtable == __objc_uninstalled_dtable);
1231   dtable = __objc_prepared_dtable_for_class (cls);
1232
1233   assert (dtable);
1234   assert (dtable != __objc_uninstalled_dtable);
1235   imp = sarray_get_safe (dtable, (size_t) sel->sel_id);
1236
1237   /* imp may be Nil if the method does not exist and we
1238      may fallback to the forwarding implementation later.  */
1239   return imp;  
1240 }
1241
1242 /* When this function is called +initialize should be completed.
1243    So now we are safe to install the dispatch table for the
1244    class so that they become available for other threads
1245    that may be waiting in the lock.
1246  */
1247 static void
1248 __objc_install_prepared_dtable_for_class (Class cls)
1249 {
1250   assert (cls);
1251   assert (cls->dtable == __objc_uninstalled_dtable);
1252   cls->dtable = __objc_prepared_dtable_for_class (cls);
1253
1254   assert (cls->dtable);
1255   assert (cls->dtable != __objc_uninstalled_dtable);
1256   objc_hash_remove (prepared_dtable_table, cls);
1257 }