OSDN Git Service

($(OBJC_O)): Also depend on $(GCC_PASSES).
[pf3gnuchains/gcc-fork.git] / gcc / objc / sendmsg.c
1 /* GNU Objective C Runtime message lookup 
2    Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
3    Contributed by Kresten Krab Thorup
4
5 This file is part of GNU CC.
6
7 GNU CC is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 2, or (at your option) any later version.
10
11 GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14 details.
15
16 You should have received a copy of the GNU General Public License along with
17 GNU CC; see the file COPYING.  If not, write to the Free Software
18 Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 /* As a special exception, if you link this library with files compiled with
22    GCC to produce an executable, this does not cause the resulting executable
23    to be covered by the GNU General Public License. This exception does not
24    however invalidate any other reasons why the executable file might be
25    covered by the GNU General Public License.  */
26
27 #include "../tconfig.h"
28 #include "runtime.h"
29 #include "sarray.h"
30 #include "encoding.h"
31
32 /* this is how we hack STRUCT_VALUE to be 1 or 0 */
33 #define gen_rtx(args...) 1
34 #define rtx int
35
36 #if !defined(STRUCT_VALUE) || STRUCT_VALUE == 0
37 #define INVISIBLE_STRUCT_RETURN 1
38 #else
39 #define INVISIBLE_STRUCT_RETURN 0
40 #endif
41
42 /* The uninstalled dispatch table */
43 struct sarray* __objc_uninstalled_dtable = 0;   /* !T:MUTEX */
44
45 /* Send +initialize to class */
46 static void __objc_send_initialize(Class);
47
48 static void __objc_install_dispatch_table_for_class (Class);
49
50 /* Forward declare some functions */
51 static void __objc_init_install_dtable(id, SEL);
52
53 /* Various forwarding functions that are used based upon the
54    return type for the selector.
55    __objc_block_forward for structures.
56    __objc_double_forward for floats/doubles.
57    __objc_word_forward for pointers or types that fit in registers.
58    */
59 static double __objc_double_forward(id, SEL, ...);
60 static id __objc_word_forward(id, SEL, ...);
61 typedef struct { id many[8]; } __big;
62 #if INVISIBLE_STRUCT_RETURN 
63 static __big 
64 #else
65 static id
66 #endif
67 __objc_block_forward(id, SEL, ...);
68 static Method_t search_for_method_in_hierarchy (Class class, SEL sel);
69 Method_t search_for_method_in_list(MethodList_t list, SEL op);
70 id nil_method(id, SEL, ...);
71
72 /* Given a selector, return the proper forwarding implementation. */
73 __inline__
74 IMP
75 __objc_get_forward_imp (SEL sel)
76 {
77   const char *t = sel->sel_types;
78
79   if (t && (*t == '[' || *t == '(' || *t == '{'))
80     return (IMP)__objc_block_forward;
81   else if (t && (*t == 'f' || *t == 'd'))
82     return (IMP)__objc_double_forward;
83   else
84     return (IMP)__objc_word_forward;
85 }
86
87 /* Given a class and selector, return the selector's implementation.  */
88 __inline__
89 IMP
90 get_imp (Class class, SEL sel)
91 {
92   IMP impl;
93   void* res = sarray_get (class->dtable, (size_t) sel->sel_id);
94   if (res == 0)
95     {
96       /* Not a valid method */
97       if(class->dtable == __objc_uninstalled_dtable)
98         {
99           /* The dispatch table needs to be installed. */
100           objc_mutex_lock(__objc_runtime_mutex);
101           __objc_install_dispatch_table_for_class (class);
102           objc_mutex_unlock(__objc_runtime_mutex);
103           /* Call ourselves with the installed dispatch table
104              and get the real method */
105           res = get_imp(class, sel);
106         }
107       else
108         {
109           /* The dispatch table has been installed so the
110              method just doesn't exist for the class.
111              Return the forwarding implementation. */
112           res = __objc_get_forward_imp(sel);
113         }
114     }
115   return res;
116 }
117
118 /* Query if an object can respond to a selector, returns YES if the
119 object implements the selector otherwise NO.  Does not check if the
120 method can be forwarded. */
121 __inline__
122 BOOL
123 __objc_responds_to (id object, SEL sel)
124 {
125   void* res;
126
127   /* Install dispatch table if need be */
128   if (object->class_pointer->dtable == __objc_uninstalled_dtable)
129     {
130       objc_mutex_lock(__objc_runtime_mutex);
131       __objc_install_dispatch_table_for_class (object->class_pointer);
132       objc_mutex_unlock(__objc_runtime_mutex);
133     }
134
135   /* Get the method from the dispatch table */
136   res = sarray_get (object->class_pointer->dtable, (size_t) sel->sel_id);
137   return (res != 0);
138 }
139
140 /* This is the lookup function.  All entries in the table are either a 
141    valid method *or* zero.  If zero then either the dispatch table
142    needs to be installed or it doesn't exist and forwarding is attempted. */
143 __inline__
144 IMP
145 objc_msg_lookup(id receiver, SEL op)
146 {
147   IMP result;
148   if(receiver)
149     {
150       result = sarray_get(receiver->class_pointer->dtable, (sidx)op->sel_id);
151       if (result == 0)
152         {
153           /* Not a valid method */
154           if(receiver->class_pointer->dtable == __objc_uninstalled_dtable)
155             {
156               /* The dispatch table needs to be installed.
157                  This happens on the very first method call to the class. */
158               __objc_init_install_dtable(receiver, op);
159
160               /* Get real method for this in newly installed dtable */
161               result = get_imp(receiver->class_pointer, op);
162             }
163           else
164             {
165               /* The dispatch table has been installed so the
166                  method just doesn't exist for the class.
167                  Attempt to forward the method. */
168               result = __objc_get_forward_imp(op);
169             }
170         }
171       return result;
172     }
173   else
174     return nil_method;
175 }
176
177 IMP
178 objc_msg_lookup_super (Super_t super, SEL sel)
179 {
180   if (super->self)
181     return get_imp (super->class, sel);
182   else
183     return nil_method;
184 }
185
186 int method_get_sizeof_arguments (Method*);
187
188 retval_t
189 objc_msg_sendv(id object, SEL op, arglist_t arg_frame)
190 {
191   Method* m = class_get_instance_method(object->class_pointer, op);
192   const char *type;
193   *((id*)method_get_first_argument (m, arg_frame, &type)) = object;
194   *((SEL*)method_get_next_argument (arg_frame, &type)) = op;
195   return __builtin_apply((apply_t)m->method_imp, 
196                          arg_frame,
197                          method_get_sizeof_arguments (m));
198 }
199
200 void
201 __objc_init_dispatch_tables()
202 {
203   __objc_uninstalled_dtable
204     = sarray_new(200, 0);
205 }
206
207 /* This function is called by objc_msg_lookup when the
208    dispatch table needs to be installed; thus it is called once
209    for each class, namely when the very first message is sent to it. */
210 static void
211 __objc_init_install_dtable(id receiver, SEL op)
212 {
213   /* This may happen, if the programmer has taken the address of a 
214      method before the dtable was initialized... too bad for him! */
215   if(receiver->class_pointer->dtable != __objc_uninstalled_dtable)
216     return;
217
218   objc_mutex_lock(__objc_runtime_mutex);
219
220   if(CLS_ISCLASS(receiver->class_pointer))
221     {
222       /* receiver is an ordinary object */
223       assert(CLS_ISCLASS(receiver->class_pointer));
224
225       /* install instance methods table */
226       __objc_install_dispatch_table_for_class (receiver->class_pointer);
227
228       /* call +initialize -- this will in turn install the factory 
229          dispatch table if not already done :-) */
230       __objc_send_initialize(receiver->class_pointer);
231     }
232   else
233     {
234       /* receiver is a class object */
235       assert(CLS_ISCLASS((Class)receiver));
236       assert(CLS_ISMETA(receiver->class_pointer));
237
238       /* Install real dtable for factory methods */
239       __objc_install_dispatch_table_for_class (receiver->class_pointer);
240
241       if (strcmp (sel_get_name (op), "initialize"))
242         __objc_send_initialize((Class)receiver);
243       else
244         CLS_SETINITIALIZED((Class)receiver);
245     }
246   objc_mutex_unlock(__objc_runtime_mutex);
247 }
248
249 /* Install dummy table for class which causes the first message to
250    that class (or instances hereof) to be initialized properly */
251 void
252 __objc_install_premature_dtable(Class class)
253 {
254   assert(__objc_uninstalled_dtable);
255   class->dtable = __objc_uninstalled_dtable;
256 }   
257
258 /* Send +initialize to class if not already done */
259 static void
260 __objc_send_initialize(Class class)
261 {
262   /* This *must* be a class object */
263   assert(CLS_ISCLASS(class));
264   assert(!CLS_ISMETA(class));
265
266   if (!CLS_ISINITIALIZED(class))
267     {
268       CLS_SETINITIALIZED(class);
269       CLS_SETINITIALIZED(class->class_pointer);
270       
271       if(class->super_class)
272         __objc_send_initialize(class->super_class);
273
274       {
275         SEL     op = sel_register_name ("initialize");
276         Class   tmpclass = class;
277         IMP     imp = 0;
278
279         while (!imp && tmpclass) {
280           MethodList_t method_list = tmpclass->class_pointer->methods;
281
282           while(!imp && method_list) {
283             int i;
284             Method_t method;
285
286             for (i=0;i<method_list->method_count;i++) {
287               method = &(method_list->method_list[i]);
288               if (method->method_name
289                   && method->method_name->sel_id == op->sel_id) {
290                 imp = method->method_imp;
291                 break;
292               }
293             }
294
295             method_list = method_list->method_next;
296
297           }
298
299           tmpclass = tmpclass->super_class;
300         }
301         if (imp)
302             (*imp)((id)class, op);
303                 
304       }
305     }
306 }
307
308 /* Walk on the methods list of class and install the methods in the reverse
309    order of the lists. Since methods added by categories are before the methods
310    of class in the methods list, this allows categories to substitute methods
311    declared in class. However if more than one category replace the same method
312    nothing is guarranteed about what method will be used.
313    Assumes that __objc_runtime_mutex is locked down. */
314 static void
315 __objc_install_methods_in_dtable (Class class, MethodList_t method_list)
316 {
317   int i;
318
319   if (!method_list)
320     return;
321
322   if (method_list->method_next)
323     __objc_install_methods_in_dtable (class, method_list->method_next);
324
325   for (i = 0; i < method_list->method_count; i++)
326     {
327       Method_t method = &(method_list->method_list[i]);
328       sarray_at_put_safe (class->dtable,
329                           (sidx) method->method_name->sel_id,
330                           method->method_imp);
331     }
332 }
333
334 /* Assumes that __objc_runtime_mutex is locked down. */
335 static void
336 __objc_install_dispatch_table_for_class (Class class)
337 {
338   Class super;
339   int counter;
340
341   /* If the class has not yet had it's class links resolved, we must 
342      re-compute all class links */
343   if(!CLS_ISRESOLV(class))
344     __objc_resolve_class_links();
345
346   super = class->super_class;
347
348   if (super != 0 && (super->dtable == __objc_uninstalled_dtable))
349     __objc_install_dispatch_table_for_class (super);
350
351   /* Allocate dtable if necessary */
352   if (super == 0)
353     {
354       objc_mutex_lock(__objc_runtime_mutex);
355       class->dtable = sarray_new (__objc_selector_max_index, 0);
356       objc_mutex_unlock(__objc_runtime_mutex);
357     }
358   else
359     class->dtable = sarray_lazy_copy (super->dtable);
360
361   __objc_install_methods_in_dtable (class, class->methods);
362 }
363
364 void
365 __objc_update_dispatch_table_for_class (Class class)
366 {
367   Class next;
368   struct sarray *arr;
369
370   /* not yet installed -- skip it */
371   if (class->dtable == __objc_uninstalled_dtable) 
372     return;
373
374   objc_mutex_lock(__objc_runtime_mutex);
375
376   arr = class->dtable;
377   __objc_install_premature_dtable (class); /* someone might require it... */
378   sarray_free (arr);                       /* release memory */
379
380   /* could have been lazy... */
381   __objc_install_dispatch_table_for_class (class); 
382
383   if (class->subclass_list)     /* Traverse subclasses */
384     for (next = class->subclass_list; next; next = next->sibling_class)
385       __objc_update_dispatch_table_for_class (next);
386
387   objc_mutex_unlock(__objc_runtime_mutex);
388 }
389
390
391 /* This function adds a method list to a class.  This function is
392    typically called by another function specific to the run-time.  As
393    such this function does not worry about thread safe issues.
394
395    This one is only called for categories. Class objects have their
396    methods installed right away, and their selectors are made into
397    SEL's by the function __objc_register_selectors_from_class. */ 
398 void
399 class_add_method_list (Class class, MethodList_t list)
400 {
401   int i;
402
403   /* Passing of a linked list is not allowed.  Do multiple calls.  */
404   assert (!list->method_next);
405
406   /* Check for duplicates.  */
407   for (i = 0; i < list->method_count; ++i)
408     {
409       Method_t method = &list->method_list[i];
410
411       if (method->method_name)  /* Sometimes these are NULL */
412         {
413           /* This is where selector names are transmogrified to SEL's */
414           method->method_name = 
415             sel_register_typed_name ((const char*)method->method_name,
416                                      method->method_types);
417         }
418     }
419
420   /* Add the methods to the class's method list.  */
421   list->method_next = class->methods;
422   class->methods = list;
423
424   /* Update the dispatch table of class */
425   __objc_update_dispatch_table_for_class (class);
426 }
427
428 Method_t
429 class_get_instance_method(Class class, SEL op)
430 {
431   return search_for_method_in_hierarchy(class, op);
432 }
433
434 Method_t
435 class_get_class_method(MetaClass class, SEL op)
436 {
437   return search_for_method_in_hierarchy(class, op);
438 }
439
440
441 /* Search for a method starting from the current class up its hierarchy.
442    Return a pointer to the method's method structure if found.  NULL
443    otherwise. */   
444
445 static Method_t
446 search_for_method_in_hierarchy (Class cls, SEL sel)
447 {
448   Method_t method = NULL;
449   Class class;
450
451   if (! sel_is_mapped (sel))
452     return NULL;
453
454   /* Scan the method list of the class.  If the method isn't found in the
455      list then step to its super class. */
456   for (class = cls; ((! method) && class); class = class->super_class)
457     method = search_for_method_in_list (class->methods, sel);
458
459   return method;
460 }
461
462
463
464 /* Given a linked list of method and a method's name.  Search for the named
465    method's method structure.  Return a pointer to the method's method
466    structure if found.  NULL otherwise. */  
467 Method_t
468 search_for_method_in_list (MethodList_t list, SEL op)
469 {
470   MethodList_t method_list = list;
471
472   if (! sel_is_mapped (op))
473     return NULL;
474
475   /* If not found then we'll search the list.  */
476   while (method_list)
477     {
478       int i;
479
480       /* Search the method list.  */
481       for (i = 0; i < method_list->method_count; ++i)
482         {
483           Method_t method = &method_list->method_list[i];
484
485           if (method->method_name)
486             if (method->method_name->sel_id == op->sel_id)
487               return method;
488         }
489
490       /* The method wasn't found.  Follow the link to the next list of
491          methods.  */
492       method_list = method_list->method_next;
493     }
494
495   return NULL;
496 }
497
498 static retval_t __objc_forward (id object, SEL sel, arglist_t args);
499
500 /* Forwarding pointers/integers through the normal registers */
501 static id
502 __objc_word_forward (id rcv, SEL op, ...)
503 {
504   void *args, *res;
505
506   args = __builtin_apply_args ();
507   res = __objc_forward (rcv, op, args);
508   if (res)
509     __builtin_return (res);
510   else
511     return res;
512 }
513
514 /* Specific routine for forwarding floats/double because of
515    architectural differences on some processors.  i386s for
516    example which uses a floating point stack versus general
517    registers for floating point numbers.  This forward routine 
518    makes sure that GCC restores the proper return values */
519 static double
520 __objc_double_forward (id rcv, SEL op, ...)
521 {
522   void *args, *res;
523
524   args = __builtin_apply_args ();
525   res = __objc_forward (rcv, op, args);
526   __builtin_return (res);
527 }
528
529 #if INVISIBLE_STRUCT_RETURN
530 static __big
531 #else
532 static id
533 #endif
534 __objc_block_forward (id rcv, SEL op, ...)
535 {
536   void *args, *res;
537
538   args = __builtin_apply_args ();
539   res = __objc_forward (rcv, op, args);
540   if (res)
541     __builtin_return (res);
542 }
543
544
545 /* This function is installed in the dispatch table for all methods which are
546    not implemented.  Thus, it is called when a selector is not recognized. */
547 static retval_t
548 __objc_forward (id object, SEL sel, arglist_t args)
549 {
550   IMP imp;
551   static SEL frwd_sel = 0;                      /* !T:SAFE2 */
552   SEL err_sel;
553
554   /* first try if the object understands forward:: */
555   if (!frwd_sel)
556     frwd_sel = sel_get_any_uid("forward::");
557
558   if (__objc_responds_to (object, frwd_sel))
559     {
560       imp = get_imp(object->class_pointer, frwd_sel);
561       return (*imp)(object, frwd_sel, sel, args);
562     }
563
564   /* If the object recognizes the doesNotRecognize: method then we're going
565      to send it. */
566   err_sel = sel_get_any_uid ("doesNotRecognize:");
567   if (__objc_responds_to (object, err_sel))
568     {
569       imp = get_imp (object->class_pointer, err_sel);
570       return (*imp) (object, err_sel, sel);
571     }
572   
573   /* The object doesn't recognize the method.  Check for responding to
574      error:.  If it does then sent it. */
575   {
576     size_t strlen (const char*);
577     char msg[256 + strlen ((const char*)sel_get_name (sel))
578              + strlen ((const char*)object->class_pointer->name)];
579
580     sprintf (msg, "(%s) %s does not recognize %s",
581              (CLS_ISMETA(object->class_pointer)
582               ? "class"
583               : "instance" ),
584              object->class_pointer->name, sel_get_name (sel));
585
586     err_sel = sel_get_any_uid ("error:");
587     if (__objc_responds_to (object, err_sel))
588       {
589         imp = get_imp (object->class_pointer, err_sel);
590         return (*imp) (object, sel_get_any_uid ("error:"), msg);
591       }
592
593     /* The object doesn't respond to doesNotRecognize: or error:;  Therefore,
594        a default action is taken. */
595     objc_error (object, OBJC_ERR_UNIMPLEMENTED, "%s\n", msg);
596   }
597 }
598
599 void
600 __objc_print_dtable_stats()
601 {
602   int total = 0;
603
604   objc_mutex_lock(__objc_runtime_mutex);
605
606   printf("memory usage: (%s)\n",
607 #ifdef OBJC_SPARSE2
608          "2-level sparse arrays"
609 #else
610          "3-level sparse arrays"
611 #endif
612          );
613
614   printf("arrays: %d = %ld bytes\n", narrays, 
615          (int)narrays*sizeof(struct sarray));
616   total += narrays*sizeof(struct sarray);
617   printf("buckets: %d = %ld bytes\n", nbuckets, 
618          (int)nbuckets*sizeof(struct sbucket));
619   total += nbuckets*sizeof(struct sbucket);
620
621   printf("idxtables: %d = %ld bytes\n", idxsize, (int)idxsize*sizeof(void*));
622   total += idxsize*sizeof(void*);
623   printf("-----------------------------------\n");
624   printf("total: %d bytes\n", total);
625   printf("===================================\n");
626
627   objc_mutex_unlock(__objc_runtime_mutex);
628 }
629
630 /* Returns the uninstalled dispatch table indicator.
631  If a class' dispatch table points to __objc_uninstalled_dtable
632  then that means it needs its dispatch table to be installed. */
633 __inline__
634 struct sarray* 
635 objc_get_uninstalled_dtable()
636 {
637   return __objc_uninstalled_dtable;
638 }