|
|
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: ! 27: #include "runtime.h" ! 28: #include "sarray.h" ! 29: ! 30: /* The uninstalled dispatch table */ ! 31: struct sarray* __objc_uninstalled_dtable = 0; ! 32: ! 33: /* Send +initialize to class */ ! 34: static void __objc_send_initialize(Class*); ! 35: ! 36: static void __objc_install_dispatch_table_for_class (Class*); ! 37: ! 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, ...); ! 44: ! 45: id ! 46: nil_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 ! 53: get_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 ! 72: objc_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: ! 80: IMP ! 81: objc_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: ! 89: retval_t ! 90: objc_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: va_list nothing; ! 101: (*_objc_error)(object, "objc_msg_sendv (performv::) not supported\n", nothing); ! 102: return 0; ! 103: #endif ! 104: } ! 105: ! 106: void __objc_init_dispatch_tables() ! 107: { ! 108: __objc_uninstalled_dtable ! 109: = sarray_new(200, __objc_init_install_dtable); ! 110: } ! 111: ! 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. */ ! 115: ! 116: static void __objc_init_install_dtable(id receiver, SEL op) ! 117: { ! 118: __label__ allready_initialized; ! 119: IMP imp; ! 120: void* args; ! 121: void* result; ! 122: ! 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; ! 127: ! 128: if(CLS_ISCLASS(receiver->class_pointer)) ! 129: { ! 130: /* receiver is an ordinary object */ ! 131: assert(CLS_ISCLASS(receiver->class_pointer)); ! 132: ! 133: /* install instance methods table */ ! 134: __objc_install_dispatch_table_for_class (receiver->class_pointer); ! 135: ! 136: /* call +initialize -- this will in turn install the factory ! 137: dispatch table if not already done :-) */ ! 138: __objc_send_initialize(receiver->class_pointer); ! 139: } ! 140: else ! 141: { ! 142: /* receiver is a class object */ ! 143: assert(CLS_ISCLASS((Class*)receiver)); ! 144: assert(CLS_ISMETA(receiver->class_pointer)); ! 145: ! 146: /* Install real dtable for factory methods */ ! 147: __objc_install_dispatch_table_for_class (receiver->class_pointer); ! 148: ! 149: if(op != sel_get_uid ("initialize")) ! 150: __objc_send_initialize((Class*)receiver); ! 151: else ! 152: CLS_SETINITIALIZED((Class*)receiver); ! 153: } ! 154: ! 155: allready_initialized: ! 156: ! 157: /* Get real method for this in newly installed dtable */ ! 158: imp = get_imp(receiver->class_pointer, op); ! 159: ! 160: args = __builtin_apply_args(); ! 161: result = __builtin_apply((apply_t)imp, args, 96); ! 162: __builtin_return (result); ! 163: ! 164: } ! 165: ! 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) ! 169: { ! 170: assert(__objc_uninstalled_dtable); ! 171: class->dtable = __objc_uninstalled_dtable; ! 172: } ! 173: ! 174: /* Send +initialize to class if not already done */ ! 175: static void __objc_send_initialize(Class* class) ! 176: { ! 177: Method_t m; ! 178: ! 179: /* This *must* be a class object */ ! 180: assert(CLS_ISCLASS(class)); ! 181: assert(!CLS_ISMETA(class)); ! 182: ! 183: if (!CLS_ISINITIALIZED(class)) ! 184: { ! 185: CLS_SETINITIALIZED(class); ! 186: CLS_SETINITIALIZED(class->class_pointer); ! 187: ! 188: if(class->super_class) ! 189: __objc_send_initialize(class->super_class); ! 190: ! 191: { ! 192: MethodList_t method_list = class->class_pointer->methods; ! 193: SEL op = sel_register_name ("initialize"); ! 194: ! 195: /* If not found then we'll search the list. */ ! 196: while (method_list) ! 197: { ! 198: int i; ! 199: ! 200: /* Search the method list. */ ! 201: for (i = 0; i < method_list->method_count; ++i) ! 202: { ! 203: Method_t method = &method_list->method_list[i]; ! 204: ! 205: ! 206: if (method->method_name == op) ! 207: (*method->method_imp)((id) class, op); ! 208: } ! 209: ! 210: /* The method wasn't found. Follow the link to the next list of ! 211: methods. */ ! 212: method_list = method_list->method_next; ! 213: } ! 214: } ! 215: } ! 216: } ! 217: ! 218: static void ! 219: __objc_install_dispatch_table_for_class (Class* class) ! 220: { ! 221: Class* super; ! 222: MethodList_t mlist; ! 223: int counter; ! 224: ! 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(); ! 229: ! 230: super = class->super_class; ! 231: ! 232: if (super != 0 && (super->dtable == __objc_uninstalled_dtable)) ! 233: __objc_install_dispatch_table_for_class (super); ! 234: ! 235: /* Allocate dtable if nessecary */ ! 236: if (super == 0) ! 237: { ! 238: class->dtable = sarray_new (__objc_selector_max_index, ! 239: __objc_missing_method); ! 240: } ! 241: else ! 242: class->dtable = sarray_lazy_copy (super->dtable); ! 243: ! 244: for (mlist = class->methods; mlist; mlist = mlist->method_next) ! 245: { ! 246: counter = mlist->method_count - 1; ! 247: while (counter >= 0) ! 248: { ! 249: Method_t method = &(mlist->method_list[counter]); ! 250: sarray_at_put (class->dtable, ! 251: (sidx) method->method_name, ! 252: method->method_imp); ! 253: counter -= 1; ! 254: } ! 255: } ! 256: } ! 257: ! 258: void __objc_update_dispatch_table_for_class (Class* class) ! 259: { ! 260: Class* next; ! 261: struct sarray* save; ! 262: ! 263: /* not yet installed -- skip it */ ! 264: if (class->dtable == __objc_uninstalled_dtable) ! 265: return; ! 266: ! 267: save = class->dtable; ! 268: __objc_install_premature_dtable (class); ! 269: sarray_free (save); ! 270: ! 271: ! 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); ! 275: } ! 276: ! 277: ! 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. ! 281: ! 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. */ ! 285: void ! 286: class_add_method_list (Class* class, MethodList_t list) ! 287: { ! 288: int i; ! 289: static SEL initialize_sel = 0; ! 290: if (!initialize_sel) ! 291: initialize_sel = sel_register_name ("initialize"); ! 292: ! 293: /* Passing of a linked list is not allowed. Do multiple calls. */ ! 294: assert (!list->method_next); ! 295: ! 296: /* Check for duplicates. */ ! 297: for (i = 0; i < list->method_count; ++i) ! 298: { ! 299: Method_t method = &list->method_list[i]; ! 300: ! 301: if (method->method_name) /* Sometimes these are NULL */ ! 302: { ! 303: /* This is where selector names are transmogriffed to SEL's */ ! 304: method->method_name = sel_register_name ((char*)method->method_name); ! 305: ! 306: if (search_for_method_in_list (class->methods, method->method_name) ! 307: && method->method_name != initialize_sel) ! 308: { ! 309: /* Duplication. Print a error message an change the method name ! 310: to NULL. */ ! 311: fprintf (stderr, "attempt to add a existing method: %s\n", ! 312: sel_get_name(method->method_name)); ! 313: method->method_name = 0; ! 314: } ! 315: } ! 316: } ! 317: ! 318: /* Add the methods to the class's method list. */ ! 319: list->method_next = class->methods; ! 320: class->methods = list; ! 321: } ! 322: ! 323: ! 324: Method_t ! 325: class_get_instance_method(Class* class, SEL op) ! 326: { ! 327: return search_for_method_in_hierarchy(class, op); ! 328: } ! 329: ! 330: Method_t ! 331: class_get_class_method(MetaClass* class, SEL op) ! 332: { ! 333: return search_for_method_in_hierarchy(class, op); ! 334: } ! 335: ! 336: ! 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 ! 339: otherwise. */ ! 340: ! 341: static Method_t ! 342: search_for_method_in_hierarchy (Class* cls, SEL sel) ! 343: { ! 344: Method_t method = NULL; ! 345: Class* class; ! 346: ! 347: if (! sel_is_mapped (sel)) ! 348: return NULL; ! 349: ! 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); ! 354: ! 355: return method; ! 356: } ! 357: ! 358: ! 359: ! 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. */ ! 363: static Method_t ! 364: search_for_method_in_list (MethodList_t list, SEL op) ! 365: { ! 366: MethodList_t method_list = list; ! 367: ! 368: if (! sel_is_mapped (op)) ! 369: return NULL; ! 370: ! 371: /* If not found then we'll search the list. */ ! 372: while (method_list) ! 373: { ! 374: int i; ! 375: ! 376: /* Search the method list. */ ! 377: for (i = 0; i < method_list->method_count; ++i) ! 378: { ! 379: Method_t method = &method_list->method_list[i]; ! 380: ! 381: if (method->method_name) ! 382: if (method->method_name == op) ! 383: return method; ! 384: } ! 385: ! 386: /* The method wasn't found. Follow the link to the next list of ! 387: methods. */ ! 388: method_list = method_list->method_next; ! 389: } ! 390: ! 391: return NULL; ! 392: } ! 393: ! 394: ! 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. */ ! 397: static id ! 398: __objc_missing_method (id object, SEL sel, ...) ! 399: { ! 400: IMP imp; ! 401: SEL frwd_sel; ! 402: SEL err_sel; ! 403: ! 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) ! 408: { ! 409: void *result, *args = __builtin_apply_args(); ! 410: result = (*imp)(object, frwd_sel, sel, args); ! 411: __builtin_return(result); ! 412: } ! 413: ! 414: /* If the object recognizes the doesNotRecognize: method then we're going ! 415: to send it. */ ! 416: err_sel = sel_get_uid ("doesNotRecognize:"); ! 417: imp = get_imp (object->class_pointer, err_sel); ! 418: if (imp != __objc_missing_method) ! 419: { ! 420: return (*imp) (object, err_sel, sel); ! 421: } ! 422: ! 423: /* The object doesn't recognize the method. Check for responding to ! 424: error:. If it does then sent it. */ ! 425: { ! 426: char msg[256 + strlen ((char*)sel_get_name (sel)) ! 427: + strlen ((char*)object->class_pointer->name)]; ! 428: ! 429: sprintf (msg, "(%s) %s does not recognize %s", ! 430: (CLS_ISMETA(object->class_pointer) ! 431: ? "class" ! 432: : "instance" ), ! 433: object->class_pointer->name, sel_get_name (sel)); ! 434: ! 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); ! 439: ! 440: /* The object doesn't respond to doesNotRecognize: or error:; Therefore, ! 441: a default action is taken. */ ! 442: fprintf (stderr, "fatal: %s\n", msg); ! 443: abort (); ! 444: } ! 445: } ! 446: ! 447: void __objc_print_dtable_stats() ! 448: { ! 449: int total = 0; ! 450: printf("memory usage: (%s)\n", ! 451: #ifdef OBJC_SPARSE2 ! 452: "2-level sparse arrays" ! 453: #else ! 454: "3-level sparse arrays" ! 455: #endif ! 456: ); ! 457: ! 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); ! 462: ! 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"); ! 468: } ! 469: ! 470: ! 471:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.