Annotation of gcc/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: 
        !            30: /* The uninstalled dispatch table */
        !            31: struct sarray* __objc_uninstalled_dtable = 0;
        !            32: 
        !            33: /* Send +initialize to class */
        !            34: static void __objc_send_initialize(Class*);
        !            35: 
        !            36: static void __objc_install_dispatch_table_for_class (Class*);
        !            37: 
        !            38: /* Forward declare some functions */
        !            39: static void __objc_init_install_dtable(id, SEL);
        !            40: static id __objc_missing_method(id, SEL, ...);
        !            41: static Method_t search_for_method_in_hierarchy (Class* class, SEL sel);
        !            42: static Method_t search_for_method_in_list(MethodList_t list, SEL op);
        !            43: id nil_method(id, SEL, ...);
        !            44: 
        !            45: id
        !            46: nil_method(id receiver, SEL op, ...)
        !            47: {
        !            48:   return receiver;
        !            49: }
        !            50: 
        !            51: /* Given a class and selector, return the selector's implementation.  */
        !            52: __inline__ IMP
        !            53: get_imp (Class* class, SEL sel)
        !            54: {
        !            55:   void* res = sarray_get (class->dtable, (size_t) sel);
        !            56:   if(res == __objc_init_install_dtable)
        !            57:     __objc_install_dispatch_table_for_class (class);
        !            58:   return sarray_get (class->dtable, (size_t) sel);
        !            59: }
        !            60: 
        !            61: __inline__ BOOL
        !            62: __objc_responds_to (id object, SEL sel)
        !            63: {
        !            64:   return get_imp (object->class_pointer, sel) != __objc_missing_method;
        !            65: }
        !            66: 
        !            67: /* This is the lookup function.  All entries in the table are either a 
        !            68:    valid method *or* one of `__objc_missing_method' which calls
        !            69:    forward:: etc, or `__objc_init_install_dtable' which installs the
        !            70:    real dtable */
        !            71: __inline__ IMP
        !            72: objc_msg_lookup(id receiver, SEL op)
        !            73: {
        !            74:   if(receiver)
        !            75:     return sarray_get(receiver->class_pointer->dtable, (sidx)op);
        !            76:   else
        !            77:     return nil_method;
        !            78: }
        !            79: 
        !            80: IMP
        !            81: objc_msg_lookup_super (Super_t super, SEL sel)
        !            82: {
        !            83:   if (super->self)
        !            84:     return get_imp (super->class, sel);
        !            85:   else
        !            86:     return nil_method;
        !            87: }
        !            88: 
        !            89: retval_t
        !            90: objc_msg_sendv(id object, SEL op, size_t frame_size, arglist_t arg_frame)
        !            91: {
        !            92: #ifdef __objc_frame_receiver
        !            93:   __objc_frame_receiver(arg_frame) = object;
        !            94:   __objc_frame_selector(arg_frame) = op;
        !            95:   return __builtin_apply((apply_t)get_imp(object->class_pointer, op),
        !            96:                         arg_frame,
        !            97:                         frame_size);
        !            98: #else
        !            99: #warning performv:: will not work
        !           100:   va_list nothing;
        !           101:   (*_objc_error)(object, "objc_msg_sendv (performv::) not supported\n", nothing);
        !           102:   return 0;
        !           103: #endif
        !           104: }
        !           105: 
        !           106: void __objc_init_dispatch_tables()
        !           107: {
        !           108:   __objc_uninstalled_dtable
        !           109:     = sarray_new(200, __objc_init_install_dtable);
        !           110: }
        !           111: 
        !           112: /* This one is a bit hairy.  This function is installed in the 
        !           113:    premature dispatch table, and thus called once for each class,
        !           114:    namely when the very first message is send to it.  */
        !           115: 
        !           116: static void __objc_init_install_dtable(id receiver, SEL op)
        !           117: {
        !           118:   __label__ allready_initialized;
        !           119:   IMP imp;
        !           120:   void* args;
        !           121:   void* result;
        !           122: 
        !           123:   /* This may happen, if the programmer has taken the address of a 
        !           124:      method before the dtable was initialized... too bad for him! */
        !           125:   if(receiver->class_pointer->dtable != __objc_uninstalled_dtable)
        !           126:     goto allready_initialized;
        !           127: 
        !           128:   if(CLS_ISCLASS(receiver->class_pointer))
        !           129:     {
        !           130:       /* receiver is an ordinary object */
        !           131:       assert(CLS_ISCLASS(receiver->class_pointer));
        !           132: 
        !           133:       /* install instance methods table */
        !           134:       __objc_install_dispatch_table_for_class (receiver->class_pointer);
        !           135: 
        !           136:       /* call +initialize -- this will in turn install the factory 
        !           137:         dispatch table if not already done :-) */
        !           138:       __objc_send_initialize(receiver->class_pointer);
        !           139:     }
        !           140:   else
        !           141:     {
        !           142:       /* receiver is a class object */
        !           143:       assert(CLS_ISCLASS((Class*)receiver));
        !           144:       assert(CLS_ISMETA(receiver->class_pointer));
        !           145: 
        !           146:       /* Install real dtable for factory methods */
        !           147:       __objc_install_dispatch_table_for_class (receiver->class_pointer);
        !           148:       
        !           149:       if(op != sel_get_uid ("initialize"))
        !           150:        __objc_send_initialize((Class*)receiver);
        !           151:       else
        !           152:        CLS_SETINITIALIZED((Class*)receiver);
        !           153:     }
        !           154: 
        !           155: allready_initialized:
        !           156:   
        !           157:   /* Get real method for this in newly installed dtable */
        !           158:   imp = get_imp(receiver->class_pointer, op);
        !           159: 
        !           160:   args = __builtin_apply_args();
        !           161:   result = __builtin_apply((apply_t)imp, args, 96);
        !           162:   __builtin_return (result);
        !           163:   
        !           164: }
        !           165: 
        !           166: /* Install dummy table for class which causes the first message to
        !           167:    that class (or instances hereof) to be initialized properly */
        !           168: void __objc_install_premature_dtable(Class* class)
        !           169: {
        !           170:   assert(__objc_uninstalled_dtable);
        !           171:   class->dtable = __objc_uninstalled_dtable;
        !           172: }   
        !           173: 
        !           174: /* Send +initialize to class if not already done */
        !           175: static void __objc_send_initialize(Class* class)
        !           176: {
        !           177:   Method_t m;
        !           178: 
        !           179:   /* This *must* be a class object */
        !           180:   assert(CLS_ISCLASS(class));
        !           181:   assert(!CLS_ISMETA(class));
        !           182: 
        !           183:   if (!CLS_ISINITIALIZED(class))
        !           184:     {
        !           185:       CLS_SETINITIALIZED(class);
        !           186:       CLS_SETINITIALIZED(class->class_pointer);
        !           187:       
        !           188:       if(class->super_class)
        !           189:        __objc_send_initialize(class->super_class);
        !           190: 
        !           191:       {
        !           192:        MethodList_t method_list = class->class_pointer->methods;
        !           193:        SEL op = sel_register_name ("initialize");
        !           194: 
        !           195:        /* If not found then we'll search the list.  */
        !           196:        while (method_list)
        !           197:          {
        !           198:            int i;
        !           199: 
        !           200:            /* Search the method list.  */
        !           201:            for (i = 0; i < method_list->method_count; ++i)
        !           202:              {
        !           203:                Method_t method = &method_list->method_list[i];
        !           204:                
        !           205:                
        !           206:                if (method->method_name == op)
        !           207:                  (*method->method_imp)((id) class, op);
        !           208:              }
        !           209: 
        !           210:            /* The method wasn't found.  Follow the link to the next list of
        !           211:               methods.  */
        !           212:            method_list = method_list->method_next;
        !           213:          }
        !           214:       }
        !           215:     }
        !           216: }  
        !           217: 
        !           218: static void
        !           219: __objc_install_dispatch_table_for_class (Class* class)
        !           220: {
        !           221:   Class* super;
        !           222:   MethodList_t mlist;
        !           223:   int counter;
        !           224: 
        !           225:   /* If the class has not yet had it's class links resolved, we must 
        !           226:      re-compute all class links */
        !           227:   if(!CLS_ISRESOLV(class))
        !           228:     __objc_resolve_class_links();
        !           229: 
        !           230:   super = class->super_class;
        !           231: 
        !           232:   if (super != 0 && (super->dtable == __objc_uninstalled_dtable))
        !           233:     __objc_install_dispatch_table_for_class (super);
        !           234: 
        !           235:   /* Allocate dtable if nessecary */
        !           236:   if (super == 0)
        !           237:     {
        !           238:       class->dtable = sarray_new (__objc_selector_max_index,
        !           239:                                  __objc_missing_method);
        !           240:     }
        !           241:   else
        !           242:     class->dtable = sarray_lazy_copy (super->dtable);
        !           243: 
        !           244:   for (mlist = class->methods; mlist; mlist = mlist->method_next)
        !           245:     {
        !           246:       counter = mlist->method_count - 1;
        !           247:       while (counter >= 0)
        !           248:         {
        !           249:           Method_t method = &(mlist->method_list[counter]);
        !           250:          sarray_at_put (class->dtable,
        !           251:                         (sidx) method->method_name,
        !           252:                         method->method_imp);
        !           253:           counter -= 1;
        !           254:         }
        !           255:     }
        !           256: }
        !           257: 
        !           258: void __objc_update_dispatch_table_for_class (Class* class)
        !           259: {
        !           260:   Class* next;
        !           261:   struct sarray* save;
        !           262: 
        !           263:   /* not yet installed -- skip it */
        !           264:   if (class->dtable == __objc_uninstalled_dtable) 
        !           265:     return;
        !           266: 
        !           267:   save = class->dtable;
        !           268:   __objc_install_premature_dtable (class);
        !           269:   sarray_free (save);
        !           270: 
        !           271: 
        !           272:   if (class->subclass_list)    /* Traverse subclasses */
        !           273:     for (next = class->subclass_list; next; next = next->sibling_class)
        !           274:       __objc_update_dispatch_table_for_class (next);
        !           275: }
        !           276: 
        !           277: 
        !           278: /* This function adds a method list to a class.  This function is
        !           279:    typically called by another function specific to the run-time.  As
        !           280:    such this function does not worry about thread safe issued.
        !           281: 
        !           282:    This one is only called for categories. Class objects have their
        !           283:    methods installed rightaway, and their selectors are made into
        !           284:    SEL's by the function __objc_register_selectors_from_class. */ 
        !           285: void
        !           286: class_add_method_list (Class* class, MethodList_t list)
        !           287: {
        !           288:   int i;
        !           289:   static SEL initialize_sel = 0;
        !           290:   if (!initialize_sel)
        !           291:     initialize_sel = sel_register_name ("initialize");
        !           292: 
        !           293:   /* Passing of a linked list is not allowed.  Do multiple calls.  */
        !           294:   assert (!list->method_next);
        !           295: 
        !           296:   /* Check for duplicates.  */
        !           297:   for (i = 0; i < list->method_count; ++i)
        !           298:     {
        !           299:       Method_t method = &list->method_list[i];
        !           300: 
        !           301:       if (method->method_name)  /* Sometimes these are NULL */
        !           302:        {
        !           303:          /* This is where selector names are transmogriffed to SEL's */
        !           304:          method->method_name = sel_register_name ((char*)method->method_name);
        !           305: 
        !           306:          if (search_for_method_in_list (class->methods, method->method_name)
        !           307:              && method->method_name != initialize_sel)
        !           308:            {
        !           309:              /* Duplication. Print a error message an change the method name
        !           310:                 to NULL. */
        !           311:              fprintf (stderr, "attempt to add a existing method: %s\n",
        !           312:                       sel_get_name(method->method_name));
        !           313:              method->method_name = 0;
        !           314:            }
        !           315:        }
        !           316:     }
        !           317: 
        !           318:   /* Add the methods to the class's method list.  */
        !           319:   list->method_next = class->methods;
        !           320:   class->methods = list;
        !           321: }
        !           322: 
        !           323: 
        !           324: Method_t
        !           325: class_get_instance_method(Class* class, SEL op)
        !           326: {
        !           327:   return search_for_method_in_hierarchy(class, op);
        !           328: }
        !           329: 
        !           330: Method_t
        !           331: class_get_class_method(MetaClass* class, SEL op)
        !           332: {
        !           333:   return search_for_method_in_hierarchy(class, op);
        !           334: }
        !           335: 
        !           336: 
        !           337: /* Search for a method starting from the current class up its hierarchy.
        !           338:    Return a pointer to the method's method structure if found.  NULL
        !           339:    otherwise. */   
        !           340: 
        !           341: static Method_t
        !           342: search_for_method_in_hierarchy (Class* cls, SEL sel)
        !           343: {
        !           344:   Method_t method = NULL;
        !           345:   Class* class;
        !           346: 
        !           347:   if (! sel_is_mapped (sel))
        !           348:     return NULL;
        !           349: 
        !           350:   /* Scan the method list of the class.  If the method isn't found in the
        !           351:      list then step to its super class. */
        !           352:   for (class = cls; ((! method) && class); class = class->super_class)
        !           353:     method = search_for_method_in_list (class->methods, sel);
        !           354: 
        !           355:   return method;
        !           356: }
        !           357: 
        !           358: 
        !           359: 
        !           360: /* Given a linked list of method and a method's name.  Search for the named
        !           361:    method's method structure.  Return a pointer to the method's method
        !           362:    structure if found.  NULL otherwise. */  
        !           363: static Method_t
        !           364: search_for_method_in_list (MethodList_t list, SEL op)
        !           365: {
        !           366:   MethodList_t method_list = list;
        !           367: 
        !           368:   if (! sel_is_mapped (op))
        !           369:     return NULL;
        !           370: 
        !           371:   /* If not found then we'll search the list.  */
        !           372:   while (method_list)
        !           373:     {
        !           374:       int i;
        !           375: 
        !           376:       /* Search the method list.  */
        !           377:       for (i = 0; i < method_list->method_count; ++i)
        !           378:         {
        !           379:           Method_t method = &method_list->method_list[i];
        !           380: 
        !           381:           if (method->method_name)
        !           382:             if (method->method_name == op)
        !           383:               return method;
        !           384:         }
        !           385: 
        !           386:       /* The method wasn't found.  Follow the link to the next list of
        !           387:          methods.  */
        !           388:       method_list = method_list->method_next;
        !           389:     }
        !           390: 
        !           391:   return NULL;
        !           392: }
        !           393: 
        !           394: 
        !           395: /* This fuction is installed in the dispatch table for all methods which are
        !           396:    not implemented.  Thus, it is called when a selector is not recognized. */
        !           397: static id
        !           398: __objc_missing_method (id object, SEL sel, ...)
        !           399: {
        !           400:   IMP imp;
        !           401:   SEL frwd_sel;
        !           402:   SEL err_sel;
        !           403: 
        !           404:   /* first try if the object understands forward:: */
        !           405:   frwd_sel = sel_get_uid("forward::");
        !           406:   imp = get_imp(object->class_pointer, frwd_sel);
        !           407:   if(imp != __objc_missing_method)
        !           408:     {
        !           409:       void *result, *args = __builtin_apply_args();
        !           410:       result = (*imp)(object, frwd_sel, sel, args);
        !           411:       __builtin_return(result);
        !           412:     }
        !           413: 
        !           414:   /* If the object recognizes the doesNotRecognize: method then we're going
        !           415:      to send it. */
        !           416:   err_sel = sel_get_uid ("doesNotRecognize:");
        !           417:   imp = get_imp (object->class_pointer, err_sel);
        !           418:   if (imp != __objc_missing_method)
        !           419:     {
        !           420:       return (*imp) (object, err_sel, sel);
        !           421:     }
        !           422:   
        !           423:   /* The object doesn't recognize the method.  Check for responding to
        !           424:      error:.  If it does then sent it. */
        !           425:   {
        !           426:     char msg[256 + strlen ((char*)sel_get_name (sel))
        !           427:              + strlen ((char*)object->class_pointer->name)];
        !           428: 
        !           429:     sprintf (msg, "(%s) %s does not recognize %s",
        !           430:             (CLS_ISMETA(object->class_pointer)
        !           431:              ? "class"
        !           432:              : "instance" ),
        !           433:              object->class_pointer->name, sel_get_name (sel));
        !           434: 
        !           435:     err_sel = sel_get_uid ("error:");
        !           436:     imp = get_imp (object->class_pointer, err_sel);
        !           437:     if (imp != __objc_missing_method)
        !           438:       return (*imp) (object, sel_get_uid ("error:"), msg);
        !           439: 
        !           440:     /* The object doesn't respond to doesNotRecognize: or error:;  Therefore,
        !           441:        a default action is taken. */
        !           442:     fprintf (stderr, "fatal: %s\n", msg);
        !           443:     abort ();
        !           444:   }
        !           445: }
        !           446: 
        !           447: void __objc_print_dtable_stats()
        !           448: {
        !           449:   int total = 0;
        !           450:   printf("memory usage: (%s)\n",
        !           451: #ifdef OBJC_SPARSE2
        !           452:         "2-level sparse arrays"
        !           453: #else
        !           454:         "3-level sparse arrays"
        !           455: #endif
        !           456:         );
        !           457: 
        !           458:   printf("arrays: %d = %d bytes\n", narrays, narrays*sizeof(struct sarray));
        !           459:   total += narrays*sizeof(struct sarray);
        !           460:   printf("buckets: %d = %d bytes\n", nbuckets, nbuckets*sizeof(struct sbucket));
        !           461:   total += nbuckets*sizeof(struct sbucket);
        !           462: 
        !           463:   printf("idxtables: %d = %d bytes\n", idxsize, idxsize*sizeof(void*));
        !           464:   total += idxsize*sizeof(void*);
        !           465:   printf("-----------------------------------\n");
        !           466:   printf("total: %d bytes\n", total);
        !           467:   printf("===================================\n");
        !           468: }
        !           469: 
        !           470: 
        !           471: 

unix.superglobalmegacorp.com

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