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