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 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/objc.h"
37 #include "objc/objc-api.h"
38 #include "objc/thr.h"
39 #include "objc-private/runtime.h"
40 #include "objc-private/sarray.h"
41 #include "objc/encoding.h"
42 #include "runtime-info.h"
43 #include <assert.h> /* For assert */
44 #include <string.h> /* For strlen */
45
46 /* This is how we hack STRUCT_VALUE to be 1 or 0.   */
47 #define gen_rtx(args...) 1
48 #define gen_rtx_MEM(args...) 1
49 #define gen_rtx_REG(args...) 1
50 /* Alread defined in gcc/coretypes.h. So prevent double definition warning.  */
51 #undef rtx
52 #define rtx int
53
54 #if ! defined (STRUCT_VALUE) || STRUCT_VALUE == 0
55 #define INVISIBLE_STRUCT_RETURN 1
56 #else
57 #define INVISIBLE_STRUCT_RETURN 0
58 #endif
59
60 /* The uninstalled dispatch table */
61 struct sarray *__objc_uninstalled_dtable = 0;   /* !T:MUTEX */
62
63 /* Two hooks for method forwarding. If either is set, it is invoked
64  * to return a function that performs the real forwarding.  If both
65  * are set, the result of __objc_msg_forward2 will be preferred over
66  * that of __objc_msg_forward.  If both return NULL or are unset,
67  * the libgcc based functions (__builtin_apply and friends) are
68  * used.
69  */
70 IMP (*__objc_msg_forward) (SEL) = NULL;
71 IMP (*__objc_msg_forward2) (id, SEL) = NULL;
72
73 /* Send +initialize to class */
74 static void __objc_send_initialize (Class);
75
76 static void __objc_install_dispatch_table_for_class (Class);
77
78 /* Forward declare some functions */
79 static void __objc_init_install_dtable (id, SEL);
80
81 /* Various forwarding functions that are used based upon the
82    return type for the selector.
83    __objc_block_forward for structures.
84    __objc_double_forward for floats/doubles.
85    __objc_word_forward for pointers or types that fit in registers. */
86 static double __objc_double_forward (id, SEL, ...);
87 static id __objc_word_forward (id, SEL, ...);
88 typedef struct { id many[8]; } __big;
89 #if INVISIBLE_STRUCT_RETURN 
90 static __big 
91 #else
92 static id
93 #endif
94 __objc_block_forward (id, SEL, ...);
95 static Method_t search_for_method_in_hierarchy (Class class, SEL sel);
96 Method_t search_for_method_in_list (MethodList_t list, SEL op);
97 id nil_method (id, SEL);
98
99 /* Given a selector, return the proper forwarding implementation. */
100 inline
101 IMP
102 __objc_get_forward_imp (id rcv, SEL sel)
103 {
104   /* If a custom forwarding hook was registered, try getting a forwarding
105      function from it. There are two forward routine hooks, one that
106      takes the receiver as an argument and one that does not. */
107   if (__objc_msg_forward2)
108     {
109       IMP result;
110       if ((result = __objc_msg_forward2 (rcv, sel)) != NULL)
111        return result;
112     }
113   if (__objc_msg_forward)
114     {
115       IMP result;
116       if ((result = __objc_msg_forward (sel)) != NULL) 
117         return result;
118     }
119
120   /* In all other cases, use the default forwarding functions built using
121      __builtin_apply and friends.  */
122     {
123       const char *t = sel->sel_types;
124
125       if (t && (*t == '[' || *t == '(' || *t == '{')
126 #ifdef OBJC_MAX_STRUCT_BY_VALUE
127           && objc_sizeof_type (t) > OBJC_MAX_STRUCT_BY_VALUE
128 #endif
129           )
130         return (IMP)__objc_block_forward;
131       else if (t && (*t == 'f' || *t == 'd'))
132         return (IMP)__objc_double_forward;
133       else
134         return (IMP)__objc_word_forward;
135     }
136 }
137
138 /* Given a class and selector, return the selector's implementation.  */
139 inline
140 IMP
141 get_imp (Class class, SEL sel)
142 {
143   /* In a vanilla implementation we would first check if the dispatch
144      table is installed.  Here instead, to get more speed in the
145      standard case (that the dispatch table is installed) we first try
146      to get the imp using brute force.  Only if that fails, we do what
147      we should have been doing from the very beginning, that is, check
148      if the dispatch table needs to be installed, install it if it's
149      not installed, and retrieve the imp from the table if it's
150      installed.  */
151   void *res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
152   if (res == 0)
153     {
154       /* Not a valid method */
155       if (class->dtable == __objc_uninstalled_dtable)
156         {
157           /* The dispatch table needs to be installed. */
158           objc_mutex_lock (__objc_runtime_mutex);
159
160            /* Double-checked locking pattern: Check
161               __objc_uninstalled_dtable again in case another thread
162               installed the dtable while we were waiting for the lock
163               to be released.  */
164          if (class->dtable == __objc_uninstalled_dtable)
165            {
166              __objc_install_dispatch_table_for_class (class);
167            }
168
169           objc_mutex_unlock (__objc_runtime_mutex);
170           /* Call ourselves with the installed dispatch table
171              and get the real method */
172           res = get_imp (class, sel);
173         }
174       else
175         {
176           /* The dispatch table has been installed.  */
177
178          /* Get the method from the dispatch table (we try to get it
179             again in case another thread has installed the dtable just
180             after we invoked sarray_get_safe, but before we checked
181             class->dtable == __objc_uninstalled_dtable).
182          */
183           res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
184           if (res == 0)
185             {
186               /* The dispatch table has been installed, and the method
187                  is not in the dispatch table.  So the method just
188                  doesn't exist for the class.  Return the forwarding
189                  implementation. */
190              res = __objc_get_forward_imp ((id)class, sel);
191             }
192         }
193     }
194   return res;
195 }
196
197 /* Query if an object can respond to a selector, returns YES if the
198 object implements the selector otherwise NO.  Does not check if the
199 method can be forwarded. */
200 inline
201 BOOL
202 __objc_responds_to (id object, SEL sel)
203 {
204   void *res;
205
206   /* Install dispatch table if need be */
207   if (object->class_pointer->dtable == __objc_uninstalled_dtable)
208     {
209       objc_mutex_lock (__objc_runtime_mutex);
210       if (object->class_pointer->dtable == __objc_uninstalled_dtable)
211         {
212           __objc_install_dispatch_table_for_class (object->class_pointer);
213         }
214       objc_mutex_unlock (__objc_runtime_mutex);
215     }
216
217   /* Get the method from the dispatch table */
218   res = sarray_get_safe (object->class_pointer->dtable, (size_t) sel->sel_id);
219   return (res != 0);
220 }
221
222 /* This is the lookup function.  All entries in the table are either a 
223    valid method *or* zero.  If zero then either the dispatch table
224    needs to be installed or it doesn't exist and forwarding is attempted. */
225 inline
226 IMP
227 objc_msg_lookup (id receiver, SEL op)
228 {
229   IMP result;
230   if (receiver)
231     {
232       result = sarray_get_safe (receiver->class_pointer->dtable, 
233                                 (sidx)op->sel_id);
234       if (result == 0)
235         {
236           /* Not a valid method */
237           if (receiver->class_pointer->dtable == __objc_uninstalled_dtable)
238             {
239               /* The dispatch table needs to be installed.
240                  This happens on the very first method call to the class. */
241               __objc_init_install_dtable (receiver, op);
242
243               /* Get real method for this in newly installed dtable */
244               result = get_imp (receiver->class_pointer, op);
245             }
246           else
247             {
248               /* The dispatch table has been installed.  Check again
249                  if the method exists (just in case the dispatch table
250                  has been installed by another thread after we did the
251                  previous check that the method exists).
252               */
253               result = sarray_get_safe (receiver->class_pointer->dtable,
254                                         (sidx)op->sel_id);
255               if (result == 0)
256                 {
257                   /* If the method still just doesn't exist for the
258                      class, attempt to forward the method. */
259                   result = __objc_get_forward_imp (receiver, op);
260                 }
261             }
262         }
263       return result;
264     }
265   else
266     return (IMP)nil_method;
267 }
268
269 IMP
270 objc_msg_lookup_super (Super_t super, SEL sel)
271 {
272   if (super->self)
273     return get_imp (super->class, sel);
274   else
275     return (IMP)nil_method;
276 }
277
278 int method_get_sizeof_arguments (Method *);
279
280 retval_t
281 objc_msg_sendv (id object, SEL op, arglist_t arg_frame)
282 {
283   Method *m = class_get_instance_method (object->class_pointer, op);
284   const char *type;
285   *((id *) method_get_first_argument (m, arg_frame, &type)) = object;
286   *((SEL *) method_get_next_argument (arg_frame, &type)) = op;
287   return __builtin_apply ((apply_t) m->method_imp, 
288                           arg_frame,
289                           method_get_sizeof_arguments (m));
290 }
291
292 void
293 __objc_init_dispatch_tables ()
294 {
295   __objc_uninstalled_dtable = sarray_new (200, 0);
296 }
297
298 /* This function is called by objc_msg_lookup when the
299    dispatch table needs to be installed; thus it is called once
300    for each class, namely when the very first message is sent to it. */
301 static void
302 __objc_init_install_dtable (id receiver, SEL op __attribute__ ((__unused__)))
303 {
304   objc_mutex_lock (__objc_runtime_mutex);
305   
306   /* This may happen, if the programmer has taken the address of a 
307      method before the dtable was initialized... too bad for him! */
308   if (receiver->class_pointer->dtable != __objc_uninstalled_dtable)
309     {
310       objc_mutex_unlock (__objc_runtime_mutex);
311       return;
312     }
313   
314   if (CLS_ISCLASS (receiver->class_pointer))
315     {
316       /* receiver is an ordinary object */
317       assert (CLS_ISCLASS (receiver->class_pointer));
318
319       /* install instance methods table */
320       __objc_install_dispatch_table_for_class (receiver->class_pointer);
321
322       /* call +initialize -- this will in turn install the factory 
323          dispatch table if not already done :-) */
324       __objc_send_initialize (receiver->class_pointer);
325     }
326   else
327     {
328       /* receiver is a class object */
329       assert (CLS_ISCLASS ((Class)receiver));
330       assert (CLS_ISMETA (receiver->class_pointer));
331
332       /* Install real dtable for factory methods */
333       __objc_install_dispatch_table_for_class (receiver->class_pointer);
334
335       __objc_send_initialize ((Class)receiver);
336     }
337   objc_mutex_unlock (__objc_runtime_mutex);
338 }
339
340 /* Install dummy table for class which causes the first message to
341    that class (or instances hereof) to be initialized properly */
342 void
343 __objc_install_premature_dtable (Class class)
344 {
345   assert (__objc_uninstalled_dtable);
346   class->dtable = __objc_uninstalled_dtable;
347 }   
348
349 /* Send +initialize to class if not already done */
350 static void
351 __objc_send_initialize (Class class)
352 {
353   /* This *must* be a class object */
354   assert (CLS_ISCLASS (class));
355   assert (! CLS_ISMETA (class));
356
357   if (! CLS_ISINITIALIZED (class))
358     {
359       CLS_SETINITIALIZED (class);
360       CLS_SETINITIALIZED (class->class_pointer);
361
362       /* Create the garbage collector type memory description */
363       __objc_generate_gc_type_description (class);
364
365       if (class->super_class)
366         __objc_send_initialize (class->super_class);
367
368       {
369         SEL          op = sel_register_name ("initialize");
370         IMP          imp = 0;
371         MethodList_t method_list = class->class_pointer->methods;
372
373         while (method_list) {
374           int i;
375           Method_t method;
376
377           for (i = 0; i < method_list->method_count; i++) {
378             method = &(method_list->method_list[i]);
379             if (method->method_name
380                 && method->method_name->sel_id == op->sel_id) {
381               imp = method->method_imp;
382               break;
383             }
384           }
385
386           if (imp)
387             break;
388
389           method_list = method_list->method_next;
390
391         }
392         if (imp)
393             (*imp) ((id) class, op);
394                 
395       }
396     }
397 }
398
399 /* Walk on the methods list of class and install the methods in the reverse
400    order of the lists. Since methods added by categories are before the methods
401    of class in the methods list, this allows categories to substitute methods
402    declared in class. However if more than one category replaces the same
403    method nothing is guaranteed about what method will be used.
404    Assumes that __objc_runtime_mutex is locked down. */
405 static void
406 __objc_install_methods_in_dtable (Class class, MethodList_t method_list)
407 {
408   int i;
409
410   if (! method_list)
411     return;
412
413   if (method_list->method_next)
414     __objc_install_methods_in_dtable (class, method_list->method_next);
415
416   for (i = 0; i < method_list->method_count; i++)
417     {
418       Method_t method = &(method_list->method_list[i]);
419       sarray_at_put_safe (class->dtable,
420                           (sidx) method->method_name->sel_id,
421                           method->method_imp);
422     }
423 }
424
425 /* Assumes that __objc_runtime_mutex is locked down. */
426 static void
427 __objc_install_dispatch_table_for_class (Class class)
428 {
429   Class super;
430
431   /* If the class has not yet had its class links resolved, we must 
432      re-compute all class links */
433   if (! CLS_ISRESOLV (class))
434     __objc_resolve_class_links ();
435
436   super = class->super_class;
437
438   if (super != 0 && (super->dtable == __objc_uninstalled_dtable))
439     __objc_install_dispatch_table_for_class (super);
440
441   /* Allocate dtable if necessary */
442   if (super == 0)
443     {
444       objc_mutex_lock (__objc_runtime_mutex);
445       class->dtable = sarray_new (__objc_selector_max_index, 0);
446       objc_mutex_unlock (__objc_runtime_mutex);
447     }
448   else
449     class->dtable = sarray_lazy_copy (super->dtable);
450
451   __objc_install_methods_in_dtable (class, class->methods);
452 }
453
454 void
455 __objc_update_dispatch_table_for_class (Class class)
456 {
457   Class next;
458   struct sarray *arr;
459
460   /* not yet installed -- skip it */
461   if (class->dtable == __objc_uninstalled_dtable) 
462     return;
463
464   objc_mutex_lock (__objc_runtime_mutex);
465
466   arr = class->dtable;
467   __objc_install_premature_dtable (class); /* someone might require it... */
468   sarray_free (arr);                       /* release memory */
469
470   /* could have been lazy... */
471   __objc_install_dispatch_table_for_class (class); 
472
473   if (class->subclass_list)     /* Traverse subclasses */
474     for (next = class->subclass_list; next; next = next->sibling_class)
475       __objc_update_dispatch_table_for_class (next);
476
477   objc_mutex_unlock (__objc_runtime_mutex);
478 }
479
480
481 /* This function adds a method list to a class.  This function is
482    typically called by another function specific to the run-time.  As
483    such this function does not worry about thread safe issues.
484
485    This one is only called for categories. Class objects have their
486    methods installed right away, and their selectors are made into
487    SEL's by the function __objc_register_selectors_from_class. */
488 void
489 class_add_method_list (Class class, MethodList_t list)
490 {
491   /* Passing of a linked list is not allowed.  Do multiple calls.  */
492   assert (! list->method_next);
493
494   __objc_register_selectors_from_list(list);
495
496   /* Add the methods to the class's method list.  */
497   list->method_next = class->methods;
498   class->methods = list;
499
500   /* Update the dispatch table of class */
501   __objc_update_dispatch_table_for_class (class);
502 }
503
504 Method_t
505 class_get_instance_method (Class class, SEL op)
506 {
507   return search_for_method_in_hierarchy (class, op);
508 }
509
510 Method_t
511 class_get_class_method (MetaClass class, SEL op)
512 {
513   return search_for_method_in_hierarchy (class, op);
514 }
515
516
517 /* Search for a method starting from the current class up its hierarchy.
518    Return a pointer to the method's method structure if found.  NULL
519    otherwise. */   
520
521 static Method_t
522 search_for_method_in_hierarchy (Class cls, SEL sel)
523 {
524   Method_t method = NULL;
525   Class class;
526
527   if (! sel_is_mapped (sel))
528     return NULL;
529
530   /* Scan the method list of the class.  If the method isn't found in the
531      list then step to its super class. */
532   for (class = cls; ((! method) && class); class = class->super_class)
533     method = search_for_method_in_list (class->methods, sel);
534
535   return method;
536 }
537
538
539
540 /* Given a linked list of method and a method's name.  Search for the named
541    method's method structure.  Return a pointer to the method's method
542    structure if found.  NULL otherwise. */  
543 Method_t
544 search_for_method_in_list (MethodList_t list, SEL op)
545 {
546   MethodList_t method_list = list;
547
548   if (! sel_is_mapped (op))
549     return NULL;
550
551   /* If not found then we'll search the list.  */
552   while (method_list)
553     {
554       int i;
555
556       /* Search the method list.  */
557       for (i = 0; i < method_list->method_count; ++i)
558         {
559           Method_t method = &method_list->method_list[i];
560
561           if (method->method_name)
562             if (method->method_name->sel_id == op->sel_id)
563               return method;
564         }
565
566       /* The method wasn't found.  Follow the link to the next list of
567          methods.  */
568       method_list = method_list->method_next;
569     }
570
571   return NULL;
572 }
573
574 static retval_t __objc_forward (id object, SEL sel, arglist_t args);
575
576 /* Forwarding pointers/integers through the normal registers */
577 static id
578 __objc_word_forward (id rcv, SEL op, ...)
579 {
580   void *args, *res;
581
582   args = __builtin_apply_args ();
583   res = __objc_forward (rcv, op, args);
584   if (res)
585     __builtin_return (res);
586   else
587     return res;
588 }
589
590 /* Specific routine for forwarding floats/double because of
591    architectural differences on some processors.  i386s for
592    example which uses a floating point stack versus general
593    registers for floating point numbers.  This forward routine 
594    makes sure that GCC restores the proper return values */
595 static double
596 __objc_double_forward (id rcv, SEL op, ...)
597 {
598   void *args, *res;
599
600   args = __builtin_apply_args ();
601   res = __objc_forward (rcv, op, args);
602   __builtin_return (res);
603 }
604
605 #if INVISIBLE_STRUCT_RETURN
606 static __big
607 #else
608 static id
609 #endif
610 __objc_block_forward (id rcv, SEL op, ...)
611 {
612   void *args, *res;
613
614   args = __builtin_apply_args ();
615   res = __objc_forward (rcv, op, args);
616   if (res)
617     __builtin_return (res);
618   else
619 #if INVISIBLE_STRUCT_RETURN
620     return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}};
621 #else
622     return nil;
623 #endif
624 }
625
626
627 /* This function is installed in the dispatch table for all methods which are
628    not implemented.  Thus, it is called when a selector is not recognized. */
629 static retval_t
630 __objc_forward (id object, SEL sel, arglist_t args)
631 {
632   IMP imp;
633   static SEL frwd_sel = 0;                      /* !T:SAFE2 */
634   SEL err_sel;
635
636   /* first try if the object understands forward:: */
637   if (! frwd_sel)
638     frwd_sel = sel_get_any_uid ("forward::");
639
640   if (__objc_responds_to (object, frwd_sel))
641     {
642       imp = get_imp (object->class_pointer, frwd_sel);
643       return (*imp) (object, frwd_sel, sel, args);
644     }
645
646   /* If the object recognizes the doesNotRecognize: method then we're going
647      to send it. */
648   err_sel = sel_get_any_uid ("doesNotRecognize:");
649   if (__objc_responds_to (object, err_sel))
650     {
651       imp = get_imp (object->class_pointer, err_sel);
652       return (*imp) (object, err_sel, sel);
653     }
654   
655   /* The object doesn't recognize the method.  Check for responding to
656      error:.  If it does then sent it. */
657   {
658     char msg[256 + strlen ((const char *) sel_get_name (sel))
659              + strlen ((const char *) object->class_pointer->name)];
660
661     sprintf (msg, "(%s) %s does not recognize %s",
662              (CLS_ISMETA (object->class_pointer)
663               ? "class"
664               : "instance" ),
665              object->class_pointer->name, sel_get_name (sel));
666
667     /* TODO: support for error: is surely deprecated ? */
668     err_sel = sel_get_any_uid ("error:");
669     if (__objc_responds_to (object, err_sel))
670       {
671         imp = get_imp (object->class_pointer, err_sel);
672         return (*imp) (object, sel_get_any_uid ("error:"), msg);
673       }
674
675     /* The object doesn't respond to doesNotRecognize: or error:;  Therefore,
676        a default action is taken. */
677     _objc_abort ("%s\n", msg);
678
679     return 0;
680   }
681 }
682
683 void
684 __objc_print_dtable_stats ()
685 {
686   int total = 0;
687
688   objc_mutex_lock (__objc_runtime_mutex);
689
690 #ifdef OBJC_SPARSE2
691   printf ("memory usage: (%s)\n", "2-level sparse arrays");
692 #else
693   printf ("memory usage: (%s)\n", "3-level sparse arrays");
694 #endif
695
696   printf ("arrays: %d = %ld bytes\n", narrays, 
697           (long) ((size_t) narrays * sizeof (struct sarray)));
698   total += narrays * sizeof (struct sarray);
699   printf ("buckets: %d = %ld bytes\n", nbuckets, 
700           (long) ((size_t) nbuckets * sizeof (struct sbucket)));
701   total += nbuckets * sizeof (struct sbucket);
702
703   printf ("idxtables: %d = %ld bytes\n",
704           idxsize, (long) ((size_t) idxsize * sizeof (void *)));
705   total += idxsize * sizeof (void *);
706   printf ("-----------------------------------\n");
707   printf ("total: %d bytes\n", total);
708   printf ("===================================\n");
709
710   objc_mutex_unlock (__objc_runtime_mutex);
711 }
712
713 /* Returns the uninstalled dispatch table indicator.
714  If a class' dispatch table points to __objc_uninstalled_dtable
715  then that means it needs its dispatch table to be installed. */
716 inline
717 struct sarray *
718 objc_get_uninstalled_dtable ()
719 {
720   return __objc_uninstalled_dtable;
721 }