1 /* GNU Objective C Runtime message lookup
2 Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
3 Contributed by Kresten Krab Thorup
5 This file is part of GNU CC.
7 GNU CC is free software; you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 2, or (at your option) any later version.
11 GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16 You should have received a copy of the GNU General Public License along with
17 GNU CC; see the file COPYING. If not, write to the Free Software
18 Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, 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. */
27 #include "../tconfig.h"
32 /* this is how we hack STRUCT_VALUE to be 1 or 0 */
33 #define gen_rtx(args...) 1
36 #if !defined(STRUCT_VALUE) || STRUCT_VALUE == 0
37 #define INVISIBLE_STRUCT_RETURN 1
39 #define INVISIBLE_STRUCT_RETURN 0
42 /* The uninstalled dispatch table */
43 struct sarray* __objc_uninstalled_dtable = 0; /* !T:MUTEX */
45 /* Send +initialize to class */
46 static void __objc_send_initialize(Class);
48 static void __objc_install_dispatch_table_for_class (Class);
50 /* Forward declare some functions */
51 static void __objc_init_install_dtable(id, SEL);
53 /* Various forwarding functions that are used based upon the
54 return type for the selector.
55 __objc_block_forward for structures.
56 __objc_double_forward for floats/doubles.
57 __objc_word_forward for pointers or types that fit in registers.
59 static double __objc_double_forward(id, SEL, ...);
60 static id __objc_word_forward(id, SEL, ...);
61 typedef struct { id many[8]; } __big;
62 #if INVISIBLE_STRUCT_RETURN
67 __objc_block_forward(id, SEL, ...);
68 static Method_t search_for_method_in_hierarchy (Class class, SEL sel);
69 Method_t search_for_method_in_list(MethodList_t list, SEL op);
70 id nil_method(id, SEL, ...);
72 /* Given a selector, return the proper forwarding implementation. */
75 __objc_get_forward_imp (SEL sel)
77 const char *t = sel->sel_types;
79 if (t && (*t == '[' || *t == '(' || *t == '{'))
80 return (IMP)__objc_block_forward;
81 else if (t && (*t == 'f' || *t == 'd'))
82 return (IMP)__objc_double_forward;
84 return (IMP)__objc_word_forward;
87 /* Given a class and selector, return the selector's implementation. */
90 get_imp (Class class, SEL sel)
93 void* res = sarray_get (class->dtable, (size_t) sel->sel_id);
96 /* Not a valid method */
97 if(class->dtable == __objc_uninstalled_dtable)
99 /* The dispatch table needs to be installed. */
100 objc_mutex_lock(__objc_runtime_mutex);
101 __objc_install_dispatch_table_for_class (class);
102 objc_mutex_unlock(__objc_runtime_mutex);
103 /* Call ourselves with the installed dispatch table
104 and get the real method */
105 res = get_imp(class, sel);
109 /* The dispatch table has been installed so the
110 method just doesn't exist for the class.
111 Return the forwarding implementation. */
112 res = __objc_get_forward_imp(sel);
118 /* Query if an object can respond to a selector, returns YES if the
119 object implements the selector otherwise NO. Does not check if the
120 method can be forwarded. */
123 __objc_responds_to (id object, SEL sel)
127 /* Install dispatch table if need be */
128 if (object->class_pointer->dtable == __objc_uninstalled_dtable)
130 objc_mutex_lock(__objc_runtime_mutex);
131 __objc_install_dispatch_table_for_class (object->class_pointer);
132 objc_mutex_unlock(__objc_runtime_mutex);
135 /* Get the method from the dispatch table */
136 res = sarray_get (object->class_pointer->dtable, (size_t) sel->sel_id);
140 /* This is the lookup function. All entries in the table are either a
141 valid method *or* zero. If zero then either the dispatch table
142 needs to be installed or it doesn't exist and forwarding is attempted. */
145 objc_msg_lookup(id receiver, SEL op)
150 result = sarray_get(receiver->class_pointer->dtable, (sidx)op->sel_id);
153 /* Not a valid method */
154 if(receiver->class_pointer->dtable == __objc_uninstalled_dtable)
156 /* The dispatch table needs to be installed.
157 This happens on the very first method call to the class. */
158 __objc_init_install_dtable(receiver, op);
160 /* Get real method for this in newly installed dtable */
161 result = get_imp(receiver->class_pointer, op);
165 /* The dispatch table has been installed so the
166 method just doesn't exist for the class.
167 Attempt to forward the method. */
168 result = __objc_get_forward_imp(op);
178 objc_msg_lookup_super (Super_t super, SEL sel)
181 return get_imp (super->class, sel);
186 int method_get_sizeof_arguments (Method*);
189 objc_msg_sendv(id object, SEL op, arglist_t arg_frame)
191 Method* m = class_get_instance_method(object->class_pointer, op);
193 *((id*)method_get_first_argument (m, arg_frame, &type)) = object;
194 *((SEL*)method_get_next_argument (arg_frame, &type)) = op;
195 return __builtin_apply((apply_t)m->method_imp,
197 method_get_sizeof_arguments (m));
201 __objc_init_dispatch_tables()
203 __objc_uninstalled_dtable
204 = sarray_new(200, 0);
207 /* This function is called by objc_msg_lookup when the
208 dispatch table needs to be installed; thus it is called once
209 for each class, namely when the very first message is sent to it. */
211 __objc_init_install_dtable(id receiver, SEL op)
213 /* This may happen, if the programmer has taken the address of a
214 method before the dtable was initialized... too bad for him! */
215 if(receiver->class_pointer->dtable != __objc_uninstalled_dtable)
218 objc_mutex_lock(__objc_runtime_mutex);
220 if(CLS_ISCLASS(receiver->class_pointer))
222 /* receiver is an ordinary object */
223 assert(CLS_ISCLASS(receiver->class_pointer));
225 /* install instance methods table */
226 __objc_install_dispatch_table_for_class (receiver->class_pointer);
228 /* call +initialize -- this will in turn install the factory
229 dispatch table if not already done :-) */
230 __objc_send_initialize(receiver->class_pointer);
234 /* receiver is a class object */
235 assert(CLS_ISCLASS((Class)receiver));
236 assert(CLS_ISMETA(receiver->class_pointer));
238 /* Install real dtable for factory methods */
239 __objc_install_dispatch_table_for_class (receiver->class_pointer);
241 if (strcmp (sel_get_name (op), "initialize"))
242 __objc_send_initialize((Class)receiver);
244 CLS_SETINITIALIZED((Class)receiver);
246 objc_mutex_unlock(__objc_runtime_mutex);
249 /* Install dummy table for class which causes the first message to
250 that class (or instances hereof) to be initialized properly */
252 __objc_install_premature_dtable(Class class)
254 assert(__objc_uninstalled_dtable);
255 class->dtable = __objc_uninstalled_dtable;
258 /* Send +initialize to class if not already done */
260 __objc_send_initialize(Class class)
262 /* This *must* be a class object */
263 assert(CLS_ISCLASS(class));
264 assert(!CLS_ISMETA(class));
266 if (!CLS_ISINITIALIZED(class))
268 CLS_SETINITIALIZED(class);
269 CLS_SETINITIALIZED(class->class_pointer);
271 if(class->super_class)
272 __objc_send_initialize(class->super_class);
275 SEL op = sel_register_name ("initialize");
276 Class tmpclass = class;
279 while (!imp && tmpclass) {
280 MethodList_t method_list = tmpclass->class_pointer->methods;
282 while(!imp && method_list) {
286 for (i=0;i<method_list->method_count;i++) {
287 method = &(method_list->method_list[i]);
288 if (method->method_name
289 && method->method_name->sel_id == op->sel_id) {
290 imp = method->method_imp;
295 method_list = method_list->method_next;
299 tmpclass = tmpclass->super_class;
302 (*imp)((id)class, op);
308 /* Walk on the methods list of class and install the methods in the reverse
309 order of the lists. Since methods added by categories are before the methods
310 of class in the methods list, this allows categories to substitute methods
311 declared in class. However if more than one category replace the same method
312 nothing is guarranteed about what method will be used.
313 Assumes that __objc_runtime_mutex is locked down. */
315 __objc_install_methods_in_dtable (Class class, MethodList_t method_list)
322 if (method_list->method_next)
323 __objc_install_methods_in_dtable (class, method_list->method_next);
325 for (i = 0; i < method_list->method_count; i++)
327 Method_t method = &(method_list->method_list[i]);
328 sarray_at_put_safe (class->dtable,
329 (sidx) method->method_name->sel_id,
334 /* Assumes that __objc_runtime_mutex is locked down. */
336 __objc_install_dispatch_table_for_class (Class class)
341 /* If the class has not yet had it's class links resolved, we must
342 re-compute all class links */
343 if(!CLS_ISRESOLV(class))
344 __objc_resolve_class_links();
346 super = class->super_class;
348 if (super != 0 && (super->dtable == __objc_uninstalled_dtable))
349 __objc_install_dispatch_table_for_class (super);
351 /* Allocate dtable if necessary */
354 objc_mutex_lock(__objc_runtime_mutex);
355 class->dtable = sarray_new (__objc_selector_max_index, 0);
356 objc_mutex_unlock(__objc_runtime_mutex);
359 class->dtable = sarray_lazy_copy (super->dtable);
361 __objc_install_methods_in_dtable (class, class->methods);
365 __objc_update_dispatch_table_for_class (Class class)
370 /* not yet installed -- skip it */
371 if (class->dtable == __objc_uninstalled_dtable)
374 objc_mutex_lock(__objc_runtime_mutex);
377 __objc_install_premature_dtable (class); /* someone might require it... */
378 sarray_free (arr); /* release memory */
380 /* could have been lazy... */
381 __objc_install_dispatch_table_for_class (class);
383 if (class->subclass_list) /* Traverse subclasses */
384 for (next = class->subclass_list; next; next = next->sibling_class)
385 __objc_update_dispatch_table_for_class (next);
387 objc_mutex_unlock(__objc_runtime_mutex);
391 /* This function adds a method list to a class. This function is
392 typically called by another function specific to the run-time. As
393 such this function does not worry about thread safe issues.
395 This one is only called for categories. Class objects have their
396 methods installed right away, and their selectors are made into
397 SEL's by the function __objc_register_selectors_from_class. */
399 class_add_method_list (Class class, MethodList_t list)
403 /* Passing of a linked list is not allowed. Do multiple calls. */
404 assert (!list->method_next);
406 /* Check for duplicates. */
407 for (i = 0; i < list->method_count; ++i)
409 Method_t method = &list->method_list[i];
411 if (method->method_name) /* Sometimes these are NULL */
413 /* This is where selector names are transmogrified to SEL's */
414 method->method_name =
415 sel_register_typed_name ((const char*)method->method_name,
416 method->method_types);
420 /* Add the methods to the class's method list. */
421 list->method_next = class->methods;
422 class->methods = list;
424 /* Update the dispatch table of class */
425 __objc_update_dispatch_table_for_class (class);
429 class_get_instance_method(Class class, SEL op)
431 return search_for_method_in_hierarchy(class, op);
435 class_get_class_method(MetaClass class, SEL op)
437 return search_for_method_in_hierarchy(class, op);
441 /* Search for a method starting from the current class up its hierarchy.
442 Return a pointer to the method's method structure if found. NULL
446 search_for_method_in_hierarchy (Class cls, SEL sel)
448 Method_t method = NULL;
451 if (! sel_is_mapped (sel))
454 /* Scan the method list of the class. If the method isn't found in the
455 list then step to its super class. */
456 for (class = cls; ((! method) && class); class = class->super_class)
457 method = search_for_method_in_list (class->methods, sel);
464 /* Given a linked list of method and a method's name. Search for the named
465 method's method structure. Return a pointer to the method's method
466 structure if found. NULL otherwise. */
468 search_for_method_in_list (MethodList_t list, SEL op)
470 MethodList_t method_list = list;
472 if (! sel_is_mapped (op))
475 /* If not found then we'll search the list. */
480 /* Search the method list. */
481 for (i = 0; i < method_list->method_count; ++i)
483 Method_t method = &method_list->method_list[i];
485 if (method->method_name)
486 if (method->method_name->sel_id == op->sel_id)
490 /* The method wasn't found. Follow the link to the next list of
492 method_list = method_list->method_next;
498 static retval_t __objc_forward (id object, SEL sel, arglist_t args);
500 /* Forwarding pointers/integers through the normal registers */
502 __objc_word_forward (id rcv, SEL op, ...)
506 args = __builtin_apply_args ();
507 res = __objc_forward (rcv, op, args);
509 __builtin_return (res);
514 /* Specific routine for forwarding floats/double because of
515 architectural differences on some processors. i386s for
516 example which uses a floating point stack versus general
517 registers for floating point numbers. This forward routine
518 makes sure that GCC restores the proper return values */
520 __objc_double_forward (id rcv, SEL op, ...)
524 args = __builtin_apply_args ();
525 res = __objc_forward (rcv, op, args);
526 __builtin_return (res);
529 #if INVISIBLE_STRUCT_RETURN
534 __objc_block_forward (id rcv, SEL op, ...)
538 args = __builtin_apply_args ();
539 res = __objc_forward (rcv, op, args);
541 __builtin_return (res);
545 /* This function is installed in the dispatch table for all methods which are
546 not implemented. Thus, it is called when a selector is not recognized. */
548 __objc_forward (id object, SEL sel, arglist_t args)
551 static SEL frwd_sel = 0; /* !T:SAFE2 */
554 /* first try if the object understands forward:: */
556 frwd_sel = sel_get_any_uid("forward::");
558 if (__objc_responds_to (object, frwd_sel))
560 imp = get_imp(object->class_pointer, frwd_sel);
561 return (*imp)(object, frwd_sel, sel, args);
564 /* If the object recognizes the doesNotRecognize: method then we're going
566 err_sel = sel_get_any_uid ("doesNotRecognize:");
567 if (__objc_responds_to (object, err_sel))
569 imp = get_imp (object->class_pointer, err_sel);
570 return (*imp) (object, err_sel, sel);
573 /* The object doesn't recognize the method. Check for responding to
574 error:. If it does then sent it. */
576 size_t strlen (const char*);
577 char msg[256 + strlen ((const char*)sel_get_name (sel))
578 + strlen ((const char*)object->class_pointer->name)];
580 sprintf (msg, "(%s) %s does not recognize %s",
581 (CLS_ISMETA(object->class_pointer)
584 object->class_pointer->name, sel_get_name (sel));
586 err_sel = sel_get_any_uid ("error:");
587 if (__objc_responds_to (object, err_sel))
589 imp = get_imp (object->class_pointer, err_sel);
590 return (*imp) (object, sel_get_any_uid ("error:"), msg);
593 /* The object doesn't respond to doesNotRecognize: or error:; Therefore,
594 a default action is taken. */
595 objc_error (object, OBJC_ERR_UNIMPLEMENTED, "%s\n", msg);
600 __objc_print_dtable_stats()
604 objc_mutex_lock(__objc_runtime_mutex);
606 printf("memory usage: (%s)\n",
608 "2-level sparse arrays"
610 "3-level sparse arrays"
614 printf("arrays: %d = %ld bytes\n", narrays,
615 (int)narrays*sizeof(struct sarray));
616 total += narrays*sizeof(struct sarray);
617 printf("buckets: %d = %ld bytes\n", nbuckets,
618 (int)nbuckets*sizeof(struct sbucket));
619 total += nbuckets*sizeof(struct sbucket);
621 printf("idxtables: %d = %ld bytes\n", idxsize, (int)idxsize*sizeof(void*));
622 total += idxsize*sizeof(void*);
623 printf("-----------------------------------\n");
624 printf("total: %d bytes\n", total);
625 printf("===================================\n");
627 objc_mutex_unlock(__objc_runtime_mutex);
630 /* Returns the uninstalled dispatch table indicator.
631 If a class' dispatch table points to __objc_uninstalled_dtable
632 then that means it needs its dispatch table to be installed. */
635 objc_get_uninstalled_dtable()
637 return __objc_uninstalled_dtable;