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