Annotation of GNUtools/cc/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: #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: 

unix.superglobalmegacorp.com

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