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