]> gcc.gnu.org Git - gcc.git/blame_incremental - gcc/objc/sendmsg.c
Fix comment typos. emit_block_move decl was hidden.
[gcc.git] / gcc / objc / sendmsg.c
... / ...
CommitLineData
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#include "sarray.h"
29
30/* The uninstalled dispatch table */
31struct sarray* __objc_uninstalled_dtable = 0;
32
33/* Send +initialize to class */
34static void __objc_send_initialize(Class*);
35
36static void __objc_install_dispatch_table_for_class (Class*);
37
38/* Forward declare some functions */
39static void __objc_init_install_dtable(id, SEL);
40static id __objc_missing_method(id, SEL, ...);
41static Method_t search_for_method_in_hierarchy (Class* class, SEL sel);
42static Method_t search_for_method_in_list(MethodList_t list, SEL op);
43id nil_method(id, SEL, ...);
44
45id
46nil_method(id receiver, SEL op, ...)
47{
48 return receiver;
49}
50
51/* Given a class and selector, return the selector's implementation. */
52__inline__ IMP
53get_imp (Class* class, SEL sel)
54{
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);
59}
60
61__inline__ BOOL
62__objc_responds_to (id object, SEL sel)
63{
64 return get_imp (object->class_pointer, sel) != __objc_missing_method;
65}
66
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
70 real dtable */
71__inline__ IMP
72objc_msg_lookup(id receiver, SEL op)
73{
74 if(receiver)
75 return sarray_get(receiver->class_pointer->dtable, (sidx)op);
76 else
77 return nil_method;
78}
79
80IMP
81objc_msg_lookup_super (Super_t super, SEL sel)
82{
83 if (super->self)
84 return get_imp (super->class, sel);
85 else
86 return nil_method;
87}
88
89retval_t
90objc_msg_sendv(id object, SEL op, size_t frame_size, arglist_t arg_frame)
91{
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),
96 arg_frame,
97 frame_size);
98#else
99#warning performv:: will not work
100 (*_objc_error)(object, "objc_msg_sendv (performv::) not supported\n", 0);
101 return 0;
102#endif
103}
104
105void __objc_init_dispatch_tables()
106{
107 __objc_uninstalled_dtable
108 = sarray_new(200, __objc_init_install_dtable);
109}
110
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. */
114
115static void __objc_init_install_dtable(id receiver, SEL op)
116{
117 __label__ allready_initialized;
118 IMP imp;
119 void* args;
120 void* result;
121
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;
126
127 if(CLS_ISCLASS(receiver->class_pointer))
128 {
129 /* receiver is an ordinary object */
130 assert(CLS_ISCLASS(receiver->class_pointer));
131
132 /* install instance methods table */
133 __objc_install_dispatch_table_for_class (receiver->class_pointer);
134
135 /* call +initialize -- this will in turn install the factory
136 dispatch table if not already done :-) */
137 __objc_send_initialize(receiver->class_pointer);
138 }
139 else
140 {
141 /* receiver is a class object */
142 assert(CLS_ISCLASS((Class*)receiver));
143 assert(CLS_ISMETA(receiver->class_pointer));
144
145 /* Install real dtable for factory methods */
146 __objc_install_dispatch_table_for_class (receiver->class_pointer);
147
148 if(op != sel_get_uid ("initialize"))
149 __objc_send_initialize((Class*)receiver);
150 else
151 CLS_SETINITIALIZED((Class*)receiver);
152 }
153
154allready_initialized:
155
156 /* Get real method for this in newly installed dtable */
157 imp = get_imp(receiver->class_pointer, op);
158
159 args = __builtin_apply_args();
160 result = __builtin_apply((apply_t)imp, args, 96);
161 __builtin_return (result);
162
163}
164
165/* Install dummy table for class which causes the first message to
166 that class (or instances hereof) to be initialized properly */
167void __objc_install_premature_dtable(Class* class)
168{
169 assert(__objc_uninstalled_dtable);
170 class->dtable = __objc_uninstalled_dtable;
171}
172
173/* Send +initialize to class if not already done */
174static void __objc_send_initialize(Class* class)
175{
176 Method_t m;
177
178 /* This *must* be a class object */
179 assert(CLS_ISCLASS(class));
180 assert(!CLS_ISMETA(class));
181
182 if (!CLS_ISINITIALIZED(class))
183 {
184 CLS_SETINITIALIZED(class);
185 CLS_SETINITIALIZED(class->class_pointer);
186
187 if(class->super_class)
188 __objc_send_initialize(class->super_class);
189
190 m = search_for_method_in_list(class->class_pointer->methods,
191 sel_get_uid("initialize"));
192 if(m != NULL)
193 {
194 CLS_SETINITIALIZED(class);
195 (*m->method_imp) ((id) class, sel_get_uid("initialize"));
196 }
197 }
198}
199
200static void
201__objc_install_dispatch_table_for_class (Class* class)
202{
203 Class* super;
204 MethodList_t mlist;
205 int counter;
206
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();
211
212 super = class->super_class;
213
214 if (super != 0 && (super->dtable == __objc_uninstalled_dtable))
215 __objc_install_dispatch_table_for_class (super);
216
217 /* Allocate dtable if nessecary */
218 if (super == 0)
219 {
220 class->dtable = sarray_new (__objc_selector_max_index,
221 __objc_missing_method);
222 }
223 else
224 class->dtable = sarray_lazy_copy (super->dtable);
225
226 for (mlist = class->methods; mlist; mlist = mlist->method_next)
227 {
228 counter = mlist->method_count - 1;
229 while (counter >= 0)
230 {
231 Method_t method = &(mlist->method_list[counter]);
232 sarray_at_put (class->dtable,
233 (sidx) method->method_name,
234 method->method_imp);
235 counter -= 1;
236 }
237 }
238}
239
240void __objc_update_dispatch_table_for_class (Class* class)
241{
242 Class* next;
243 struct sarray* save;
244
245 /* not yet installed -- skip it */
246 if (class->dtable == __objc_uninstalled_dtable)
247 return;
248
249 save = class->dtable;
250 __objc_install_premature_dtable (class);
251 sarray_free (save);
252
253
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);
257}
258
259
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.
263
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. */
267void
268class_add_method_list (Class* class, MethodList_t list)
269{
270 int i;
271
272 /* Passing of a linked list is not allowed. Do multiple calls. */
273 assert (!list->method_next);
274
275 /* Check for duplicates. */
276 for (i = 0; i < list->method_count; ++i)
277 {
278 Method_t method = &list->method_list[i];
279
280 if (method->method_name) /* Sometimes these are NULL */
281 {
282 /* This is where selector names are transmogriffed to SEL's */
283 method->method_name = sel_register_name ((char*)method->method_name);
284
285 if (search_for_method_in_list (class->methods, method->method_name))
286 {
287 /* Duplication. Print a error message an change the method name
288 to NULL. */
289 fprintf (stderr, "attempt to add a existing method: %s\n",
290 sel_get_name(method->method_name));
291 method->method_name = 0;
292 }
293 }
294 }
295
296 /* Add the methods to the class's method list. */
297 list->method_next = class->methods;
298 class->methods = list;
299}
300
301
302Method_t
303class_get_instance_method(Class* class, SEL op)
304{
305 return search_for_method_in_hierarchy(class, op);
306}
307
308Method_t
309class_get_class_method(MetaClass* class, SEL op)
310{
311 return search_for_method_in_hierarchy(class, op);
312}
313
314
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
317 otherwise. */
318
319static Method_t
320search_for_method_in_hierarchy (Class* cls, SEL sel)
321{
322 Method_t method = NULL;
323 Class* class;
324
325 if (! sel_is_mapped (sel))
326 return NULL;
327
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);
332
333 return method;
334}
335
336
337
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. */
341static Method_t
342search_for_method_in_list (MethodList_t list, SEL op)
343{
344 MethodList_t method_list = list;
345
346 if (! sel_is_mapped (op))
347 return NULL;
348
349 /* If not found then we'll search the list. */
350 while (method_list)
351 {
352 int i;
353
354 /* Search the method list. */
355 for (i = 0; i < method_list->method_count; ++i)
356 {
357 Method_t method = &method_list->method_list[i];
358
359 if (method->method_name)
360 if (method->method_name == op)
361 return method;
362 }
363
364 /* The method wasn't found. Follow the link to the next list of
365 methods. */
366 method_list = method_list->method_next;
367 }
368
369 return NULL;
370}
371
372
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. */
375static id
376__objc_missing_method (id object, SEL sel, ...)
377{
378 IMP imp;
379 SEL frwd_sel;
380 SEL err_sel;
381
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)
386 {
387 void *result, *args = __builtin_apply_args();
388 result = (*imp)(object, frwd_sel, sel, args);
389 __builtin_return(result);
390 }
391
392 /* If the object recognizes the doesNotRecognize: method then we're going
393 to send it. */
394 err_sel = sel_get_uid ("doesNotRecognize:");
395 imp = get_imp (object->class_pointer, err_sel);
396 if (imp != __objc_missing_method)
397 {
398 return (*imp) (object, err_sel, sel);
399 }
400
401 /* The object doesn't recognize the method. Check for responding to
402 error:. If it does then sent it. */
403 {
404 char msg[256 + strlen ((char*)sel_get_name (sel))
405 + strlen ((char*)object->class_pointer->name)];
406
407 sprintf (msg, "(%s) %s does not recognize %s",
408 (CLS_ISMETA(object->class_pointer)
409 ? "class"
410 : "instance" ),
411 object->class_pointer->name, sel_get_name (sel));
412
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);
417
418 /* The object doesn't respond to doesNotRecognize: or error:; Therefore,
419 a default action is taken. */
420 fprintf (stderr, "fatal: %s\n", msg);
421 abort ();
422 }
423}
424
425void __objc_print_dtable_stats()
426{
427 int total = 0;
428 printf("memory usage: (%s)\n",
429#ifdef OBJC_SPARSE2
430 "2-level sparse arrays"
431#else
432 "3-level sparse arrays"
433#endif
434 );
435
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);
440
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");
446}
447
448
449
This page took 0.02932 seconds and 5 git commands to generate.