Annotation of gcc/objc/sendmsg.c, revision 1.1.1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.