OSDN Git Service

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