1 /* GNU Objective C Runtime message lookup
2 Copyright (C) 1993 Free Software Foundation, Inc.
4 Author: Kresten Krab Thorup
6 This file is part of GNU CC.
8 GNU 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.
12 GNU 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
17 You 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. */
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. */
30 /* The uninstalled dispatch table */
31 struct sarray* __objc_uninstalled_dtable = 0;
33 /* Send +initialize to class */
34 static void __objc_send_initialize(Class*);
36 static void __objc_install_dispatch_table_for_class (Class*);
38 /* Forward declare some functions */
39 static void __objc_init_install_dtable(id, SEL);
40 static id __objc_missing_method(id, SEL, ...);
41 static Method_t search_for_method_in_hierarchy (Class* class, SEL sel);
42 static Method_t search_for_method_in_list(MethodList_t list, SEL op);
43 id nil_method(id, SEL, ...);
46 nil_method(id receiver, SEL op, ...)
51 /* Given a class and selector, return the selector's implementation. */
53 get_imp (Class* class, SEL sel)
55 void* res = sarray_get (class->dtable, (size_t) sel);
56 if(res == __objc_init_install_dtable)
57 __objc_install_dispatch_table_for_class (class);
58 return sarray_get (class->dtable, (size_t) sel);
62 __objc_responds_to (id object, SEL sel)
64 return get_imp (object->class_pointer, sel) != __objc_missing_method;
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
72 objc_msg_lookup(id receiver, SEL op)
75 return sarray_get(receiver->class_pointer->dtable, (sidx)op);
81 objc_msg_lookup_super (Super_t super, SEL sel)
84 return get_imp (super->class, sel);
90 objc_msg_sendv(id object, SEL op, size_t frame_size, arglist_t arg_frame)
92 #ifdef __objc_frame_receiver
93 __objc_frame_receiver(arg_frame) = object;
94 __objc_frame_selector(arg_frame) = op;
95 return __builtin_apply((apply_t)get_imp(object->class_pointer, op),
99 #warning performv:: will not work
101 (*_objc_error)(object, "objc_msg_sendv (performv::) not supported\n", nothing);
106 void __objc_init_dispatch_tables()
108 __objc_uninstalled_dtable
109 = sarray_new(200, __objc_init_install_dtable);
112 /* This one is a bit hairy. This function is installed in the
113 premature dispatch table, and thus called once for each class,
114 namely when the very first message is send to it. */
116 static void __objc_init_install_dtable(id receiver, SEL op)
118 __label__ allready_initialized;
123 /* This may happen, if the programmer has taken the address of a
124 method before the dtable was initialized... too bad for him! */
125 if(receiver->class_pointer->dtable != __objc_uninstalled_dtable)
126 goto allready_initialized;
128 if(CLS_ISCLASS(receiver->class_pointer))
130 /* receiver is an ordinary object */
131 assert(CLS_ISCLASS(receiver->class_pointer));
133 /* install instance methods table */
134 __objc_install_dispatch_table_for_class (receiver->class_pointer);
136 /* call +initialize -- this will in turn install the factory
137 dispatch table if not already done :-) */
138 __objc_send_initialize(receiver->class_pointer);
142 /* receiver is a class object */
143 assert(CLS_ISCLASS((Class*)receiver));
144 assert(CLS_ISMETA(receiver->class_pointer));
146 /* Install real dtable for factory methods */
147 __objc_install_dispatch_table_for_class (receiver->class_pointer);
149 if(op != sel_get_uid ("initialize"))
150 __objc_send_initialize((Class*)receiver);
152 CLS_SETINITIALIZED((Class*)receiver);
155 allready_initialized:
157 /* Get real method for this in newly installed dtable */
158 imp = get_imp(receiver->class_pointer, op);
160 args = __builtin_apply_args();
161 result = __builtin_apply((apply_t)imp, args, 96);
162 __builtin_return (result);
166 /* Install dummy table for class which causes the first message to
167 that class (or instances hereof) to be initialized properly */
168 void __objc_install_premature_dtable(Class* class)
170 assert(__objc_uninstalled_dtable);
171 class->dtable = __objc_uninstalled_dtable;
174 /* Send +initialize to class if not already done */
175 static void __objc_send_initialize(Class* class)
179 /* This *must* be a class object */
180 assert(CLS_ISCLASS(class));
181 assert(!CLS_ISMETA(class));
183 if (!CLS_ISINITIALIZED(class))
185 CLS_SETINITIALIZED(class);
186 CLS_SETINITIALIZED(class->class_pointer);
188 if(class->super_class)
189 __objc_send_initialize(class->super_class);
192 MethodList_t method_list = class->class_pointer->methods;
193 SEL op = sel_register_name ("initialize");
195 /* If not found then we'll search the list. */
200 /* Search the method list. */
201 for (i = 0; i < method_list->method_count; ++i)
203 Method_t method = &method_list->method_list[i];
206 if (method->method_name == op)
207 (*method->method_imp)((id) class, op);
210 /* The method wasn't found. Follow the link to the next list of
212 method_list = method_list->method_next;
219 __objc_install_dispatch_table_for_class (Class* class)
225 /* If the class has not yet had it's class links resolved, we must
226 re-compute all class links */
227 if(!CLS_ISRESOLV(class))
228 __objc_resolve_class_links();
230 super = class->super_class;
232 if (super != 0 && (super->dtable == __objc_uninstalled_dtable))
233 __objc_install_dispatch_table_for_class (super);
235 /* Allocate dtable if nessecary */
238 class->dtable = sarray_new (__objc_selector_max_index,
239 __objc_missing_method);
242 class->dtable = sarray_lazy_copy (super->dtable);
244 for (mlist = class->methods; mlist; mlist = mlist->method_next)
246 counter = mlist->method_count - 1;
249 Method_t method = &(mlist->method_list[counter]);
250 sarray_at_put (class->dtable,
251 (sidx) method->method_name,
258 void __objc_update_dispatch_table_for_class (Class* class)
263 /* not yet installed -- skip it */
264 if (class->dtable == __objc_uninstalled_dtable)
267 save = class->dtable;
268 __objc_install_premature_dtable (class);
272 if (class->subclass_list) /* Traverse subclasses */
273 for (next = class->subclass_list; next; next = next->sibling_class)
274 __objc_update_dispatch_table_for_class (next);
278 /* This function adds a method list to a class. This function is
279 typically called by another function specific to the run-time. As
280 such this function does not worry about thread safe issued.
282 This one is only called for categories. Class objects have their
283 methods installed rightaway, and their selectors are made into
284 SEL's by the function __objc_register_selectors_from_class. */
286 class_add_method_list (Class* class, MethodList_t list)
289 static SEL initialize_sel = 0;
291 initialize_sel = sel_register_name ("initialize");
293 /* Passing of a linked list is not allowed. Do multiple calls. */
294 assert (!list->method_next);
296 /* Check for duplicates. */
297 for (i = 0; i < list->method_count; ++i)
299 Method_t method = &list->method_list[i];
301 if (method->method_name) /* Sometimes these are NULL */
303 /* This is where selector names are transmogriffed to SEL's */
304 method->method_name = sel_register_name ((char*)method->method_name);
306 if (search_for_method_in_list (class->methods, method->method_name)
307 && method->method_name != initialize_sel)
309 /* Duplication. Print a error message an change the method name
311 fprintf (stderr, "attempt to add a existing method: %s\n",
312 sel_get_name(method->method_name));
313 method->method_name = 0;
318 /* Add the methods to the class's method list. */
319 list->method_next = class->methods;
320 class->methods = list;
325 class_get_instance_method(Class* class, SEL op)
327 return search_for_method_in_hierarchy(class, op);
331 class_get_class_method(MetaClass* class, SEL op)
333 return search_for_method_in_hierarchy(class, op);
337 /* Search for a method starting from the current class up its hierarchy.
338 Return a pointer to the method's method structure if found. NULL
342 search_for_method_in_hierarchy (Class* cls, SEL sel)
344 Method_t method = NULL;
347 if (! sel_is_mapped (sel))
350 /* Scan the method list of the class. If the method isn't found in the
351 list then step to its super class. */
352 for (class = cls; ((! method) && class); class = class->super_class)
353 method = search_for_method_in_list (class->methods, sel);
360 /* Given a linked list of method and a method's name. Search for the named
361 method's method structure. Return a pointer to the method's method
362 structure if found. NULL otherwise. */
364 search_for_method_in_list (MethodList_t list, SEL op)
366 MethodList_t method_list = list;
368 if (! sel_is_mapped (op))
371 /* If not found then we'll search the list. */
376 /* Search the method list. */
377 for (i = 0; i < method_list->method_count; ++i)
379 Method_t method = &method_list->method_list[i];
381 if (method->method_name)
382 if (method->method_name == op)
386 /* The method wasn't found. Follow the link to the next list of
388 method_list = method_list->method_next;
395 /* This fuction is installed in the dispatch table for all methods which are
396 not implemented. Thus, it is called when a selector is not recognized. */
398 __objc_missing_method (id object, SEL sel, ...)
404 /* first try if the object understands forward:: */
405 frwd_sel = sel_get_uid("forward::");
406 imp = get_imp(object->class_pointer, frwd_sel);
407 if(imp != __objc_missing_method)
409 void *result, *args = __builtin_apply_args();
410 result = (*imp)(object, frwd_sel, sel, args);
411 __builtin_return(result);
414 /* If the object recognizes the doesNotRecognize: method then we're going
416 err_sel = sel_get_uid ("doesNotRecognize:");
417 imp = get_imp (object->class_pointer, err_sel);
418 if (imp != __objc_missing_method)
420 return (*imp) (object, err_sel, sel);
423 /* The object doesn't recognize the method. Check for responding to
424 error:. If it does then sent it. */
426 char msg[256 + strlen ((char*)sel_get_name (sel))
427 + strlen ((char*)object->class_pointer->name)];
429 sprintf (msg, "(%s) %s does not recognize %s",
430 (CLS_ISMETA(object->class_pointer)
433 object->class_pointer->name, sel_get_name (sel));
435 err_sel = sel_get_uid ("error:");
436 imp = get_imp (object->class_pointer, err_sel);
437 if (imp != __objc_missing_method)
438 return (*imp) (object, sel_get_uid ("error:"), msg);
440 /* The object doesn't respond to doesNotRecognize: or error:; Therefore,
441 a default action is taken. */
442 fprintf (stderr, "fatal: %s\n", msg);
447 void __objc_print_dtable_stats()
450 printf("memory usage: (%s)\n",
452 "2-level sparse arrays"
454 "3-level sparse arrays"
458 printf("arrays: %d = %d bytes\n", narrays, narrays*sizeof(struct sarray));
459 total += narrays*sizeof(struct sarray);
460 printf("buckets: %d = %d bytes\n", nbuckets, nbuckets*sizeof(struct sbucket));
461 total += nbuckets*sizeof(struct sbucket);
463 printf("idxtables: %d = %d bytes\n", idxsize, idxsize*sizeof(void*));
464 total += idxsize*sizeof(void*);
465 printf("-----------------------------------\n");
466 printf("total: %d bytes\n", total);
467 printf("===================================\n");