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

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

unix.superglobalmegacorp.com

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