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