OSDN Git Service

Added fixup for __STDC__ == 0 and __STDC__ == 1
[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 "runtime.h"
28 #include "sarray.h"
29
30 /* The uninstalled dispatch table */
31 struct sarray* __objc_uninstalled_dtable = 0;
32
33 /* Send +initialize to class */
34 static void __objc_send_initialize(Class*);
35
36 static void __objc_install_dispatch_table_for_class (Class*);
37
38 /* Forward declare some functions */
39 static void __objc_init_install_dtable(id, SEL);
40 static id __objc_missing_method(id, SEL, ...);
41 static Method_t search_for_method_in_hierarchy (Class* class, SEL sel);
42 static Method_t search_for_method_in_list(MethodList_t list, SEL op);
43 id nil_method(id, SEL, ...);
44
45 id
46 nil_method(id receiver, SEL op, ...)
47 {
48   return receiver;
49 }
50
51 /* Given a class and selector, return the selector's implementation.  */
52 __inline__ IMP
53 get_imp (Class* class, SEL sel)
54 {
55   void* res = sarray_get (class->dtable, (size_t) sel);
56   if(res == __objc_init_install_dtable)
57     __objc_install_dispatch_table_for_class (class);
58   return sarray_get (class->dtable, (size_t) sel);
59 }
60
61 __inline__ BOOL
62 __objc_responds_to (id object, SEL sel)
63 {
64   return get_imp (object->class_pointer, sel) != __objc_missing_method;
65 }
66
67 /* This is the lookup function.  All entries in the table are either a 
68    valid method *or* one of `__objc_missing_method' which calls
69    forward:: etc, or `__objc_init_install_dtable' which installs the
70    real dtable */
71 __inline__ IMP
72 objc_msg_lookup(id receiver, SEL op)
73 {
74   if(receiver)
75     return sarray_get(receiver->class_pointer->dtable, (sidx)op);
76   else
77     return nil_method;
78 }
79
80 IMP
81 objc_msg_lookup_super (Super_t super, SEL sel)
82 {
83   if (super->self)
84     return get_imp (super->class, sel);
85   else
86     return nil_method;
87 }
88
89 retval_t
90 objc_msg_sendv(id object, SEL op, size_t frame_size, arglist_t arg_frame)
91 {
92 #ifdef __objc_frame_receiver
93   __objc_frame_receiver(arg_frame) = object;
94   __objc_frame_selector(arg_frame) = op;
95   return __builtin_apply((apply_t)get_imp(object->class_pointer, op),
96                          arg_frame,
97                          frame_size);
98 #else
99 #warning performv:: will not work
100   va_list nothing;
101   (*_objc_error)(object, "objc_msg_sendv (performv::) not supported\n", nothing);
102   return 0;
103 #endif
104 }
105
106 void __objc_init_dispatch_tables()
107 {
108   __objc_uninstalled_dtable
109     = sarray_new(200, __objc_init_install_dtable);
110 }
111
112 /* This one is a bit hairy.  This function is installed in the 
113    premature dispatch table, and thus called once for each class,
114    namely when the very first message is send to it.  */
115
116 static void __objc_init_install_dtable(id receiver, SEL op)
117 {
118   __label__ allready_initialized;
119   IMP imp;
120   void* args;
121   void* result;
122
123   /* This may happen, if the programmer has taken the address of a 
124      method before the dtable was initialized... too bad for him! */
125   if(receiver->class_pointer->dtable != __objc_uninstalled_dtable)
126     goto allready_initialized;
127
128   if(CLS_ISCLASS(receiver->class_pointer))
129     {
130       /* receiver is an ordinary object */
131       assert(CLS_ISCLASS(receiver->class_pointer));
132
133       /* install instance methods table */
134       __objc_install_dispatch_table_for_class (receiver->class_pointer);
135
136       /* call +initialize -- this will in turn install the factory 
137          dispatch table if not already done :-) */
138       __objc_send_initialize(receiver->class_pointer);
139     }
140   else
141     {
142       /* receiver is a class object */
143       assert(CLS_ISCLASS((Class*)receiver));
144       assert(CLS_ISMETA(receiver->class_pointer));
145
146       /* Install real dtable for factory methods */
147       __objc_install_dispatch_table_for_class (receiver->class_pointer);
148       
149       if(op != sel_get_uid ("initialize"))
150         __objc_send_initialize((Class*)receiver);
151       else
152         CLS_SETINITIALIZED((Class*)receiver);
153     }
154
155 allready_initialized:
156   
157   /* Get real method for this in newly installed dtable */
158   imp = get_imp(receiver->class_pointer, op);
159
160   args = __builtin_apply_args();
161   result = __builtin_apply((apply_t)imp, args, 96);
162   __builtin_return (result);
163   
164 }
165
166 /* Install dummy table for class which causes the first message to
167    that class (or instances hereof) to be initialized properly */
168 void __objc_install_premature_dtable(Class* class)
169 {
170   assert(__objc_uninstalled_dtable);
171   class->dtable = __objc_uninstalled_dtable;
172 }   
173
174 /* Send +initialize to class if not already done */
175 static void __objc_send_initialize(Class* class)
176 {
177   Method_t m;
178
179   /* This *must* be a class object */
180   assert(CLS_ISCLASS(class));
181   assert(!CLS_ISMETA(class));
182
183   if (!CLS_ISINITIALIZED(class))
184     {
185       CLS_SETINITIALIZED(class);
186       CLS_SETINITIALIZED(class->class_pointer);
187       
188       if(class->super_class)
189         __objc_send_initialize(class->super_class);
190
191       {
192         MethodList_t method_list = class->class_pointer->methods;
193         SEL op = sel_register_name ("initialize");
194
195         /* If not found then we'll search the list.  */
196         while (method_list)
197           {
198             int i;
199
200             /* Search the method list.  */
201             for (i = 0; i < method_list->method_count; ++i)
202               {
203                 Method_t method = &method_list->method_list[i];
204                 
205                 
206                 if (method->method_name == op)
207                   (*method->method_imp)((id) class, op);
208               }
209
210             /* The method wasn't found.  Follow the link to the next list of
211                methods.  */
212             method_list = method_list->method_next;
213           }
214       }
215     }
216 }  
217
218 static void
219 __objc_install_dispatch_table_for_class (Class* class)
220 {
221   Class* super;
222   MethodList_t mlist;
223   int counter;
224
225   /* If the class has not yet had it's class links resolved, we must 
226      re-compute all class links */
227   if(!CLS_ISRESOLV(class))
228     __objc_resolve_class_links();
229
230   super = class->super_class;
231
232   if (super != 0 && (super->dtable == __objc_uninstalled_dtable))
233     __objc_install_dispatch_table_for_class (super);
234
235   /* Allocate dtable if nessecary */
236   if (super == 0)
237     {
238       class->dtable = sarray_new (__objc_selector_max_index,
239                                   __objc_missing_method);
240     }
241   else
242     class->dtable = sarray_lazy_copy (super->dtable);
243
244   for (mlist = class->methods; mlist; mlist = mlist->method_next)
245     {
246       counter = mlist->method_count - 1;
247       while (counter >= 0)
248         {
249           Method_t method = &(mlist->method_list[counter]);
250           sarray_at_put (class->dtable,
251                          (sidx) method->method_name,
252                          method->method_imp);
253           counter -= 1;
254         }
255     }
256 }
257
258 void __objc_update_dispatch_table_for_class (Class* class)
259 {
260   Class* next;
261   struct sarray* save;
262
263   /* not yet installed -- skip it */
264   if (class->dtable == __objc_uninstalled_dtable) 
265     return;
266
267   save = class->dtable;
268   __objc_install_premature_dtable (class);
269   sarray_free (save);
270
271
272   if (class->subclass_list)     /* Traverse subclasses */
273     for (next = class->subclass_list; next; next = next->sibling_class)
274       __objc_update_dispatch_table_for_class (next);
275 }
276
277
278 /* This function adds a method list to a class.  This function is
279    typically called by another function specific to the run-time.  As
280    such this function does not worry about thread safe issued.
281
282    This one is only called for categories. Class objects have their
283    methods installed rightaway, and their selectors are made into
284    SEL's by the function __objc_register_selectors_from_class. */ 
285 void
286 class_add_method_list (Class* class, MethodList_t list)
287 {
288   int i;
289   static SEL initialize_sel = 0;
290   if (!initialize_sel)
291     initialize_sel = sel_register_name ("initialize");
292
293   /* Passing of a linked list is not allowed.  Do multiple calls.  */
294   assert (!list->method_next);
295
296   /* Check for duplicates.  */
297   for (i = 0; i < list->method_count; ++i)
298     {
299       Method_t method = &list->method_list[i];
300
301       if (method->method_name)  /* Sometimes these are NULL */
302         {
303           /* This is where selector names are transmogriffed to SEL's */
304           method->method_name = sel_register_name ((char*)method->method_name);
305
306           if (search_for_method_in_list (class->methods, method->method_name)
307               && method->method_name != initialize_sel)
308             {
309               /* Duplication. Print a error message an change the method name
310                  to NULL. */
311               fprintf (stderr, "attempt to add a existing method: %s\n",
312                        sel_get_name(method->method_name));
313               method->method_name = 0;
314             }
315         }
316     }
317
318   /* Add the methods to the class's method list.  */
319   list->method_next = class->methods;
320   class->methods = list;
321 }
322
323
324 Method_t
325 class_get_instance_method(Class* class, SEL op)
326 {
327   return search_for_method_in_hierarchy(class, op);
328 }
329
330 Method_t
331 class_get_class_method(MetaClass* class, SEL op)
332 {
333   return search_for_method_in_hierarchy(class, op);
334 }
335
336
337 /* Search for a method starting from the current class up its hierarchy.
338    Return a pointer to the method's method structure if found.  NULL
339    otherwise. */   
340
341 static Method_t
342 search_for_method_in_hierarchy (Class* cls, SEL sel)
343 {
344   Method_t method = NULL;
345   Class* class;
346
347   if (! sel_is_mapped (sel))
348     return NULL;
349
350   /* Scan the method list of the class.  If the method isn't found in the
351      list then step to its super class. */
352   for (class = cls; ((! method) && class); class = class->super_class)
353     method = search_for_method_in_list (class->methods, sel);
354
355   return method;
356 }
357
358
359
360 /* Given a linked list of method and a method's name.  Search for the named
361    method's method structure.  Return a pointer to the method's method
362    structure if found.  NULL otherwise. */  
363 static Method_t
364 search_for_method_in_list (MethodList_t list, SEL op)
365 {
366   MethodList_t method_list = list;
367
368   if (! sel_is_mapped (op))
369     return NULL;
370
371   /* If not found then we'll search the list.  */
372   while (method_list)
373     {
374       int i;
375
376       /* Search the method list.  */
377       for (i = 0; i < method_list->method_count; ++i)
378         {
379           Method_t method = &method_list->method_list[i];
380
381           if (method->method_name)
382             if (method->method_name == op)
383               return method;
384         }
385
386       /* The method wasn't found.  Follow the link to the next list of
387          methods.  */
388       method_list = method_list->method_next;
389     }
390
391   return NULL;
392 }
393
394
395 /* This fuction is installed in the dispatch table for all methods which are
396    not implemented.  Thus, it is called when a selector is not recognized. */
397 static id
398 __objc_missing_method (id object, SEL sel, ...)
399 {
400   IMP imp;
401   SEL frwd_sel;
402   SEL err_sel;
403
404   /* first try if the object understands forward:: */
405   frwd_sel = sel_get_uid("forward::");
406   imp = get_imp(object->class_pointer, frwd_sel);
407   if(imp != __objc_missing_method)
408     {
409       void *result, *args = __builtin_apply_args();
410       result = (*imp)(object, frwd_sel, sel, args);
411       __builtin_return(result);
412     }
413
414   /* If the object recognizes the doesNotRecognize: method then we're going
415      to send it. */
416   err_sel = sel_get_uid ("doesNotRecognize:");
417   imp = get_imp (object->class_pointer, err_sel);
418   if (imp != __objc_missing_method)
419     {
420       return (*imp) (object, err_sel, sel);
421     }
422   
423   /* The object doesn't recognize the method.  Check for responding to
424      error:.  If it does then sent it. */
425   {
426     char msg[256 + strlen ((char*)sel_get_name (sel))
427              + strlen ((char*)object->class_pointer->name)];
428
429     sprintf (msg, "(%s) %s does not recognize %s",
430              (CLS_ISMETA(object->class_pointer)
431               ? "class"
432               : "instance" ),
433              object->class_pointer->name, sel_get_name (sel));
434
435     err_sel = sel_get_uid ("error:");
436     imp = get_imp (object->class_pointer, err_sel);
437     if (imp != __objc_missing_method)
438       return (*imp) (object, sel_get_uid ("error:"), msg);
439
440     /* The object doesn't respond to doesNotRecognize: or error:;  Therefore,
441        a default action is taken. */
442     fprintf (stderr, "fatal: %s\n", msg);
443     abort ();
444   }
445 }
446
447 void __objc_print_dtable_stats()
448 {
449   int total = 0;
450   printf("memory usage: (%s)\n",
451 #ifdef OBJC_SPARSE2
452          "2-level sparse arrays"
453 #else
454          "3-level sparse arrays"
455 #endif
456          );
457
458   printf("arrays: %d = %d bytes\n", narrays, narrays*sizeof(struct sarray));
459   total += narrays*sizeof(struct sarray);
460   printf("buckets: %d = %d bytes\n", nbuckets, nbuckets*sizeof(struct sbucket));
461   total += nbuckets*sizeof(struct sbucket);
462
463   printf("idxtables: %d = %d bytes\n", idxsize, idxsize*sizeof(void*));
464   total += idxsize*sizeof(void*);
465   printf("-----------------------------------\n");
466   printf("total: %d bytes\n", total);
467   printf("===================================\n");
468 }
469
470
471