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