]> gcc.gnu.org Git - gcc.git/blame - gcc/objc/sendmsg.c
Various fixes (freebsd, ncr, nextstep): See ChangeLog.
[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
a39d31bc 27#include "../tconfig.h"
c72fc2d9 28#include "runtime.h"
991d3e71 29#include "sarray.h"
772fa04a 30#include "encoding.h"
c72fc2d9 31
a39d31bc
KKT
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
c72fc2d9
TW
42/* The uninstalled dispatch table */
43struct sarray* __objc_uninstalled_dtable = 0;
c72fc2d9
TW
44
45/* Send +initialize to class */
d0b57512 46static void __objc_send_initialize(Class*);
c72fc2d9 47
d0b57512 48static void __objc_install_dispatch_table_for_class (Class*);
c72fc2d9
TW
49
50/* Forward declare some functions */
c72fc2d9 51static void __objc_init_install_dtable(id, SEL);
a39d31bc
KKT
52static id __objc_word_forward(id, SEL, ...);
53typedef struct { id many[8]; } __big;
54#if INVISIBLE_STRUCT_RETURN
55static __big
56#else
57static id
58#endif
59__objc_block_forward(id, SEL, ...);
d0b57512 60static Method_t search_for_method_in_hierarchy (Class* class, SEL sel);
c72fc2d9
TW
61static Method_t search_for_method_in_list(MethodList_t list, SEL op);
62id nil_method(id, SEL, ...);
63
64id
65nil_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
d0b57512 72get_imp (Class* class, SEL sel)
c72fc2d9 73{
a39d31bc
KKT
74 IMP impl;
75 void* res = sarray_get (class->dtable, (size_t) sel->sel_id);
c72fc2d9 76 if(res == __objc_init_install_dtable)
a39d31bc
KKT
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;
c72fc2d9
TW
90}
91
d408c5da
KKT
92__inline__ BOOL
93__objc_responds_to (id object, SEL sel)
94{
a39d31bc
KKT
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);
d408c5da
KKT
102}
103
c72fc2d9
TW
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
109objc_msg_lookup(id receiver, SEL op)
110{
a39d31bc 111 IMP result;
c72fc2d9 112 if(receiver)
a39d31bc
KKT
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 }
c72fc2d9
TW
125 else
126 return nil_method;
127}
128
129IMP
130objc_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
a39d31bc
KKT
138int method_get_sizeof_arguments (Method*);
139
c72fc2d9 140retval_t
772fa04a 141objc_msg_sendv(id object, SEL op, arglist_t arg_frame)
c72fc2d9 142{
772fa04a
KKT
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,
c72fc2d9 148 arg_frame,
772fa04a 149 method_get_sizeof_arguments (m));
c72fc2d9
TW
150}
151
152void __objc_init_dispatch_tables()
153{
c72fc2d9
TW
154 __objc_uninstalled_dtable
155 = sarray_new(200, __objc_init_install_dtable);
c72fc2d9
TW
156}
157
c72fc2d9
TW
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
162static void __objc_init_install_dtable(id receiver, SEL op)
163{
164 __label__ allready_initialized;
165 IMP imp;
166 void* args;
167 void* result;
168
c72fc2d9
TW
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 */
d0b57512 189 assert(CLS_ISCLASS((Class*)receiver));
c72fc2d9
TW
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);
a39d31bc
KKT
194
195 if (strcmp (sel_get_name (op), "initialize"))
d0b57512 196 __objc_send_initialize((Class*)receiver);
c72fc2d9 197 else
d0b57512 198 CLS_SETINITIALIZED((Class*)receiver);
c72fc2d9
TW
199 }
200
201allready_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);
a39d31bc
KKT
208 if (result)
209 __builtin_return (result);
210 else
211 return;
c72fc2d9
TW
212
213}
c72fc2d9
TW
214
215/* Install dummy table for class which causes the first message to
216 that class (or instances hereof) to be initialized properly */
d0b57512 217void __objc_install_premature_dtable(Class* class)
c72fc2d9 218{
c72fc2d9
TW
219 assert(__objc_uninstalled_dtable);
220 class->dtable = __objc_uninstalled_dtable;
c72fc2d9
TW
221}
222
223/* Send +initialize to class if not already done */
d0b57512 224static void __objc_send_initialize(Class* class)
c72fc2d9 225{
c72fc2d9
TW
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);
4be7cc98
RS
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
a39d31bc 253 if (method->method_name->sel_id == op->sel_id)
4be7cc98
RS
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 }
c72fc2d9
TW
262 }
263}
264
265static void
d0b57512 266__objc_install_dispatch_table_for_class (Class* class)
c72fc2d9 267{
d0b57512 268 Class* super;
c72fc2d9
TW
269 MethodList_t mlist;
270 int counter;
271
d408c5da
KKT
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
c72fc2d9
TW
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 {
a39d31bc 285 class->dtable = sarray_new (__objc_selector_max_index, 0);
c72fc2d9
TW
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]);
772fa04a 296 sarray_at_put_safe (class->dtable,
a39d31bc 297 (sidx) method->method_name->sel_id,
772fa04a 298 method->method_imp);
c72fc2d9
TW
299 counter -= 1;
300 }
301 }
c72fc2d9
TW
302}
303
d0b57512 304void __objc_update_dispatch_table_for_class (Class* class)
c72fc2d9 305{
d0b57512 306 Class* next;
c72fc2d9
TW
307
308 /* not yet installed -- skip it */
c72fc2d9 309 if (class->dtable == __objc_uninstalled_dtable)
c72fc2d9
TW
310 return;
311
772fa04a
KKT
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... */
c72fc2d9
TW
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);
772fa04a 319
c72fc2d9
TW
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. */
330void
d0b57512 331class_add_method_list (Class* class, MethodList_t list)
c72fc2d9
TW
332{
333 int i;
4be7cc98
RS
334 static SEL initialize_sel = 0;
335 if (!initialize_sel)
336 initialize_sel = sel_register_name ("initialize");
c72fc2d9
TW
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 */
a39d31bc
KKT
349 method->method_name =
350 sel_register_typed_name ((const char*)method->method_name,
351 method->method_types);
c72fc2d9 352
4be7cc98 353 if (search_for_method_in_list (class->methods, method->method_name)
a39d31bc 354 && method->method_name->sel_id != initialize_sel->sel_id)
c72fc2d9
TW
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
371Method_t
d0b57512 372class_get_instance_method(Class* class, SEL op)
c72fc2d9
TW
373{
374 return search_for_method_in_hierarchy(class, op);
375}
376
377Method_t
d0b57512 378class_get_class_method(MetaClass* class, SEL op)
c72fc2d9
TW
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
388static Method_t
d0b57512 389search_for_method_in_hierarchy (Class* cls, SEL sel)
c72fc2d9
TW
390{
391 Method_t method = NULL;
d0b57512 392 Class* class;
c72fc2d9
TW
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. */
410static Method_t
411search_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)
a39d31bc 429 if (method->method_name->sel_id == op->sel_id)
c72fc2d9
TW
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
a39d31bc
KKT
441static retval_t __objc_forward (id object, SEL sel, arglist_t args);
442
443static 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
457static __big
458#else
459static 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
c72fc2d9
TW
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. */
a39d31bc
KKT
474static retval_t
475__objc_forward (id object, SEL sel, arglist_t args)
c72fc2d9
TW
476{
477 IMP imp;
a39d31bc 478 static SEL frwd_sel = 0;
c72fc2d9
TW
479 SEL err_sel;
480
481 /* first try if the object understands forward:: */
a39d31bc
KKT
482 if (!frwd_sel)
483 frwd_sel = sel_get_any_uid("forward::");
484
485 if (__objc_responds_to (object, frwd_sel))
c72fc2d9 486 {
a39d31bc
KKT
487 imp = get_imp(object->class_pointer, frwd_sel);
488 return (*imp)(object, frwd_sel, sel, args);
c72fc2d9
TW
489 }
490
491 /* If the object recognizes the doesNotRecognize: method then we're going
492 to send it. */
a39d31bc
KKT
493 err_sel = sel_get_any_uid ("doesNotRecognize:");
494 if (__objc_responds_to (object, err_sel))
c72fc2d9 495 {
a39d31bc 496 imp = get_imp (object->class_pointer, err_sel);
c72fc2d9
TW
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 {
a39d31bc
KKT
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)];
c72fc2d9
TW
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
a39d31bc
KKT
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 }
c72fc2d9
TW
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
a7ab3794 527void __objc_print_dtable_stats()
c72fc2d9
TW
528{
529 int total = 0;
530 printf("memory usage: (%s)\n",
c72fc2d9
TW
531#ifdef OBJC_SPARSE2
532 "2-level sparse arrays"
533#else
534 "3-level sparse arrays"
c72fc2d9
TW
535#endif
536 );
537
a39d31bc 538 printf("arrays: %d = %ld bytes\n", narrays, (int)narrays*sizeof(struct sarray));
c72fc2d9 539 total += narrays*sizeof(struct sarray);
a39d31bc 540 printf("buckets: %d = %ld bytes\n", nbuckets, (int)nbuckets*sizeof(struct sbucket));
c72fc2d9
TW
541 total += nbuckets*sizeof(struct sbucket);
542
a39d31bc 543 printf("idxtables: %d = %ld bytes\n", idxsize, (int)idxsize*sizeof(void*));
c72fc2d9 544 total += idxsize*sizeof(void*);
c72fc2d9
TW
545 printf("-----------------------------------\n");
546 printf("total: %d bytes\n", total);
547 printf("===================================\n");
a7ab3794 548}
c72fc2d9 549
c72fc2d9
TW
550
551
This page took 0.205463 seconds and 5 git commands to generate.