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