Annotation of GNUtools/cc/objc/sendmsg.c, revision 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.