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