OSDN Git Service

PR middle-end/44563
[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
27 /* FIXME: This file has no business including tm.h.  */
28 /* FIXME: This should be using libffi instead of __builtin_apply
29    and friends.  */
30
31 #include "objc-private/common.h"
32 #include "objc-private/error.h"
33 #include "tconfig.h"
34 #include "coretypes.h"
35 #include "tm.h"
36 #include "objc/runtime.h"
37 #include "objc/thr.h"
38 #include "objc-private/module-abi-8.h"
39 #include "objc-private/runtime.h"
40 #include "objc-private/sarray.h"
41 #include "objc-private/selector.h" /* For sel_is_mapped() */
42 #include "runtime-info.h"
43 #include <assert.h> /* For assert */
44 #include <string.h> /* For strlen */
45
46 /* Temporarily while we include objc/objc-api.h instead of objc-private/module-abi-8.h.  */
47 #define _CLS_IN_CONSTRUCTION 0x10L
48 #define CLS_IS_IN_CONSTRUCTION(cls) __CLS_ISINFO(cls, _CLS_IN_CONSTRUCTION)
49
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.  */
55 #undef rtx
56 #define rtx int
57
58 #if ! defined (STRUCT_VALUE) || STRUCT_VALUE == 0
59 #define INVISIBLE_STRUCT_RETURN 1
60 #else
61 #define INVISIBLE_STRUCT_RETURN 0
62 #endif
63
64 /* The uninstalled dispatch table.  */
65 struct sarray *__objc_uninstalled_dtable = 0;   /* !T:MUTEX */
66
67 /* Two hooks for method forwarding. If either is set, it is invoked to
68  * return a function that performs the real forwarding.  If both are
69  * set, the result of __objc_msg_forward2 will be preferred over that
70  * of __objc_msg_forward.  If both return NULL or are unset, the
71  * libgcc based functions (__builtin_apply and friends) are used.  */
72 IMP (*__objc_msg_forward) (SEL) = NULL;
73 IMP (*__objc_msg_forward2) (id, SEL) = NULL;
74
75 /* Send +initialize to class.  */
76 static void __objc_send_initialize (Class);
77
78 static void __objc_install_dispatch_table_for_class (Class);
79
80 /* Forward declare some functions.  */
81 static void __objc_init_install_dtable (id, SEL);
82
83 /* Various forwarding functions that are used based upon the
84    return type for the selector.
85    __objc_block_forward for structures.
86    __objc_double_forward for floats/doubles.
87    __objc_word_forward for pointers or types that fit in registers.  */
88 static double __objc_double_forward (id, SEL, ...);
89 static id __objc_word_forward (id, SEL, ...);
90 typedef struct { id many[8]; } __big;
91 #if INVISIBLE_STRUCT_RETURN 
92 static __big 
93 #else
94 static id
95 #endif
96 __objc_block_forward (id, SEL, ...);
97 static struct objc_method * search_for_method_in_hierarchy (Class class, SEL sel);
98 struct objc_method * search_for_method_in_list (struct objc_method_list * list, SEL op);
99 id nil_method (id, SEL);
100
101 /* Given a selector, return the proper forwarding implementation.  */
102 inline
103 IMP
104 __objc_get_forward_imp (id rcv, SEL sel)
105 {
106   /* If a custom forwarding hook was registered, try getting a
107      forwarding function from it. There are two forward routine hooks,
108      one that takes the receiver as an argument and one that does
109      not.  */
110   if (__objc_msg_forward2)
111     {
112       IMP result;
113       if ((result = __objc_msg_forward2 (rcv, sel)) != NULL)
114        return result;
115     }
116   if (__objc_msg_forward)
117     {
118       IMP result;
119       if ((result = __objc_msg_forward (sel)) != NULL) 
120         return result;
121     }
122
123   /* In all other cases, use the default forwarding functions built
124      using __builtin_apply and friends.  */
125     {
126       const char *t = sel->sel_types;
127       
128       if (t && (*t == '[' || *t == '(' || *t == '{')
129 #ifdef OBJC_MAX_STRUCT_BY_VALUE
130           && objc_sizeof_type (t) > OBJC_MAX_STRUCT_BY_VALUE
131 #endif
132           )
133         return (IMP)__objc_block_forward;
134       else if (t && (*t == 'f' || *t == 'd'))
135         return (IMP)__objc_double_forward;
136       else
137         return (IMP)__objc_word_forward;
138     }
139 }
140
141 /* Selectors for +resolveClassMethod: and +resolveInstanceMethod:.
142    These are set up at startup.  */
143 static SEL selector_resolveClassMethod = NULL;
144 static SEL selector_resolveInstanceMethod = NULL;
145
146 /* Internal routines use to resolve a class method using
147    +resolveClassMethod:.  'class' is always a non-Nil class (*not* a
148    meta-class), and 'sel' is the selector that we are trying to
149    resolve.  This must be called when class is not Nil, and the
150    dispatch table for class methods has already been installed.
151
152    This routine tries to call +resolveClassMethod: to give an
153    opportunity to resolve the method.  If +resolveClassMethod: returns
154    YES, it tries looking up the method again, and if found, it returns
155    it.  Else, it returns NULL.  */
156 static inline
157 IMP
158 __objc_resolve_class_method (Class class, SEL sel)
159 {
160   /* We need to lookup +resolveClassMethod:.  */
161   BOOL (*resolveMethodIMP) (id, SEL, SEL);
162
163   /* The dispatch table for class methods is already installed and we
164      don't want any forwarding to happen when looking up this method,
165      so we just look it up directly.  Note that if 'sel' is precisely
166      +resolveClassMethod:, this would look it up yet again and find
167      nothing.  That's no problem and there's no recursion.  */
168   resolveMethodIMP = (BOOL (*) (id, SEL, SEL))sarray_get_safe
169     (class->class_pointer->dtable, (size_t) selector_resolveClassMethod->sel_id);
170
171   if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveClassMethod, sel))
172     {
173       /* +resolveClassMethod: returned YES.  Look the method up again.
174          We already know the dtable is installed.  */
175       
176       /* TODO: There is the case where +resolveClassMethod: is buggy
177          and returned YES without actually adding the method.  We
178          could maybe print an error message.  */
179       return sarray_get_safe (class->class_pointer->dtable, (size_t) sel->sel_id);
180     }
181
182   return NULL;
183 }
184
185 /* Internal routines use to resolve a instance method using
186    +resolveInstanceMethod:.  'class' is always a non-Nil class, and
187    'sel' is the selector that we are trying to resolve.  This must be
188    called when class is not Nil, and the dispatch table for instance
189    methods has already been installed.
190
191    This routine tries to call +resolveInstanceMethod: to give an
192    opportunity to resolve the method.  If +resolveInstanceMethod:
193    returns YES, it tries looking up the method again, and if found, it
194    returns it.  Else, it returns NULL.  */
195 static inline
196 IMP
197 __objc_resolve_instance_method (Class class, SEL sel)
198 {
199   /* We need to lookup +resolveInstanceMethod:.  */
200   BOOL (*resolveMethodIMP) (id, SEL, SEL);
201
202   /* The dispatch table for class methods may not be already installed
203      so we have to install it if needed.  */
204   resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable,
205                                       (size_t) selector_resolveInstanceMethod->sel_id);
206   if (resolveMethodIMP == 0)
207     {
208       /* Try again after installing the dtable.  */
209       if (class->class_pointer->dtable == __objc_uninstalled_dtable)
210         {
211           objc_mutex_lock (__objc_runtime_mutex);
212           if (class->class_pointer->dtable == __objc_uninstalled_dtable)
213             __objc_install_dispatch_table_for_class (class->class_pointer);
214           objc_mutex_unlock (__objc_runtime_mutex);
215         }
216       resolveMethodIMP = sarray_get_safe (class->class_pointer->dtable,
217                                           (size_t) selector_resolveInstanceMethod->sel_id);           
218     }
219
220   if (resolveMethodIMP && resolveMethodIMP ((id)class, selector_resolveInstanceMethod, sel))
221     {
222       /* +resolveInstanceMethod: returned YES.  Look the method up
223          again.  We already know the dtable is installed.  */
224       
225       /* TODO: There is the case where +resolveInstanceMethod: is
226          buggy and returned YES without actually adding the method.
227          We could maybe print an error message.  */
228       return sarray_get_safe (class->dtable, (size_t) sel->sel_id);     
229     }
230
231   return NULL;
232 }
233
234 /* Temporary definition until we include objc/runtime.h.  */
235 objc_EXPORT Class objc_lookupClass (const char *name);
236
237 /* Given a class and selector, return the selector's
238    implementation.  */
239 inline
240 IMP
241 get_imp (Class class, SEL sel)
242 {
243   /* In a vanilla implementation we would first check if the dispatch
244      table is installed.  Here instead, to get more speed in the
245      standard case (that the dispatch table is installed) we first try
246      to get the imp using brute force.  Only if that fails, we do what
247      we should have been doing from the very beginning, that is, check
248      if the dispatch table needs to be installed, install it if it's
249      not installed, and retrieve the imp from the table if it's
250      installed.  */
251   void *res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
252   if (res == 0)
253     {
254       /* Not a valid method.  */
255       if (class->dtable == __objc_uninstalled_dtable)
256         {
257           /* The dispatch table needs to be installed.  */
258           objc_mutex_lock (__objc_runtime_mutex);
259
260            /* Double-checked locking pattern: Check
261               __objc_uninstalled_dtable again in case another thread
262               installed the dtable while we were waiting for the lock
263               to be released.  */
264          if (class->dtable == __objc_uninstalled_dtable)
265            {
266              __objc_install_dispatch_table_for_class (class);
267            }
268
269           objc_mutex_unlock (__objc_runtime_mutex);
270           /* Call ourselves with the installed dispatch table and get
271              the real method.  */
272           res = get_imp (class, sel);
273         }
274       else
275         {
276           /* The dispatch table has been installed.  */
277
278          /* Get the method from the dispatch table (we try to get it
279             again in case another thread has installed the dtable just
280             after we invoked sarray_get_safe, but before we checked
281             class->dtable == __objc_uninstalled_dtable).  */
282           res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
283           if (res == 0)
284             {
285               /* The dispatch table has been installed, and the method
286                  is not in the dispatch table.  So the method just
287                  doesn't exist for the class.  */
288
289               /* Try going through the +resolveClassMethod: or
290                  +resolveInstanceMethod: process.  */
291               if (CLS_ISMETA (class))
292                 {
293                   /* We have the meta class, but we need to invoke the
294                      +resolveClassMethod: method on the class.  So, we
295                      need to obtain the class from the meta class,
296                      which we do using the fact that both the class
297                      and the meta-class have the same name.  */
298                   Class realClass = objc_lookupClass (class->name);
299                   if (realClass)
300                     res = __objc_resolve_class_method (realClass, sel);
301                 }
302               else
303                 res = __objc_resolve_instance_method (class, sel);
304
305               if (res == 0)
306                 {
307                   /* If that fails, then return the forwarding
308                      implementation.  We don't know the receiver (only
309                      its class), so we have to pass 'nil' as the first
310                      argument.  Passing the class as first argument is
311                      wrong because the class is not the receiver; it
312                      can result in us calling a class method when we
313                      want an instance method of the same name.  */
314                   res = __objc_get_forward_imp (nil, sel);
315                 }
316             }
317         }
318     }
319   return res;
320 }
321
322 /* The new name of get_imp().  */
323 IMP
324 class_getMethodImplementation (Class class_, SEL selector)
325 {
326   if (class_ == Nil  ||  selector == NULL)
327     return NULL;
328
329   /* get_imp is inlined, so we're good.  */
330   return get_imp (class_, selector);
331 }
332
333 /* Given a method, return its implementation.  */
334 IMP
335 method_get_imp (struct objc_method * method)
336 {
337   return (method != (struct objc_method *)0) ? method->method_imp : (IMP)0;
338 }
339
340 /* Query if an object can respond to a selector, returns YES if the
341    object implements the selector otherwise NO.  Does not check if the
342    method can be forwarded.  */
343 inline
344 BOOL
345 __objc_responds_to (id object, SEL sel)
346 {
347   void *res;
348
349   /* Install dispatch table if need be.  */
350   if (object->class_pointer->dtable == __objc_uninstalled_dtable)
351     {
352       objc_mutex_lock (__objc_runtime_mutex);
353       if (object->class_pointer->dtable == __objc_uninstalled_dtable)
354         {
355           __objc_install_dispatch_table_for_class (object->class_pointer);
356         }
357       objc_mutex_unlock (__objc_runtime_mutex);
358     }
359
360   /* Get the method from the dispatch table.  */
361   res = sarray_get_safe (object->class_pointer->dtable, (size_t) sel->sel_id);
362   return (res != 0);
363 }
364
365 BOOL
366 class_respondsToSelector (Class class_, SEL selector)
367 {
368   void *res;
369
370   if (class_ == Nil  ||  selector == NULL)
371     return NO;
372
373   /* Install dispatch table if need be.  */
374   if (class_->dtable == __objc_uninstalled_dtable)
375     {
376       objc_mutex_lock (__objc_runtime_mutex);
377       if (class_->dtable == __objc_uninstalled_dtable)
378         {
379           __objc_install_dispatch_table_for_class (class_);
380         }
381       objc_mutex_unlock (__objc_runtime_mutex);
382     }
383
384   /* Get the method from the dispatch table.  */
385   res = sarray_get_safe (class_->dtable, (size_t) selector->sel_id);
386   return (res != 0);
387 }
388
389 /* This is the lookup function.  All entries in the table are either a
390    valid method *or* zero.  If zero then either the dispatch table
391    needs to be installed or it doesn't exist and forwarding is
392    attempted.  */
393 IMP
394 objc_msg_lookup (id receiver, SEL op)
395 {
396   IMP result;
397   if (receiver)
398     {
399       result = sarray_get_safe (receiver->class_pointer->dtable, 
400                                 (sidx)op->sel_id);
401       if (result == 0)
402         {
403           /* Not a valid method.  */
404           if (receiver->class_pointer->dtable == __objc_uninstalled_dtable)
405             {
406               /* The dispatch table needs to be installed.  This
407                  happens on the very first method call to the
408                  class.  */
409               __objc_init_install_dtable (receiver, op);
410
411               /* Get real method for this in newly installed
412                  dtable.  */
413               result = get_imp (receiver->class_pointer, op);
414             }
415           else
416             {
417               /* The dispatch table has been installed.  Check again
418                  if the method exists (just in case the dispatch table
419                  has been installed by another thread after we did the
420                  previous check that the method exists).  */
421               result = sarray_get_safe (receiver->class_pointer->dtable,
422                                         (sidx)op->sel_id);
423               if (result == 0)
424                 {
425                   /* Try going through the +resolveClassMethod: or
426                      +resolveInstanceMethod: process.  */
427                   if (CLS_ISMETA (receiver->class_pointer))
428                     result = __objc_resolve_class_method ((Class)receiver, op);
429                   else
430                     result = __objc_resolve_instance_method (receiver->class_pointer,
431                                                              op);
432
433                   if (result == 0)
434                     {
435                       /* If the method still just doesn't exist for
436                          the class, attempt to forward the method.  */
437                       result = __objc_get_forward_imp (receiver, op);
438                     }
439                 }
440             }
441         }
442       return result;
443     }
444   else
445     return (IMP)nil_method;
446 }
447
448 IMP
449 objc_msg_lookup_super (struct objc_super *super, SEL sel)
450 {
451   if (super->self)
452     return get_imp (super->super_class, sel);
453   else
454     return (IMP)nil_method;
455 }
456
457 /* Temporarily defined here until objc_msg_sendv() goes away.  */
458 char *method_get_first_argument (struct objc_method *,
459                                  arglist_t argframe, 
460                                  const char **type);
461 char *method_get_next_argument (arglist_t argframe, 
462                                 const char **type);
463 int method_get_sizeof_arguments (struct objc_method *);
464
465 struct objc_method *
466 class_get_instance_method (Class class, SEL op);
467
468 retval_t
469 objc_msg_sendv (id object, SEL op, arglist_t arg_frame)
470 {
471   struct objc_method *m = class_get_instance_method (object->class_pointer, op);
472   const char *type;
473   *((id *) method_get_first_argument (m, arg_frame, &type)) = object;
474   *((SEL *) method_get_next_argument (arg_frame, &type)) = op;
475   return __builtin_apply ((apply_t) m->method_imp, 
476                           arg_frame,
477                           method_get_sizeof_arguments (m));
478 }
479
480 void
481 __objc_init_dispatch_tables ()
482 {
483   __objc_uninstalled_dtable = sarray_new (200, 0);
484
485   /* TODO: It would be cool to register typed selectors here.  */
486   selector_resolveClassMethod = sel_registerName ("resolveClassMethod:");
487   selector_resolveInstanceMethod  =sel_registerName ("resolveInstanceMethod:");
488 }
489
490 /* This function is called by objc_msg_lookup when the dispatch table
491    needs to be installed; thus it is called once for each class,
492    namely when the very first message is sent to it.  */
493 static void
494 __objc_init_install_dtable (id receiver, SEL op __attribute__ ((__unused__)))
495 {
496   objc_mutex_lock (__objc_runtime_mutex);
497   
498   /* This may happen, if the programmer has taken the address of a
499      method before the dtable was initialized... too bad for him!  */
500   if (receiver->class_pointer->dtable != __objc_uninstalled_dtable)
501     {
502       objc_mutex_unlock (__objc_runtime_mutex);
503       return;
504     }
505   
506   if (CLS_ISCLASS (receiver->class_pointer))
507     {
508       /* receiver is an ordinary object.  */
509       assert (CLS_ISCLASS (receiver->class_pointer));
510
511       /* Install instance methods table.  */
512       __objc_install_dispatch_table_for_class (receiver->class_pointer);
513
514       /* Call +initialize -- this will in turn install the factory
515          dispatch table if not already done. :-)  */
516       __objc_send_initialize (receiver->class_pointer);
517     }
518   else
519     {
520       /* receiver is a class object.  */
521       assert (CLS_ISCLASS ((Class)receiver));
522       assert (CLS_ISMETA (receiver->class_pointer));
523
524       /* Install real dtable for factory methods.  */
525       __objc_install_dispatch_table_for_class (receiver->class_pointer);
526
527       __objc_send_initialize ((Class)receiver);
528     }
529   objc_mutex_unlock (__objc_runtime_mutex);
530 }
531
532 /* Install dummy table for class which causes the first message to
533    that class (or instances hereof) to be initialized properly.  */
534 void
535 __objc_install_premature_dtable (Class class)
536 {
537   assert (__objc_uninstalled_dtable);
538   class->dtable = __objc_uninstalled_dtable;
539 }   
540
541 /* Send +initialize to class if not already done.  */
542 static void
543 __objc_send_initialize (Class class)
544 {
545   /* This *must* be a class object.  */
546   assert (CLS_ISCLASS (class));
547   assert (! CLS_ISMETA (class));
548
549   if (! CLS_ISINITIALIZED (class))
550     {
551       CLS_SETINITIALIZED (class);
552       CLS_SETINITIALIZED (class->class_pointer);
553
554       /* Create the garbage collector type memory description.  */
555       __objc_generate_gc_type_description (class);
556
557       if (class->super_class)
558         __objc_send_initialize (class->super_class);
559
560       {
561         SEL op = sel_registerName ("initialize");
562         IMP imp = 0;
563         struct objc_method_list * method_list = class->class_pointer->methods;
564         
565         while (method_list)
566           {
567             int i;
568             struct objc_method * method;
569             
570             for (i = 0; i < method_list->method_count; i++)
571               {
572                 method = &(method_list->method_list[i]);
573                 if (method->method_name
574                     && method->method_name->sel_id == op->sel_id)
575                   {
576                     imp = method->method_imp;
577                     break;
578                   }
579               }
580             
581             if (imp)
582               break;
583             
584             method_list = method_list->method_next;
585           }
586         if (imp)
587           (*imp) ((id) class, op);
588       }
589     }
590 }
591
592 /* Walk on the methods list of class and install the methods in the
593    reverse order of the lists.  Since methods added by categories are
594    before the methods of class in the methods list, this allows
595    categories to substitute methods declared in class.  However if
596    more than one category replaces the same method nothing is
597    guaranteed about what method will be used.  Assumes that
598    __objc_runtime_mutex is locked down.  */
599 static void
600 __objc_install_methods_in_dtable (Class class, struct objc_method_list * method_list)
601 {
602   int i;
603   
604   if (! method_list)
605     return;
606   
607   if (method_list->method_next)
608     __objc_install_methods_in_dtable (class, method_list->method_next);
609   
610   for (i = 0; i < method_list->method_count; i++)
611     {
612       struct objc_method * method = &(method_list->method_list[i]);
613       sarray_at_put_safe (class->dtable,
614                           (sidx) method->method_name->sel_id,
615                           method->method_imp);
616     }
617 }
618
619 /* Assumes that __objc_runtime_mutex is locked down.  */
620 static void
621 __objc_install_dispatch_table_for_class (Class class)
622 {
623   Class super;
624
625   /* If the class has not yet had its class links resolved, we must
626      re-compute all class links.  */
627   if (! CLS_ISRESOLV (class))
628     __objc_resolve_class_links ();
629   
630   super = class->super_class;
631
632   if (super != 0 && (super->dtable == __objc_uninstalled_dtable))
633     __objc_install_dispatch_table_for_class (super);
634
635   /* Allocate dtable if necessary.  */
636   if (super == 0)
637     {
638       objc_mutex_lock (__objc_runtime_mutex);
639       class->dtable = sarray_new (__objc_selector_max_index, 0);
640       objc_mutex_unlock (__objc_runtime_mutex);
641     }
642   else
643     class->dtable = sarray_lazy_copy (super->dtable);
644
645   __objc_install_methods_in_dtable (class, class->methods);
646 }
647
648 void
649 __objc_update_dispatch_table_for_class (Class class)
650 {
651   Class next;
652   struct sarray *arr;
653
654   /* Not yet installed -- skip it.  */
655   if (class->dtable == __objc_uninstalled_dtable) 
656     return;
657
658   objc_mutex_lock (__objc_runtime_mutex);
659
660   arr = class->dtable;
661   __objc_install_premature_dtable (class); /* someone might require it... */
662   sarray_free (arr);                       /* release memory */
663   
664   /* Could have been lazy...  */
665   __objc_install_dispatch_table_for_class (class); 
666
667   if (class->subclass_list)     /* Traverse subclasses.  */
668     for (next = class->subclass_list; next; next = next->sibling_class)
669       __objc_update_dispatch_table_for_class (next);
670
671   objc_mutex_unlock (__objc_runtime_mutex);
672 }
673
674 /* This function adds a method list to a class.  This function is
675    typically called by another function specific to the run-time.  As
676    such this function does not worry about thread safe issues.
677
678    This one is only called for categories. Class objects have their
679    methods installed right away, and their selectors are made into
680    SEL's by the function __objc_register_selectors_from_class.  */
681 void
682 class_add_method_list (Class class, struct objc_method_list * list)
683 {
684   /* Passing of a linked list is not allowed.  Do multiple calls.  */
685   assert (! list->method_next);
686
687   __objc_register_selectors_from_list(list);
688
689   /* Add the methods to the class's method list.  */
690   list->method_next = class->methods;
691   class->methods = list;
692
693   /* Update the dispatch table of class.  */
694   __objc_update_dispatch_table_for_class (class);
695 }
696
697 struct objc_method *
698 class_get_instance_method (Class class, SEL op)
699 {
700   return search_for_method_in_hierarchy (class, op);
701 }
702
703 struct objc_method *
704 class_get_class_method (MetaClass class, SEL op)
705 {
706   return search_for_method_in_hierarchy (class, op);
707 }
708
709 struct objc_method *
710 class_getInstanceMethod (Class class_, SEL selector)
711 {
712   struct objc_method *m;
713
714   if (class_ == Nil  ||  selector == NULL)
715     return NULL;
716
717   m = search_for_method_in_hierarchy (class_, selector);
718   if (m)
719     return m;
720
721   /* Try going through +resolveInstanceMethod:, and do the search
722      again if successful.  */
723   if (__objc_resolve_instance_method (class_, selector))
724     return search_for_method_in_hierarchy (class_, selector);
725
726   return NULL;
727 }
728
729 struct objc_method *
730 class_getClassMethod (Class class_, SEL selector)
731 {
732   struct objc_method *m;
733
734   if (class_ == Nil  ||  selector == NULL)
735     return NULL;
736   
737   m = search_for_method_in_hierarchy (class_->class_pointer, 
738                                       selector);
739   if (m)
740     return m;
741
742   /* Try going through +resolveClassMethod:, and do the search again
743      if successful.  */
744   if (__objc_resolve_class_method (class_, selector))
745     return search_for_method_in_hierarchy (class_->class_pointer, 
746                                            selector);    
747
748   return NULL;
749 }
750
751 BOOL
752 class_addMethod (Class class_, SEL selector, IMP implementation,
753                  const char *method_types)
754 {
755   struct objc_method_list *method_list;
756   struct objc_method *method;
757   const char *method_name;
758
759   if (class_ == Nil  ||  selector == NULL  ||  implementation == NULL  
760       || method_types == NULL  || (strcmp (method_types, "") == 0))
761     return NO;
762
763   method_name = sel_getName (selector);
764   if (method_name == NULL)
765     return NO;
766
767   method_list = (struct objc_method_list *)objc_calloc (1, sizeof (struct objc_method_list));
768   method_list->method_count = 1;
769
770   method = &(method_list->method_list[0]);
771   method->method_name = objc_malloc (strlen (method_name) + 1);
772   strcpy ((char *)method->method_name, method_name);
773
774   method->method_types = objc_malloc (strlen (method_types) + 1);
775   strcpy ((char *)method->method_types, method_types);
776   
777   method->method_imp = implementation;
778   
779   if (CLS_IS_IN_CONSTRUCTION (class_))
780     {
781       /* We only need to add the method to the list.  It will be
782          registered with the runtime when the class pair is registered
783          (if ever).  */
784       method_list->method_next = class_->methods;
785       class_->methods = method_list;
786     }
787   else
788     {
789       /* Add the method to a live class.  */
790       objc_mutex_lock (__objc_runtime_mutex);
791       class_add_method_list (class_, method_list);
792       objc_mutex_unlock (__objc_runtime_mutex);
793     }
794
795   return YES;
796 }
797
798 /* Temporarily, until we include objc/runtime.h.  */
799 extern IMP
800 method_setImplementation (struct objc_method * method, IMP implementation);
801
802 IMP
803 class_replaceMethod (Class class_, SEL selector, IMP implementation,
804                      const char *method_types)
805 {
806   struct objc_method * method;
807
808   if (class_ == Nil  ||  selector == NULL  ||  implementation == NULL
809       || method_types == NULL)
810     return NULL;
811
812   method = search_for_method_in_hierarchy (class_, selector);
813
814   if (method)
815     {
816       return method_setImplementation (method, implementation);
817     }
818   else
819     {
820       class_addMethod (class_, selector, implementation, method_types);
821       return NULL;
822     }
823 }
824
825 /* Search for a method starting from the current class up its
826    hierarchy.  Return a pointer to the method's method structure if
827    found.  NULL otherwise.  */
828 static struct objc_method *
829 search_for_method_in_hierarchy (Class cls, SEL sel)
830 {
831   struct objc_method * method = NULL;
832   Class class;
833
834   if (! sel_is_mapped (sel))
835     return NULL;
836
837   /* Scan the method list of the class.  If the method isn't found in
838      the list then step to its super class.  */
839   for (class = cls; ((! method) && class); class = class->super_class)
840     method = search_for_method_in_list (class->methods, sel);
841
842   return method;
843 }
844
845
846
847 /* Given a linked list of method and a method's name.  Search for the
848    named method's method structure.  Return a pointer to the method's
849    method structure if found.  NULL otherwise.  */  
850 struct objc_method *
851 search_for_method_in_list (struct objc_method_list * list, SEL op)
852 {
853   struct objc_method_list * method_list = list;
854
855   if (! sel_is_mapped (op))
856     return NULL;
857
858   /* If not found then we'll search the list.  */
859   while (method_list)
860     {
861       int i;
862
863       /* Search the method list.  */
864       for (i = 0; i < method_list->method_count; ++i)
865         {
866           struct objc_method * method = &method_list->method_list[i];
867
868           if (method->method_name)
869             if (method->method_name->sel_id == op->sel_id)
870               return method;
871         }
872
873       /* The method wasn't found.  Follow the link to the next list of
874          methods.  */
875       method_list = method_list->method_next;
876     }
877
878   return NULL;
879 }
880
881 static retval_t __objc_forward (id object, SEL sel, arglist_t args);
882
883 /* Forwarding pointers/integers through the normal registers.  */
884 static id
885 __objc_word_forward (id rcv, SEL op, ...)
886 {
887   void *args, *res;
888
889   args = __builtin_apply_args ();
890   res = __objc_forward (rcv, op, args);
891   if (res)
892     __builtin_return (res);
893   else
894     return res;
895 }
896
897 /* Specific routine for forwarding floats/double because of
898    architectural differences on some processors.  i386s for example
899    which uses a floating point stack versus general registers for
900    floating point numbers.  This forward routine makes sure that GCC
901    restores the proper return values.  */
902 static double
903 __objc_double_forward (id rcv, SEL op, ...)
904 {
905   void *args, *res;
906
907   args = __builtin_apply_args ();
908   res = __objc_forward (rcv, op, args);
909   __builtin_return (res);
910 }
911
912 #if INVISIBLE_STRUCT_RETURN
913 static __big
914 #else
915 static id
916 #endif
917 __objc_block_forward (id rcv, SEL op, ...)
918 {
919   void *args, *res;
920
921   args = __builtin_apply_args ();
922   res = __objc_forward (rcv, op, args);
923   if (res)
924     __builtin_return (res);
925   else
926 #if INVISIBLE_STRUCT_RETURN
927     return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}};
928 #else
929     return nil;
930 #endif
931 }
932
933
934 /* This function is installed in the dispatch table for all methods
935    which are not implemented.  Thus, it is called when a selector is
936    not recognized.  */
937 static retval_t
938 __objc_forward (id object, SEL sel, arglist_t args)
939 {
940   IMP imp;
941   static SEL frwd_sel = 0;                      /* !T:SAFE2 */
942   SEL err_sel;
943
944   /* First try if the object understands forward::.  */
945   if (! frwd_sel)
946     frwd_sel = sel_get_any_uid ("forward::");
947
948   if (__objc_responds_to (object, frwd_sel))
949     {
950       imp = get_imp (object->class_pointer, frwd_sel);
951       return (*imp) (object, frwd_sel, sel, args);
952     }
953
954   /* If the object recognizes the doesNotRecognize: method then we're
955      going to send it.  */
956   err_sel = sel_get_any_uid ("doesNotRecognize:");
957   if (__objc_responds_to (object, err_sel))
958     {
959       imp = get_imp (object->class_pointer, err_sel);
960       return (*imp) (object, err_sel, sel);
961     }
962   
963   /* The object doesn't recognize the method.  Check for responding to
964      error:.  If it does then sent it.  */
965   {
966     char msg[256 + strlen ((const char *) sel_getName (sel))
967              + strlen ((const char *) object->class_pointer->name)];
968
969     sprintf (msg, "(%s) %s does not recognize %s",
970              (CLS_ISMETA (object->class_pointer)
971               ? "class"
972               : "instance" ),
973              object->class_pointer->name, sel_getName (sel));
974
975     /* TODO: support for error: is surely deprecated ? */
976     err_sel = sel_get_any_uid ("error:");
977     if (__objc_responds_to (object, err_sel))
978       {
979         imp = get_imp (object->class_pointer, err_sel);
980         return (*imp) (object, sel_get_any_uid ("error:"), msg);
981       }
982
983     /* The object doesn't respond to doesNotRecognize: or error:;
984        Therefore, a default action is taken.  */
985     _objc_abort ("%s\n", msg);
986
987     return 0;
988   }
989 }
990
991 void
992 __objc_print_dtable_stats ()
993 {
994   int total = 0;
995
996   objc_mutex_lock (__objc_runtime_mutex);
997
998 #ifdef OBJC_SPARSE2
999   printf ("memory usage: (%s)\n", "2-level sparse arrays");
1000 #else
1001   printf ("memory usage: (%s)\n", "3-level sparse arrays");
1002 #endif
1003
1004   printf ("arrays: %d = %ld bytes\n", narrays, 
1005           (long) ((size_t) narrays * sizeof (struct sarray)));
1006   total += narrays * sizeof (struct sarray);
1007   printf ("buckets: %d = %ld bytes\n", nbuckets, 
1008           (long) ((size_t) nbuckets * sizeof (struct sbucket)));
1009   total += nbuckets * sizeof (struct sbucket);
1010
1011   printf ("idxtables: %d = %ld bytes\n",
1012           idxsize, (long) ((size_t) idxsize * sizeof (void *)));
1013   total += idxsize * sizeof (void *);
1014   printf ("-----------------------------------\n");
1015   printf ("total: %d bytes\n", total);
1016   printf ("===================================\n");
1017
1018   objc_mutex_unlock (__objc_runtime_mutex);
1019 }
1020
1021 /* Returns the uninstalled dispatch table indicator.  If a class'
1022    dispatch table points to __objc_uninstalled_dtable then that means
1023    it needs its dispatch table to be installed.  */
1024 struct sarray *
1025 objc_get_uninstalled_dtable (void)
1026 {
1027   return __objc_uninstalled_dtable;
1028 }