|
|
1.1 root 1: /* GNU Objective C Runtime message lookup 1.1.1.4 ! root 2: Copyright (C) 1993, 1995 Free Software Foundation, Inc. ! 3: Contributed by Kresten Krab Thorup 1.1 root 4: 5: This file is part of GNU CC. 6: 7: GNU CC is free software; you can redistribute it and/or modify it under the 1.1.1.4 ! root 8: terms of the GNU General Public License as published by the Free Software ! 9: Foundation; either version 2, or (at your option) any later version. 1.1 root 10: 11: GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY 1.1.1.4 ! root 12: WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ! 13: FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ! 14: details. 1.1 root 15: 16: You should have received a copy of the GNU General Public License along with 1.1.1.4 ! root 17: GNU CC; see the file COPYING. If not, write to the Free Software ! 18: Foundation, 59 Temple Place - Suite 330, ! 19: Boston, MA 02111-1307, USA. */ 1.1 root 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 */ 1.1.1.4 ! root 46: static void __objc_send_initialize(Class); 1.1 root 47: 1.1.1.4 ! root 48: static void __objc_install_dispatch_table_for_class (Class); 1.1 root 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.1.4 ! root 60: static Method_t search_for_method_in_hierarchy (Class class, SEL sel); 1.1 root 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.1.4 ! root 73: get_imp (Class class, SEL sel) 1.1 root 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: { 1.1.1.4 ! root 165: __label__ already_initialized; 1.1 root 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) 1.1.1.4 ! root 173: goto already_initialized; 1.1 root 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 */ 1.1.1.4 ! root 190: assert(CLS_ISCLASS((Class)receiver)); 1.1 root 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.1.4 ! root 197: __objc_send_initialize((Class)receiver); 1.1 root 198: else 1.1.1.4 ! root 199: CLS_SETINITIALIZED((Class)receiver); 1.1 root 200: } 201: 1.1.1.4 ! root 202: already_initialized: 1.1 root 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 */ 1.1.1.4 ! root 218: void __objc_install_premature_dtable(Class class) 1.1 root 219: { 220: assert(__objc_uninstalled_dtable); 221: class->dtable = __objc_uninstalled_dtable; 222: } 223: 224: /* Send +initialize to class if not already done */ 1.1.1.4 ! root 225: static void __objc_send_initialize(Class class) 1.1 root 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: { 1.1.1.4 ! root 240: SEL op = sel_register_name ("initialize"); ! 241: Class tmpclass = class; ! 242: IMP imp = 0; ! 243: ! 244: while (!imp && tmpclass) { ! 245: MethodList_t method_list = tmpclass->class_pointer->methods; 1.1 root 246: 1.1.1.4 ! root 247: while(!imp && method_list) { 1.1 root 248: int i; 1.1.1.4 ! root 249: Method_t method; 1.1 root 250: 1.1.1.4 ! root 251: for (i=0;i<method_list->method_count;i++) { ! 252: method = &(method_list->method_list[i]); ! 253: if (method->method_name->sel_id == op->sel_id) { ! 254: imp = method->method_imp; ! 255: break; 1.1 root 256: } 1.1.1.4 ! root 257: } 1.1 root 258: 259: method_list = method_list->method_next; 1.1.1.4 ! root 260: 1.1 root 261: } 1.1.1.4 ! root 262: ! 263: tmpclass = tmpclass->super_class; ! 264: } ! 265: if (imp) ! 266: (*imp)((id)class, op); ! 267: 1.1 root 268: } 269: } 270: } 271: 272: static void 1.1.1.4 ! root 273: __objc_install_dispatch_table_for_class (Class class) 1.1 root 274: { 1.1.1.4 ! root 275: Class super; 1.1 root 276: MethodList_t mlist; 277: int counter; 278: 279: /* If the class has not yet had it's class links resolved, we must 280: re-compute all class links */ 281: if(!CLS_ISRESOLV(class)) 282: __objc_resolve_class_links(); 283: 284: super = class->super_class; 285: 286: if (super != 0 && (super->dtable == __objc_uninstalled_dtable)) 287: __objc_install_dispatch_table_for_class (super); 288: 1.1.1.4 ! root 289: /* Allocate dtable if necessary */ 1.1 root 290: if (super == 0) 291: { 1.1.1.3 root 292: class->dtable = sarray_new (__objc_selector_max_index, 0); 1.1 root 293: } 294: else 295: class->dtable = sarray_lazy_copy (super->dtable); 296: 297: for (mlist = class->methods; mlist; mlist = mlist->method_next) 298: { 299: counter = mlist->method_count - 1; 300: while (counter >= 0) 301: { 302: Method_t method = &(mlist->method_list[counter]); 1.1.1.2 root 303: sarray_at_put_safe (class->dtable, 1.1.1.3 root 304: (sidx) method->method_name->sel_id, 1.1.1.2 root 305: method->method_imp); 1.1 root 306: counter -= 1; 307: } 308: } 309: } 310: 1.1.1.4 ! root 311: void __objc_update_dispatch_table_for_class (Class class) 1.1 root 312: { 1.1.1.4 ! root 313: Class next; 1.1 root 314: 315: /* not yet installed -- skip it */ 316: if (class->dtable == __objc_uninstalled_dtable) 317: return; 318: 1.1.1.2 root 319: sarray_free (class->dtable); /* release memory */ 320: __objc_install_premature_dtable (class); /* someone might require it... */ 321: __objc_install_dispatch_table_for_class (class); /* could have been lazy... */ 1.1 root 322: 323: if (class->subclass_list) /* Traverse subclasses */ 324: for (next = class->subclass_list; next; next = next->sibling_class) 325: __objc_update_dispatch_table_for_class (next); 1.1.1.2 root 326: 1.1 root 327: } 328: 329: 330: /* This function adds a method list to a class. This function is 331: typically called by another function specific to the run-time. As 332: such this function does not worry about thread safe issued. 333: 334: This one is only called for categories. Class objects have their 1.1.1.4 ! root 335: methods installed right away, and their selectors are made into 1.1 root 336: SEL's by the function __objc_register_selectors_from_class. */ 337: void 1.1.1.4 ! root 338: class_add_method_list (Class class, MethodList_t list) 1.1 root 339: { 340: int i; 341: static SEL initialize_sel = 0; 342: if (!initialize_sel) 343: initialize_sel = sel_register_name ("initialize"); 344: 345: /* Passing of a linked list is not allowed. Do multiple calls. */ 346: assert (!list->method_next); 347: 348: /* Check for duplicates. */ 349: for (i = 0; i < list->method_count; ++i) 350: { 351: Method_t method = &list->method_list[i]; 352: 353: if (method->method_name) /* Sometimes these are NULL */ 354: { 1.1.1.4 ! root 355: /* This is where selector names are transmogrified to SEL's */ 1.1.1.3 root 356: method->method_name = 357: sel_register_typed_name ((const char*)method->method_name, 358: method->method_types); 1.1 root 359: 360: if (search_for_method_in_list (class->methods, method->method_name) 1.1.1.3 root 361: && method->method_name->sel_id != initialize_sel->sel_id) 1.1 root 362: { 363: /* Duplication. Print a error message an change the method name 364: to NULL. */ 365: fprintf (stderr, "attempt to add a existing method: %s\n", 366: sel_get_name(method->method_name)); 367: method->method_name = 0; 368: } 369: } 370: } 371: 372: /* Add the methods to the class's method list. */ 373: list->method_next = class->methods; 374: class->methods = list; 375: } 376: 377: 378: Method_t 1.1.1.4 ! root 379: class_get_instance_method(Class class, SEL op) 1.1 root 380: { 381: return search_for_method_in_hierarchy(class, op); 382: } 383: 384: Method_t 1.1.1.4 ! root 385: class_get_class_method(MetaClass class, SEL op) 1.1 root 386: { 387: return search_for_method_in_hierarchy(class, op); 388: } 389: 390: 391: /* Search for a method starting from the current class up its hierarchy. 392: Return a pointer to the method's method structure if found. NULL 393: otherwise. */ 394: 395: static Method_t 1.1.1.4 ! root 396: search_for_method_in_hierarchy (Class cls, SEL sel) 1.1 root 397: { 398: Method_t method = NULL; 1.1.1.4 ! root 399: Class class; 1.1 root 400: 401: if (! sel_is_mapped (sel)) 402: return NULL; 403: 404: /* Scan the method list of the class. If the method isn't found in the 405: list then step to its super class. */ 406: for (class = cls; ((! method) && class); class = class->super_class) 407: method = search_for_method_in_list (class->methods, sel); 408: 409: return method; 410: } 411: 412: 413: 414: /* Given a linked list of method and a method's name. Search for the named 415: method's method structure. Return a pointer to the method's method 416: structure if found. NULL otherwise. */ 417: static Method_t 418: search_for_method_in_list (MethodList_t list, SEL op) 419: { 420: MethodList_t method_list = list; 421: 422: if (! sel_is_mapped (op)) 423: return NULL; 424: 425: /* If not found then we'll search the list. */ 426: while (method_list) 427: { 428: int i; 429: 430: /* Search the method list. */ 431: for (i = 0; i < method_list->method_count; ++i) 432: { 433: Method_t method = &method_list->method_list[i]; 434: 435: if (method->method_name) 1.1.1.3 root 436: if (method->method_name->sel_id == op->sel_id) 1.1 root 437: return method; 438: } 439: 440: /* The method wasn't found. Follow the link to the next list of 441: methods. */ 442: method_list = method_list->method_next; 443: } 444: 445: return NULL; 446: } 447: 1.1.1.3 root 448: static retval_t __objc_forward (id object, SEL sel, arglist_t args); 449: 450: static id 451: __objc_word_forward (id rcv, SEL op, ...) 452: { 453: void *args, *res; 454: 455: args = __builtin_apply_args (); 456: res = __objc_forward (rcv, op, args); 457: if (res) 458: __builtin_return (res); 459: else 460: return res; 461: } 462: 463: #if INVISIBLE_STRUCT_RETURN 464: static __big 465: #else 466: static id 467: #endif 468: __objc_block_forward (id rcv, SEL op, ...) 469: { 470: void *args, *res; 471: 472: args = __builtin_apply_args (); 473: res = __objc_forward (rcv, op, args); 474: if (res) 475: __builtin_return (res); 476: } 477: 1.1 root 478: 1.1.1.4 ! root 479: /* This function is installed in the dispatch table for all methods which are 1.1 root 480: not implemented. Thus, it is called when a selector is not recognized. */ 1.1.1.3 root 481: static retval_t 482: __objc_forward (id object, SEL sel, arglist_t args) 1.1 root 483: { 484: IMP imp; 1.1.1.3 root 485: static SEL frwd_sel = 0; 1.1 root 486: SEL err_sel; 487: 488: /* first try if the object understands forward:: */ 1.1.1.3 root 489: if (!frwd_sel) 490: frwd_sel = sel_get_any_uid("forward::"); 491: 492: if (__objc_responds_to (object, frwd_sel)) 493: { 494: imp = get_imp(object->class_pointer, frwd_sel); 495: return (*imp)(object, frwd_sel, sel, args); 1.1 root 496: } 497: 498: /* If the object recognizes the doesNotRecognize: method then we're going 499: to send it. */ 1.1.1.3 root 500: err_sel = sel_get_any_uid ("doesNotRecognize:"); 501: if (__objc_responds_to (object, err_sel)) 1.1 root 502: { 1.1.1.3 root 503: imp = get_imp (object->class_pointer, err_sel); 1.1 root 504: return (*imp) (object, err_sel, sel); 505: } 506: 507: /* The object doesn't recognize the method. Check for responding to 508: error:. If it does then sent it. */ 509: { 1.1.1.3 root 510: size_t strlen (const char*); 511: char msg[256 + strlen ((const char*)sel_get_name (sel)) 512: + strlen ((const char*)object->class_pointer->name)]; 1.1 root 513: 514: sprintf (msg, "(%s) %s does not recognize %s", 515: (CLS_ISMETA(object->class_pointer) 516: ? "class" 517: : "instance" ), 518: object->class_pointer->name, sel_get_name (sel)); 519: 1.1.1.3 root 520: err_sel = sel_get_any_uid ("error:"); 521: if (__objc_responds_to (object, err_sel)) 522: { 523: imp = get_imp (object->class_pointer, err_sel); 524: return (*imp) (object, sel_get_any_uid ("error:"), msg); 525: } 1.1 root 526: 527: /* The object doesn't respond to doesNotRecognize: or error:; Therefore, 528: a default action is taken. */ 529: fprintf (stderr, "fatal: %s\n", msg); 530: abort (); 531: } 532: } 533: 534: void __objc_print_dtable_stats() 535: { 536: int total = 0; 537: printf("memory usage: (%s)\n", 538: #ifdef OBJC_SPARSE2 539: "2-level sparse arrays" 540: #else 541: "3-level sparse arrays" 542: #endif 543: ); 544: 1.1.1.3 root 545: printf("arrays: %d = %ld bytes\n", narrays, (int)narrays*sizeof(struct sarray)); 1.1 root 546: total += narrays*sizeof(struct sarray); 1.1.1.3 root 547: printf("buckets: %d = %ld bytes\n", nbuckets, (int)nbuckets*sizeof(struct sbucket)); 1.1 root 548: total += nbuckets*sizeof(struct sbucket); 549: 1.1.1.3 root 550: printf("idxtables: %d = %ld bytes\n", idxsize, (int)idxsize*sizeof(void*)); 1.1 root 551: total += idxsize*sizeof(void*); 552: printf("-----------------------------------\n"); 553: printf("total: %d bytes\n", total); 554: printf("===================================\n"); 555: } 556: 557: 558:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.