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

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"
1.1.1.2 ! root       29: #include "encoding.h"
1.1       root       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)
                     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: retval_t
1.1.1.2 ! root       91: objc_msg_sendv(id object, SEL op, arglist_t arg_frame)
1.1       root       92: {
1.1.1.2 ! root       93:   Method* m = class_get_instance_method(object->class_pointer, op);
        !            94:   const char *type;
        !            95:   *((id*)method_get_first_argument (m, arg_frame, &type)) = object;
        !            96:   *((SEL*)method_get_next_argument (arg_frame, &type)) = op;
        !            97:   return __builtin_apply((apply_t)m->method_imp, 
1.1       root       98:                         arg_frame,
1.1.1.2 ! root       99:                         method_get_sizeof_arguments (m));
1.1       root      100: }
                    101: 
                    102: void __objc_init_dispatch_tables()
                    103: {
                    104:   __objc_uninstalled_dtable
                    105:     = sarray_new(200, __objc_init_install_dtable);
                    106: }
                    107: 
                    108: /* This one is a bit hairy.  This function is installed in the 
                    109:    premature dispatch table, and thus called once for each class,
                    110:    namely when the very first message is send to it.  */
                    111: 
                    112: static void __objc_init_install_dtable(id receiver, SEL op)
                    113: {
                    114:   __label__ allready_initialized;
                    115:   IMP imp;
                    116:   void* args;
                    117:   void* result;
                    118: 
                    119:   /* This may happen, if the programmer has taken the address of a 
                    120:      method before the dtable was initialized... too bad for him! */
                    121:   if(receiver->class_pointer->dtable != __objc_uninstalled_dtable)
                    122:     goto allready_initialized;
                    123: 
                    124:   if(CLS_ISCLASS(receiver->class_pointer))
                    125:     {
                    126:       /* receiver is an ordinary object */
                    127:       assert(CLS_ISCLASS(receiver->class_pointer));
                    128: 
                    129:       /* install instance methods table */
                    130:       __objc_install_dispatch_table_for_class (receiver->class_pointer);
                    131: 
                    132:       /* call +initialize -- this will in turn install the factory 
                    133:         dispatch table if not already done :-) */
                    134:       __objc_send_initialize(receiver->class_pointer);
                    135:     }
                    136:   else
                    137:     {
                    138:       /* receiver is a class object */
                    139:       assert(CLS_ISCLASS((Class*)receiver));
                    140:       assert(CLS_ISMETA(receiver->class_pointer));
                    141: 
                    142:       /* Install real dtable for factory methods */
                    143:       __objc_install_dispatch_table_for_class (receiver->class_pointer);
                    144:       
                    145:       if(op != sel_get_uid ("initialize"))
                    146:        __objc_send_initialize((Class*)receiver);
                    147:       else
                    148:        CLS_SETINITIALIZED((Class*)receiver);
                    149:     }
                    150: 
                    151: allready_initialized:
                    152:   
                    153:   /* Get real method for this in newly installed dtable */
                    154:   imp = get_imp(receiver->class_pointer, op);
                    155: 
                    156:   args = __builtin_apply_args();
                    157:   result = __builtin_apply((apply_t)imp, args, 96);
                    158:   __builtin_return (result);
                    159:   
                    160: }
                    161: 
                    162: /* Install dummy table for class which causes the first message to
                    163:    that class (or instances hereof) to be initialized properly */
                    164: void __objc_install_premature_dtable(Class* class)
                    165: {
                    166:   assert(__objc_uninstalled_dtable);
                    167:   class->dtable = __objc_uninstalled_dtable;
                    168: }   
                    169: 
                    170: /* Send +initialize to class if not already done */
                    171: static void __objc_send_initialize(Class* class)
                    172: {
                    173:   Method_t m;
                    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]);
1.1.1.2 ! root      246:          sarray_at_put_safe (class->dtable,
        !           247:                              (sidx) method->method_name,
        !           248:                              method->method_imp);
1.1       root      249:           counter -= 1;
                    250:         }
                    251:     }
                    252: }
                    253: 
                    254: void __objc_update_dispatch_table_for_class (Class* class)
                    255: {
                    256:   Class* next;
                    257:   struct sarray* save;
                    258: 
                    259:   /* not yet installed -- skip it */
                    260:   if (class->dtable == __objc_uninstalled_dtable) 
                    261:     return;
                    262: 
1.1.1.2 ! root      263:   sarray_free (class->dtable); /* release memory */
        !           264:   __objc_install_premature_dtable (class); /* someone might require it... */
        !           265:   __objc_install_dispatch_table_for_class (class); /* could have been lazy... */
1.1       root      266: 
                    267:   if (class->subclass_list)    /* Traverse subclasses */
                    268:     for (next = class->subclass_list; next; next = next->sibling_class)
                    269:       __objc_update_dispatch_table_for_class (next);
1.1.1.2 ! root      270: 
1.1       root      271: }
                    272: 
                    273: 
                    274: /* This function adds a method list to a class.  This function is
                    275:    typically called by another function specific to the run-time.  As
                    276:    such this function does not worry about thread safe issued.
                    277: 
                    278:    This one is only called for categories. Class objects have their
                    279:    methods installed rightaway, and their selectors are made into
                    280:    SEL's by the function __objc_register_selectors_from_class. */ 
                    281: void
                    282: class_add_method_list (Class* class, MethodList_t list)
                    283: {
                    284:   int i;
                    285:   static SEL initialize_sel = 0;
                    286:   if (!initialize_sel)
                    287:     initialize_sel = sel_register_name ("initialize");
                    288: 
                    289:   /* Passing of a linked list is not allowed.  Do multiple calls.  */
                    290:   assert (!list->method_next);
                    291: 
                    292:   /* Check for duplicates.  */
                    293:   for (i = 0; i < list->method_count; ++i)
                    294:     {
                    295:       Method_t method = &list->method_list[i];
                    296: 
                    297:       if (method->method_name)  /* Sometimes these are NULL */
                    298:        {
                    299:          /* This is where selector names are transmogriffed to SEL's */
                    300:          method->method_name = sel_register_name ((char*)method->method_name);
                    301: 
                    302:          if (search_for_method_in_list (class->methods, method->method_name)
                    303:              && method->method_name != initialize_sel)
                    304:            {
                    305:              /* Duplication. Print a error message an change the method name
                    306:                 to NULL. */
                    307:              fprintf (stderr, "attempt to add a existing method: %s\n",
                    308:                       sel_get_name(method->method_name));
                    309:              method->method_name = 0;
                    310:            }
                    311:        }
                    312:     }
                    313: 
                    314:   /* Add the methods to the class's method list.  */
                    315:   list->method_next = class->methods;
                    316:   class->methods = list;
                    317: }
                    318: 
                    319: 
                    320: Method_t
                    321: class_get_instance_method(Class* class, SEL op)
                    322: {
                    323:   return search_for_method_in_hierarchy(class, op);
                    324: }
                    325: 
                    326: Method_t
                    327: class_get_class_method(MetaClass* class, SEL op)
                    328: {
                    329:   return search_for_method_in_hierarchy(class, op);
                    330: }
                    331: 
                    332: 
                    333: /* Search for a method starting from the current class up its hierarchy.
                    334:    Return a pointer to the method's method structure if found.  NULL
                    335:    otherwise. */   
                    336: 
                    337: static Method_t
                    338: search_for_method_in_hierarchy (Class* cls, SEL sel)
                    339: {
                    340:   Method_t method = NULL;
                    341:   Class* class;
                    342: 
                    343:   if (! sel_is_mapped (sel))
                    344:     return NULL;
                    345: 
                    346:   /* Scan the method list of the class.  If the method isn't found in the
                    347:      list then step to its super class. */
                    348:   for (class = cls; ((! method) && class); class = class->super_class)
                    349:     method = search_for_method_in_list (class->methods, sel);
                    350: 
                    351:   return method;
                    352: }
                    353: 
                    354: 
                    355: 
                    356: /* Given a linked list of method and a method's name.  Search for the named
                    357:    method's method structure.  Return a pointer to the method's method
                    358:    structure if found.  NULL otherwise. */  
                    359: static Method_t
                    360: search_for_method_in_list (MethodList_t list, SEL op)
                    361: {
                    362:   MethodList_t method_list = list;
                    363: 
                    364:   if (! sel_is_mapped (op))
                    365:     return NULL;
                    366: 
                    367:   /* If not found then we'll search the list.  */
                    368:   while (method_list)
                    369:     {
                    370:       int i;
                    371: 
                    372:       /* Search the method list.  */
                    373:       for (i = 0; i < method_list->method_count; ++i)
                    374:         {
                    375:           Method_t method = &method_list->method_list[i];
                    376: 
                    377:           if (method->method_name)
                    378:             if (method->method_name == op)
                    379:               return method;
                    380:         }
                    381: 
                    382:       /* The method wasn't found.  Follow the link to the next list of
                    383:          methods.  */
                    384:       method_list = method_list->method_next;
                    385:     }
                    386: 
                    387:   return NULL;
                    388: }
                    389: 
                    390: 
                    391: /* This fuction is installed in the dispatch table for all methods which are
                    392:    not implemented.  Thus, it is called when a selector is not recognized. */
                    393: static id
                    394: __objc_missing_method (id object, SEL sel, ...)
                    395: {
                    396:   IMP imp;
                    397:   SEL frwd_sel;
                    398:   SEL err_sel;
                    399: 
                    400:   /* first try if the object understands forward:: */
                    401:   frwd_sel = sel_get_uid("forward::");
                    402:   imp = get_imp(object->class_pointer, frwd_sel);
                    403:   if(imp != __objc_missing_method)
                    404:     {
                    405:       void *result, *args = __builtin_apply_args();
                    406:       result = (*imp)(object, frwd_sel, sel, args);
                    407:       __builtin_return(result);
                    408:     }
                    409: 
                    410:   /* If the object recognizes the doesNotRecognize: method then we're going
                    411:      to send it. */
                    412:   err_sel = sel_get_uid ("doesNotRecognize:");
                    413:   imp = get_imp (object->class_pointer, err_sel);
                    414:   if (imp != __objc_missing_method)
                    415:     {
                    416:       return (*imp) (object, err_sel, sel);
                    417:     }
                    418:   
                    419:   /* The object doesn't recognize the method.  Check for responding to
                    420:      error:.  If it does then sent it. */
                    421:   {
                    422:     char msg[256 + strlen ((char*)sel_get_name (sel))
                    423:              + strlen ((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 = %d bytes\n", narrays, narrays*sizeof(struct sarray));
                    455:   total += narrays*sizeof(struct sarray);
                    456:   printf("buckets: %d = %d bytes\n", nbuckets, nbuckets*sizeof(struct sbucket));
                    457:   total += nbuckets*sizeof(struct sbucket);
                    458: 
                    459:   printf("idxtables: %d = %d bytes\n", idxsize, 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.