OSDN Git Service

Formattign changes.
[pf3gnuchains/gcc-fork.git] / gcc / objc / sendmsg.c
1 /* GNU Objective C Runtime message lookup 
2    Copyright (C) 1993, 1995, 1996 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 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 static Method_t search_for_method_in_list(MethodList_t list, SEL op);
70 id nil_method(id, SEL, ...);
71
72 /* Given a class and selector, return the selector's implementation.  */
73 __inline__
74 IMP
75 get_imp (Class class, SEL sel)
76 {
77   IMP impl;
78   void* res = sarray_get (class->dtable, (size_t) sel->sel_id);
79   if(res == __objc_init_install_dtable)
80     {
81       objc_mutex_lock(__objc_runtime_mutex);
82       __objc_install_dispatch_table_for_class (class);
83       objc_mutex_unlock(__objc_runtime_mutex);
84       res = sarray_get (class->dtable, (size_t) sel->sel_id);
85     }
86   if (res == 0)
87     {
88       const char *t = sel->sel_types;
89       if (t && (*t == '[' || *t == '(' || *t == '{'))
90         res = (IMP)__objc_block_forward;
91       else if (t && (*t == 'f' || *t == 'd'))
92         res = (IMP)__objc_double_forward;
93       else
94         res = (IMP)__objc_word_forward;
95     }
96   return res;
97 }
98
99 __inline__ BOOL
100 __objc_responds_to (id object, SEL sel)
101 {
102   void* res = sarray_get (object->class_pointer->dtable, (size_t) sel->sel_id);
103   if(res == __objc_init_install_dtable)
104     {
105       objc_mutex_lock(__objc_runtime_mutex);
106       __objc_install_dispatch_table_for_class (object->class_pointer);
107       objc_mutex_unlock(__objc_runtime_mutex);
108       res = sarray_get (object->class_pointer->dtable, (size_t) sel->sel_id);
109     }
110   return (res != 0);
111 }
112
113 /* This is the lookup function.  All entries in the table are either a 
114    valid method *or* one of `__objc_missing_method' which calls
115    forward:: etc, or `__objc_init_install_dtable' which installs the
116    real dtable */
117 __inline__ IMP
118 objc_msg_lookup(id receiver, SEL op)
119 {
120   IMP result;
121   if(receiver)
122     {
123       result = sarray_get(receiver->class_pointer->dtable, (sidx)op->sel_id);
124       if (result == 0)
125         {
126           const char *t = op->sel_types;
127           if (t && (*t == '[' || *t == '(' || *t == '{'))
128             result = (IMP)__objc_block_forward;
129           else if (t && (*t == 'f' || *t == 'd'))
130             result = (IMP)__objc_double_forward;
131           else
132             result = (IMP)__objc_word_forward;
133         }
134       return result;
135     }
136   else
137     return nil_method;
138 }
139
140 IMP
141 objc_msg_lookup_super (Super_t super, SEL sel)
142 {
143   if (super->self)
144     return get_imp (super->class, sel);
145   else
146     return nil_method;
147 }
148
149 int method_get_sizeof_arguments (Method*);
150
151 retval_t
152 objc_msg_sendv(id object, SEL op, arglist_t arg_frame)
153 {
154   Method* m = class_get_instance_method(object->class_pointer, op);
155   const char *type;
156   *((id*)method_get_first_argument (m, arg_frame, &type)) = object;
157   *((SEL*)method_get_next_argument (arg_frame, &type)) = op;
158   return __builtin_apply((apply_t)m->method_imp, 
159                          arg_frame,
160                          method_get_sizeof_arguments (m));
161 }
162
163 void __objc_init_dispatch_tables()
164 {
165   __objc_uninstalled_dtable
166     = sarray_new(200, __objc_init_install_dtable);
167 }
168
169 /* This one is a bit hairy.  This function is installed in the 
170    premature dispatch table, and thus called once for each class,
171    namely when the very first message is send to it.  */
172
173 static void __objc_init_install_dtable(id receiver, SEL op)
174 {
175   __label__ already_initialized;
176   IMP imp;
177   void* args;
178   void* result;
179
180   /* This may happen, if the programmer has taken the address of a 
181      method before the dtable was initialized... too bad for him! */
182   if(receiver->class_pointer->dtable != __objc_uninstalled_dtable)
183     goto already_initialized;
184
185   objc_mutex_lock(__objc_runtime_mutex);
186
187   if(CLS_ISCLASS(receiver->class_pointer))
188     {
189       /* receiver is an ordinary object */
190       assert(CLS_ISCLASS(receiver->class_pointer));
191
192       /* install instance methods table */
193       __objc_install_dispatch_table_for_class (receiver->class_pointer);
194
195       /* call +initialize -- this will in turn install the factory 
196          dispatch table if not already done :-) */
197       __objc_send_initialize(receiver->class_pointer);
198     }
199   else
200     {
201       /* receiver is a class object */
202       assert(CLS_ISCLASS((Class)receiver));
203       assert(CLS_ISMETA(receiver->class_pointer));
204
205       /* Install real dtable for factory methods */
206       __objc_install_dispatch_table_for_class (receiver->class_pointer);
207
208       if (strcmp (sel_get_name (op), "initialize"))
209         __objc_send_initialize((Class)receiver);
210       else
211         CLS_SETINITIALIZED((Class)receiver);
212     }
213   objc_mutex_unlock(__objc_runtime_mutex);
214
215 already_initialized:
216   
217   /* Get real method for this in newly installed dtable */
218   imp = get_imp(receiver->class_pointer, op);
219
220   args = __builtin_apply_args();
221   result = __builtin_apply((apply_t)imp, args, 96);
222   if (result)
223     __builtin_return (result);
224   else
225     return;
226   
227 }
228
229 /* Install dummy table for class which causes the first message to
230    that class (or instances hereof) to be initialized properly */
231 void __objc_install_premature_dtable(Class class)
232 {
233   assert(__objc_uninstalled_dtable);
234   class->dtable = __objc_uninstalled_dtable;
235 }   
236
237 /* Send +initialize to class if not already done */
238 static void __objc_send_initialize(Class class)
239 {
240   /* This *must* be a class object */
241   assert(CLS_ISCLASS(class));
242   assert(!CLS_ISMETA(class));
243
244   if (!CLS_ISINITIALIZED(class))
245     {
246       CLS_SETINITIALIZED(class);
247       CLS_SETINITIALIZED(class->class_pointer);
248       
249       if(class->super_class)
250         __objc_send_initialize(class->super_class);
251
252       {
253         SEL     op = sel_register_name ("initialize");
254         Class   tmpclass = class;
255         IMP     imp = 0;
256
257         while (!imp && tmpclass) {
258           MethodList_t method_list = tmpclass->class_pointer->methods;
259
260           while(!imp && method_list) {
261             int i;
262             Method_t method;
263
264             for (i=0;i<method_list->method_count;i++) {
265               method = &(method_list->method_list[i]);
266               if (method->method_name->sel_id == op->sel_id) {
267                 imp = method->method_imp;
268                 break;
269               }
270             }
271
272             method_list = method_list->method_next;
273
274           }
275
276           tmpclass = tmpclass->super_class;
277         }
278         if (imp)
279             (*imp)((id)class, op);
280                 
281       }
282     }
283 }  
284
285 /* Assumes that __objc_runtime_mutex is locked down. */
286 static void
287 __objc_install_dispatch_table_for_class (Class class)
288 {
289   Class super;
290   MethodList_t mlist;
291   int counter;
292
293   /* If the class has not yet had it's class links resolved, we must 
294      re-compute all class links */
295   if(!CLS_ISRESOLV(class))
296     __objc_resolve_class_links();
297
298   super = class->super_class;
299
300   if (super != 0 && (super->dtable == __objc_uninstalled_dtable))
301     __objc_install_dispatch_table_for_class (super);
302
303   /* Allocate dtable if necessary */
304   if (super == 0)
305     {
306       objc_mutex_lock(__objc_runtime_mutex);
307       class->dtable = sarray_new (__objc_selector_max_index, 0);
308       objc_mutex_unlock(__objc_runtime_mutex);
309     }
310   else
311     class->dtable = sarray_lazy_copy (super->dtable);
312
313   for (mlist = class->methods; mlist; mlist = mlist->method_next)
314     {
315       counter = mlist->method_count - 1;
316       while (counter >= 0)
317         {
318           Method_t method = &(mlist->method_list[counter]);
319           sarray_at_put_safe (class->dtable,
320                               (sidx) method->method_name->sel_id,
321                               method->method_imp);
322           counter -= 1;
323         }
324     }
325 }
326
327 void __objc_update_dispatch_table_for_class (Class class)
328 {
329   Class next;
330   struct sarray *arr;
331
332   /* not yet installed -- skip it */
333   if (class->dtable == __objc_uninstalled_dtable) 
334     return;
335
336   objc_mutex_lock(__objc_runtime_mutex);
337
338   arr = class->dtable;
339   __objc_install_premature_dtable (class); /* someone might require it... */
340   sarray_free (arr);                       /* release memory */
341
342   /* could have been lazy... */
343   __objc_install_dispatch_table_for_class (class); 
344
345   if (class->subclass_list)     /* Traverse subclasses */
346     for (next = class->subclass_list; next; next = next->sibling_class)
347       __objc_update_dispatch_table_for_class (next);
348
349   objc_mutex_unlock(__objc_runtime_mutex);
350 }
351
352
353 /* This function adds a method list to a class.  This function is
354    typically called by another function specific to the run-time.  As
355    such this function does not worry about thread safe issues.
356
357    This one is only called for categories. Class objects have their
358    methods installed right away, and their selectors are made into
359    SEL's by the function __objc_register_selectors_from_class. */ 
360 void
361 class_add_method_list (Class class, MethodList_t list)
362 {
363   int i;
364   static SEL initialize_sel = 0;                /* !T:SAFE2 */
365
366   if (!initialize_sel)
367     initialize_sel = sel_register_name ("initialize");
368
369   /* Passing of a linked list is not allowed.  Do multiple calls.  */
370   assert (!list->method_next);
371
372   /* Check for duplicates.  */
373   for (i = 0; i < list->method_count; ++i)
374     {
375       Method_t method = &list->method_list[i];
376
377       if (method->method_name)  /* Sometimes these are NULL */
378         {
379           /* This is where selector names are transmogrified to SEL's */
380           method->method_name = 
381             sel_register_typed_name ((const char*)method->method_name,
382                                      method->method_types);
383
384           if (search_for_method_in_list (class->methods, method->method_name)
385               && method->method_name->sel_id != initialize_sel->sel_id)
386             {
387               /* Duplication. Print a error message an change the method name
388                  to NULL. */
389               fprintf (stderr, "attempt to add a existing method: %s\n",
390                        sel_get_name(method->method_name));
391               method->method_name = 0;
392             }
393         }
394     }
395
396   /* Add the methods to the class's method list.  */
397   list->method_next = class->methods;
398   class->methods = list;
399 }
400
401
402 Method_t
403 class_get_instance_method(Class class, SEL op)
404 {
405   return search_for_method_in_hierarchy(class, op);
406 }
407
408 Method_t
409 class_get_class_method(MetaClass class, SEL op)
410 {
411   return search_for_method_in_hierarchy(class, op);
412 }
413
414
415 /* Search for a method starting from the current class up its hierarchy.
416    Return a pointer to the method's method structure if found.  NULL
417    otherwise. */   
418
419 static Method_t
420 search_for_method_in_hierarchy (Class cls, SEL sel)
421 {
422   Method_t method = NULL;
423   Class class;
424
425   if (! sel_is_mapped (sel))
426     return NULL;
427
428   /* Scan the method list of the class.  If the method isn't found in the
429      list then step to its super class. */
430   for (class = cls; ((! method) && class); class = class->super_class)
431     method = search_for_method_in_list (class->methods, sel);
432
433   return method;
434 }
435
436
437
438 /* Given a linked list of method and a method's name.  Search for the named
439    method's method structure.  Return a pointer to the method's method
440    structure if found.  NULL otherwise. */  
441 static Method_t
442 search_for_method_in_list (MethodList_t list, SEL op)
443 {
444   MethodList_t method_list = list;
445
446   if (! sel_is_mapped (op))
447     return NULL;
448
449   /* If not found then we'll search the list.  */
450   while (method_list)
451     {
452       int i;
453
454       /* Search the method list.  */
455       for (i = 0; i < method_list->method_count; ++i)
456         {
457           Method_t method = &method_list->method_list[i];
458
459           if (method->method_name)
460             if (method->method_name->sel_id == op->sel_id)
461               return method;
462         }
463
464       /* The method wasn't found.  Follow the link to the next list of
465          methods.  */
466       method_list = method_list->method_next;
467     }
468
469   return NULL;
470 }
471
472 static retval_t __objc_forward (id object, SEL sel, arglist_t args);
473
474 /* Forwarding pointers/integers through the normal registers */
475 static id
476 __objc_word_forward (id rcv, SEL op, ...)
477 {
478   void *args, *res;
479
480   args = __builtin_apply_args ();
481   res = __objc_forward (rcv, op, args);
482   if (res)
483     __builtin_return (res);
484   else
485     return res;
486 }
487
488 /* Specific routine for forwarding floats/double because of
489    architectural differences on some processors.  i386s for
490    example which uses a floating point stack versus general
491    registers for floating point numbers.  This forward routine 
492    makes sure that GCC restores the proper return values */
493 static double
494 __objc_double_forward (id rcv, SEL op, ...)
495 {
496   void *args, *res;
497
498   args = __builtin_apply_args ();
499   res = __objc_forward (rcv, op, args);
500   __builtin_return (res);
501 }
502
503 #if INVISIBLE_STRUCT_RETURN
504 static __big
505 #else
506 static id
507 #endif
508 __objc_block_forward (id rcv, SEL op, ...)
509 {
510   void *args, *res;
511
512   args = __builtin_apply_args ();
513   res = __objc_forward (rcv, op, args);
514   if (res)
515     __builtin_return (res);
516 }
517
518
519 /* This function is installed in the dispatch table for all methods which are
520    not implemented.  Thus, it is called when a selector is not recognized. */
521 static retval_t
522 __objc_forward (id object, SEL sel, arglist_t args)
523 {
524   IMP imp;
525   static SEL frwd_sel = 0;                      /* !T:SAFE2 */
526   SEL err_sel;
527
528   /* first try if the object understands forward:: */
529   if (!frwd_sel)
530     frwd_sel = sel_get_any_uid("forward::");
531
532   if (__objc_responds_to (object, frwd_sel))
533     {
534       imp = get_imp(object->class_pointer, frwd_sel);
535       return (*imp)(object, frwd_sel, sel, args);
536     }
537
538   /* If the object recognizes the doesNotRecognize: method then we're going
539      to send it. */
540   err_sel = sel_get_any_uid ("doesNotRecognize:");
541   if (__objc_responds_to (object, err_sel))
542     {
543       imp = get_imp (object->class_pointer, err_sel);
544       return (*imp) (object, err_sel, sel);
545     }
546   
547   /* The object doesn't recognize the method.  Check for responding to
548      error:.  If it does then sent it. */
549   {
550     size_t strlen (const char*);
551     char msg[256 + strlen ((const char*)sel_get_name (sel))
552              + strlen ((const char*)object->class_pointer->name)];
553
554     sprintf (msg, "(%s) %s does not recognize %s",
555              (CLS_ISMETA(object->class_pointer)
556               ? "class"
557               : "instance" ),
558              object->class_pointer->name, sel_get_name (sel));
559
560     err_sel = sel_get_any_uid ("error:");
561     if (__objc_responds_to (object, err_sel))
562       {
563         imp = get_imp (object->class_pointer, err_sel);
564         return (*imp) (object, sel_get_any_uid ("error:"), msg);
565       }
566
567     /* The object doesn't respond to doesNotRecognize: or error:;  Therefore,
568        a default action is taken. */
569     fprintf (stderr, "fatal: %s\n", msg);
570     abort ();
571   }
572 }
573
574 void __objc_print_dtable_stats()
575 {
576   int total = 0;
577
578   objc_mutex_lock(__objc_runtime_mutex);
579
580   printf("memory usage: (%s)\n",
581 #ifdef OBJC_SPARSE2
582          "2-level sparse arrays"
583 #else
584          "3-level sparse arrays"
585 #endif
586          );
587
588   printf("arrays: %d = %ld bytes\n", narrays, 
589          (int)narrays*sizeof(struct sarray));
590   total += narrays*sizeof(struct sarray);
591   printf("buckets: %d = %ld bytes\n", nbuckets, 
592          (int)nbuckets*sizeof(struct sbucket));
593   total += nbuckets*sizeof(struct sbucket);
594
595   printf("idxtables: %d = %ld bytes\n", idxsize, (int)idxsize*sizeof(void*));
596   total += idxsize*sizeof(void*);
597   printf("-----------------------------------\n");
598   printf("total: %d bytes\n", total);
599   printf("===================================\n");
600
601   objc_mutex_unlock(__objc_runtime_mutex);
602 }
603
604 /* Returns the dispatch table */
605 __inline__
606 struct sarray* 
607 objc_get_uninstalled_dtable()
608 {
609   return __objc_uninstalled_dtable;
610 }