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

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: 

unix.superglobalmegacorp.com

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