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
100 (*_objc_error
)(object
, "objc_msg_sendv (performv::) not supported\n", 0);
105 void __objc_init_dispatch_tables()
107 __objc_uninstalled_dtable
108 = sarray_new(200, __objc_init_install_dtable
);
111 /* This one is a bit hairy. This function is installed in the
112 premature dispatch table, and thus called once for each class,
113 namely when the very first message is send to it. */
115 static void __objc_init_install_dtable(id receiver
, SEL op
)
117 __label__ allready_initialized
;
122 /* This may happen, if the programmer has taken the address of a
123 method before the dtable was initialized... too bad for him! */
124 if(receiver
->class_pointer
->dtable
!= __objc_uninstalled_dtable
)
125 goto allready_initialized
;
127 if(CLS_ISCLASS(receiver
->class_pointer
))
129 /* receiver is an ordinary object */
130 assert(CLS_ISCLASS(receiver
->class_pointer
));
132 /* install instance methods table */
133 __objc_install_dispatch_table_for_class (receiver
->class_pointer
);
135 /* call +initialize -- this will in turn install the factory
136 dispatch table if not already done :-) */
137 __objc_send_initialize(receiver
->class_pointer
);
141 /* receiver is a class object */
142 assert(CLS_ISCLASS((Class
*)receiver
));
143 assert(CLS_ISMETA(receiver
->class_pointer
));
145 /* Install real dtable for factory methods */
146 __objc_install_dispatch_table_for_class (receiver
->class_pointer
);
148 if(op
!= sel_get_uid ("initialize"))
149 __objc_send_initialize((Class
*)receiver
);
151 CLS_SETINITIALIZED((Class
*)receiver
);
154 allready_initialized
:
156 /* Get real method for this in newly installed dtable */
157 imp
= get_imp(receiver
->class_pointer
, op
);
159 args
= __builtin_apply_args();
160 result
= __builtin_apply((apply_t
)imp
, args
, 96);
161 __builtin_return (result
);
165 /* Install dummy table for class which causes the first message to
166 that class (or instances hereof) to be initialized properly */
167 void __objc_install_premature_dtable(Class
* class)
169 assert(__objc_uninstalled_dtable
);
170 class->dtable
= __objc_uninstalled_dtable
;
173 /* Send +initialize to class if not already done */
174 static void __objc_send_initialize(Class
* class)
178 /* This *must* be a class object */
179 assert(CLS_ISCLASS(class));
180 assert(!CLS_ISMETA(class));
182 if (!CLS_ISINITIALIZED(class))
184 CLS_SETINITIALIZED(class);
185 CLS_SETINITIALIZED(class->class_pointer
);
187 if(class->super_class
)
188 __objc_send_initialize(class->super_class
);
190 m
= search_for_method_in_list(class->class_pointer
->methods
,
191 sel_get_uid("initialize"));
194 CLS_SETINITIALIZED(class);
195 (*m
->method_imp
) ((id
) class, sel_get_uid("initialize"));
201 __objc_install_dispatch_table_for_class (Class
* class)
207 /* If the class has not yet had it's class links resolved, we must
208 re-compute all class links */
209 if(!CLS_ISRESOLV(class))
210 __objc_resolve_class_links();
212 super
= class->super_class
;
214 if (super
!= 0 && (super
->dtable
== __objc_uninstalled_dtable
))
215 __objc_install_dispatch_table_for_class (super
);
217 /* Allocate dtable if nessecary */
220 class->dtable
= sarray_new (__objc_selector_max_index
,
221 __objc_missing_method
);
224 class->dtable
= sarray_lazy_copy (super
->dtable
);
226 for (mlist
= class->methods
; mlist
; mlist
= mlist
->method_next
)
228 counter
= mlist
->method_count
- 1;
231 Method_t method
= &(mlist
->method_list
[counter
]);
232 sarray_at_put (class->dtable
,
233 (sidx
) method
->method_name
,
240 void __objc_update_dispatch_table_for_class (Class
* class)
245 /* not yet installed -- skip it */
246 if (class->dtable
== __objc_uninstalled_dtable
)
249 save
= class->dtable
;
250 __objc_install_premature_dtable (class);
254 if (class->subclass_list
) /* Traverse subclasses */
255 for (next
= class->subclass_list
; next
; next
= next
->sibling_class
)
256 __objc_update_dispatch_table_for_class (next
);
260 /* This function adds a method list to a class. This function is
261 typically called by another function specific to the run-time. As
262 such this function does not worry about thread safe issued.
264 This one is only called for categories. Class objects have their
265 methods installed rightaway, and their selectors are made into
266 SEL's by the function __objc_register_selectors_from_class. */
268 class_add_method_list (Class
* class, MethodList_t list
)
272 /* Passing of a linked list is not allowed. Do multiple calls. */
273 assert (!list
->method_next
);
275 /* Check for duplicates. */
276 for (i
= 0; i
< list
->method_count
; ++i
)
278 Method_t method
= &list
->method_list
[i
];
280 if (method
->method_name
) /* Sometimes these are NULL */
282 /* This is where selector names are transmogriffed to SEL's */
283 method
->method_name
= sel_register_name ((char*)method
->method_name
);
285 if (search_for_method_in_list (class->methods
, method
->method_name
))
287 /* Duplication. Print a error message an change the method name
289 fprintf (stderr
, "attempt to add a existing method: %s\n",
290 sel_get_name(method
->method_name
));
291 method
->method_name
= 0;
296 /* Add the methods to the class's method list. */
297 list
->method_next
= class->methods
;
298 class->methods
= list
;
303 class_get_instance_method(Class
* class, SEL op
)
305 return search_for_method_in_hierarchy(class, op
);
309 class_get_class_method(MetaClass
* class, SEL op
)
311 return search_for_method_in_hierarchy(class, op
);
315 /* Search for a method starting from the current class up its hierarchy.
316 Return a pointer to the method's method structure if found. NULL
320 search_for_method_in_hierarchy (Class
* cls
, SEL sel
)
322 Method_t method
= NULL
;
325 if (! sel_is_mapped (sel
))
328 /* Scan the method list of the class. If the method isn't found in the
329 list then step to its super class. */
330 for (class = cls
; ((! method
) && class); class = class->super_class
)
331 method
= search_for_method_in_list (class->methods
, sel
);
338 /* Given a linked list of method and a method's name. Search for the named
339 method's method structure. Return a pointer to the method's method
340 structure if found. NULL otherwise. */
342 search_for_method_in_list (MethodList_t list
, SEL op
)
344 MethodList_t method_list
= list
;
346 if (! sel_is_mapped (op
))
349 /* If not found then we'll search the list. */
354 /* Search the method list. */
355 for (i
= 0; i
< method_list
->method_count
; ++i
)
357 Method_t method
= &method_list
->method_list
[i
];
359 if (method
->method_name
)
360 if (method
->method_name
== op
)
364 /* The method wasn't found. Follow the link to the next list of
366 method_list
= method_list
->method_next
;
373 /* This fuction is installed in the dispatch table for all methods which are
374 not implemented. Thus, it is called when a selector is not recognized. */
376 __objc_missing_method (id object
, SEL sel
, ...)
382 /* first try if the object understands forward:: */
383 frwd_sel
= sel_get_uid("forward::");
384 imp
= get_imp(object
->class_pointer
, frwd_sel
);
385 if(imp
!= __objc_missing_method
)
387 void *result
, *args
= __builtin_apply_args();
388 result
= (*imp
)(object
, frwd_sel
, sel
, args
);
389 __builtin_return(result
);
392 /* If the object recognizes the doesNotRecognize: method then we're going
394 err_sel
= sel_get_uid ("doesNotRecognize:");
395 imp
= get_imp (object
->class_pointer
, err_sel
);
396 if (imp
!= __objc_missing_method
)
398 return (*imp
) (object
, err_sel
, sel
);
401 /* The object doesn't recognize the method. Check for responding to
402 error:. If it does then sent it. */
404 char msg
[256 + strlen ((char*)sel_get_name (sel
))
405 + strlen ((char*)object
->class_pointer
->name
)];
407 sprintf (msg
, "(%s) %s does not recognize %s",
408 (CLS_ISMETA(object
->class_pointer
)
411 object
->class_pointer
->name
, sel_get_name (sel
));
413 err_sel
= sel_get_uid ("error:");
414 imp
= get_imp (object
->class_pointer
, err_sel
);
415 if (imp
!= __objc_missing_method
)
416 return (*imp
) (object
, sel_get_uid ("error:"), msg
);
418 /* The object doesn't respond to doesNotRecognize: or error:; Therefore,
419 a default action is taken. */
420 fprintf (stderr
, "fatal: %s\n", msg
);
425 void __objc_print_dtable_stats()
428 printf("memory usage: (%s)\n",
430 "2-level sparse arrays"
432 "3-level sparse arrays"
436 printf("arrays: %d = %d bytes\n", narrays
, narrays
*sizeof(struct sarray
));
437 total
+= narrays
*sizeof(struct sarray
);
438 printf("buckets: %d = %d bytes\n", nbuckets
, nbuckets
*sizeof(struct sbucket
));
439 total
+= nbuckets
*sizeof(struct sbucket
);
441 printf("idxtables: %d = %d bytes\n", idxsize
, idxsize
*sizeof(void*));
442 total
+= idxsize
*sizeof(void*);
443 printf("-----------------------------------\n");
444 printf("total: %d bytes\n", total
);
445 printf("===================================\n");