Annotation of gcc/objc/core.c, revision 1.1

1.1     ! root        1: /* Method dispatcher and class-object creator for Objective C.
        !             2:    Copyright (C) 1992 Free Software Foundation, Inc.
        !             3: 
        !             4: This file is part of GNU CC.
        !             5: 
        !             6: GNU CC is free software; you can redistribute it and/or modify
        !             7: it under the terms of the GNU General Public License as published by
        !             8: the Free Software Foundation; either version 2, or (at your option)
        !             9: any later version.
        !            10: 
        !            11: GNU CC is distributed in the hope that it will be useful,
        !            12: but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            14: GNU General Public License for more details.
        !            15: 
        !            16: You should have received a copy of the GNU General Public License
        !            17: along with GNU CC; see the file COPYING.  If not, write to
        !            18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
        !            19: 
        !            20: /* As a special exception, if you link this library with files
        !            21:    compiled with GCC to produce an executable, this does not cause
        !            22:    the resulting executable to be covered by the GNU General Public License.
        !            23:    This exception does not however invalidate any other reasons why
        !            24:    the executable file might be covered by the GNU General Public License.  */
        !            25: 
        !            26: #include "tconfig.h"
        !            27: #include "assert.h"
        !            28: #include <ctype.h>
        !            29: #include "gstdarg.h"
        !            30: #include <stdio.h>
        !            31: #include "gstddef.h"
        !            32: 
        !            33: #include "hash.h"
        !            34: #include "objc.h"
        !            35: #include "objc-proto.h"
        !            36: 
        !            37: 
        !            38: #define MODULE_HASH_SIZE 32   /* Initial module hash table size.
        !            39:                                 Value doesn't really matter.  */
        !            40: 
        !            41: #define CLASS_HASH_SIZE 32    /* Initial number of buckets size of
        !            42:                                 class hash table.  Value doesn't
        !            43:                                 really matter.  */
        !            44: 
        !            45: 
        !            46: /* Forward declare some functions.  */
        !            47: id            objc_object_create (Class_t),
        !            48:               objc_object_dispose (id),
        !            49:               objc_object_realloc (id, unsigned int),
        !            50:               objc_object_copy (id);
        !            51: void          objc_error (id object, const char *fmt, va_list ap);
        !            52: static id     nil_method (id, SEL, ...);
        !            53: static id     return_error_static (id, SEL, ...);
        !            54: static IMP    handle_runtime_error (id, SEL);
        !            55: static void   initialize_dispatch_tables (void);
        !            56: static SEL    record_selector (const char*);
        !            57: static void   record_methods_from_class (Class_t);
        !            58: static void   record_methods_from_list (MethodList_t);
        !            59: static void   initialize_class (const char*);
        !            60: /*
        !            61:  * This is a hash table of Class_t structures. 
        !            62:  *
        !            63:  * At initialization the executable is searched for all Class_t structures. 
        !            64:  * Since these structures are created by the compiler they are therefore
        !            65:  * located in the TEXT segment.  
        !            66:  *
        !            67:  * A identical structure is allocated from the free store and initialized from
        !            68:  * its TEXT counterpart and placed in the hash table using the TEXT part as
        !            69:  * its key. 
        !            70:  *
        !            71:  * Since the free store structure is now writable, additional initialization
        !            72:  * takes place such as its "info" variable, method cache allocation, and
        !            73:  * linking of all of its method and ivar lists from multiple implementations. 
        !            74:  */
        !            75: cache_ptr      class_hash_table = NULL;
        !            76: 
        !            77: /*
        !            78:  * This variable is a flag used within the messaging routines.  If a
        !            79:  * application sets it to !0 then the messager will print messages sent to
        !            80:  * objects. 
        !            81:  */
        !            82: BOOL  objc_trace = NO;
        !            83: 
        !            84: /* This mutex provides a course lock for method dispatch.  */
        !            85: MUTEX  runtimeMutex;
        !            86: 
        !            87: /*
        !            88:  * This hash table is used by the initialization routines.  When the
        !            89:  * constructor function (__objc_execClass) is called it is passed a pointer
        !            90:  * to a module structure.  That pointer is stored in this table and its
        !            91:  * contents are processed in __objcInit. 
        !            92:  */
        !            93: cache_ptr    module_hash_table = NULL;
        !            94: 
        !            95: /*
        !            96:  * This hash table is used in the constructor subroutine to hold pointers 
        !            97:  * to categories that have not been attached to a class.  Constructors are
        !            98:  * received in a random order.  Files may contain category implementation
        !            99:  * of objects whose constructor hasn't been executed yet.  Therefore, 
        !           100:  * there is no object to attach the categories.
        !           101:  *
        !           102:  * This hash table holds pointers to categories that haven't been
        !           103:  * attached to objects.  As objects are processed the category hash
        !           104:  * table is searched for attachments.  If a category is found for the
        !           105:  * object it is attached to the object and deleted from the hash table.
        !           106:  */
        !           107: cache_ptr    unclaimed_category_hash_table = NULL;
        !           108: 
        !           109: /*
        !           110:  * This flag is used by the messager routines to determine if the run-time
        !           111:  * has been initialized.  If the run-time isn't initialized then a
        !           112:  * initialization clean up routine is called. 
        !           113:  */
        !           114: static int     initialized = 0;
        !           115: 
        !           116: /*
        !           117:  * Records that hold pointers to arrays of records.  The terminal records are
        !           118:  * method implementations. 
        !           119:  *
        !           120:  * The size of the first record is the number of unique classes in the
        !           121:  * executable.  The second is the number of selectors. 
        !           122:  *
        !           123:  * The second record conatins methods that are visible to the class -- that is,
        !           124:  * methods that are not overriden from the classt to the root object. 
        !           125:  *
        !           126:  * The cache pointers of class and meta class structures point to one of these
        !           127:  * records. 
        !           128:  */
        !           129: static struct record *instance_method_record   = NULL;
        !           130: static struct record *factory_method_record    = NULL;
        !           131: 
        !           132: /*
        !           133:  * This structure is used to translate between selectors and their ASCII
        !           134:  * representation.  A NULL terminated array of char*,
        !           135:  * OBJC_SELECTOR_REFERENCES, is passed to the constructor routine: 
        !           136:  * __objc_execClass. That routine places entries from that array into this
        !           137:  * structure.  The location within OBJC_SELECTOR_REFERENCES where the string
        !           138:  * was taken from is replaced with a small integer, the index into the array
        !           139:  * inside selectorTranslateTable.  That integer then becomes the selector. 
        !           140:  *
        !           141:  * Selectors begin at 1 to numEntries.  A selector outside of that range is
        !           142:  * considered an error.  The selector integers are used as the first index
        !           143:  * into the instance_method_record and factory_method_record arrays. 
        !           144:  */
        !           145: static struct record *selector_record = NULL;
        !           146: 
        !           147: /*
        !           148:  * This data structure is used in the special case where usual fatal error
        !           149:  * functions are called but have been overridden in a class.  The value
        !           150:  * returned by that function is returned to the calling object.  error_static
        !           151:  * holds the returned value until it is retrieved by return_error_static
        !           152:  * which returns it to the calling function. 
        !           153:  */
        !           154: static id      error_static;
        !           155: 
        !           156: 
        !           157: /* Given a class and selector, return the selector's implementation.  */
        !           158: static inline IMP      
        !           159: get_imp (Class_t class, SEL sel)
        !           160: {
        !           161:   IMP  imp = NULL;
        !           162:   imp = record_get (getClassNumber (class),
        !           163:                    record_get ((unsigned int)sel, *class->cache));
        !           164: 
        !           165:   return imp;
        !           166: }
        !           167: 
        !           168: 
        !           169: static void
        !           170: error (msg, arg1, arg2)
        !           171:      char *msg, *arg1, *arg2;
        !           172: {
        !           173: #if 0 /* There is no portable way to get the program name.  Too bad.  */
        !           174:   fprintf (stderr, "%s: ", programname);
        !           175: #endif
        !           176:   fprintf (stderr, msg, arg1, arg2);
        !           177:   fprintf (stderr, "\n");
        !           178: }
        !           179: 
        !           180: static void
        !           181: fatal (msg, arg1, arg2)
        !           182:      char *msg, *arg1, *arg2;
        !           183: {
        !           184:   error (msg, arg1, arg2);
        !           185:   exit (1);
        !           186: }
        !           187: 
        !           188: static void *
        !           189: xmalloc (unsigned int size)
        !           190: {
        !           191:   void *ptr = (void *) malloc (size);
        !           192:   if (ptr == 0)
        !           193:     fatal ("virtual memory exceeded");
        !           194:   return ptr;
        !           195: }
        !           196: 
        !           197: static void *
        !           198: xcalloc (unsigned int size, unsigned int units)
        !           199: {
        !           200:   void *ptr = (void *) calloc (size, units);
        !           201:   if (ptr == 0)
        !           202:     fatal ("virtual memory exceeded");
        !           203:   return ptr;
        !           204: }
        !           205: 
        !           206: void *
        !           207: __objc_xmalloc (unsigned int size)
        !           208: {
        !           209:   void *ptr = (void *) malloc (size);
        !           210:   if (ptr == 0)
        !           211:     fatal ("virtual memory exceeded");
        !           212:   return ptr;
        !           213: }
        !           214: 
        !           215: void *
        !           216: __objc_xrealloc (void *optr, unsigned int size)
        !           217: {
        !           218:   void *ptr = (void *) realloc (optr, size);
        !           219:   if (ptr == 0)
        !           220:     fatal ("virtual memory exceeded");
        !           221:   return ptr;
        !           222: }
        !           223: 
        !           224: void *
        !           225: __objc_xcalloc (unsigned int size, unsigned int units)
        !           226: {
        !           227:   void *ptr = (void *) calloc (size, units);
        !           228:   if (ptr == 0)
        !           229:     fatal ("virtual memory exceeded");
        !           230:   return ptr;
        !           231: }
        !           232: 
        !           233: static inline char *
        !           234: my_strdup (const char *str)
        !           235: {
        !           236:   char *new = (char *) xmalloc (strlen (str) + 1);
        !           237:   strcpy (new, str);
        !           238:        
        !           239:   return new;
        !           240: }
        !           241: 
        !           242: 
        !           243: /*
        !           244:  * This function is called by constructor functions generated for each module
        !           245:  * compiled.  
        !           246:  *
        !           247:  * The purpose of this function is to gather the module pointers so that they
        !           248:  * may be processed by the initialization clean up routine. 
        !           249:  */
        !           250: void 
        !           251: __objc_execClass (Module_t module)
        !           252: {
        !           253:   /* Has we processed any constructors previously? 
        !           254:      Flag used to indicate that some global data structures
        !           255:      need to be built.  */
        !           256:   static BOOL previous_constructors = 0;
        !           257: 
        !           258:   Symtab_t    symtab = module->symtab;
        !           259:   Class_t     object_class;
        !           260:   node_ptr node;
        !           261:   SEL         *(*selectors)[] = (SEL *(*)[])symtab->refs;
        !           262:   int         i;
        !           263:   BOOL        incomplete = 0;
        !           264: 
        !           265: 
        !           266:   assert (module->size == sizeof (Module));
        !           267:   DEBUG_PRINTF ("received load module: %s\n",module->name);
        !           268: 
        !           269:   /* Header file data structure hack test.  */
        !           270:   assert (sizeof (Class) == sizeof (MetaClass));
        !           271: 
        !           272:   /* On the first call of this routine, initialize
        !           273:      some data structures.  */
        !           274:   if (!previous_constructors) {
        !           275: 
        !           276:     /* Enable malloc debugging. This'll slow'er down! */
        !           277: #if defined (DEBUG) && defined (NeXT)
        !           278:     malloc_debug (62);
        !           279: #endif
        !           280: 
        !           281:     /* Allocate and initialize the mutex.  */
        !           282:     MUTEX_ALLOC (&runtimeMutex);
        !           283:     MUTEX_INIT (runtimeMutex);
        !           284: 
        !           285:     /* Allocate the module hash table.  */
        !           286:     module_hash_table
        !           287:       = hash_new (MODULE_HASH_SIZE, (hash_func_type)hash_ptr,
        !           288:                  (compare_func_type)compare_ptrs);
        !           289: 
        !           290:     /* Allocate a table for unclaimed categories.  */
        !           291:     unclaimed_category_hash_table
        !           292:       = hash_new (16, (hash_func_type)hash_ptr,
        !           293:                  (compare_func_type)compare_ptrs);
        !           294: 
        !           295:     /* Allocate a master selector table if it doesn't exist.  */
        !           296:     selector_record = record_new ();
        !           297:     
        !           298:     previous_constructors = 1;
        !           299:   }
        !           300: 
        !           301:   /* Save the module pointer for later processing.  */
        !           302:   hash_add (&module_hash_table, module, module);
        !           303: 
        !           304:   /* Parse the classes in the load module and gather selector information.  */
        !           305:   DEBUG_PRINTF ("gathering selectors from module: %s\n",module->name);
        !           306:   for (i = 0; i < symtab->cls_def_cnt; ++i) {
        !           307:     Class_t class = (Class_t)symtab->defs[i];
        !           308: 
        !           309:     /* Make sure we have what we think.  */
        !           310:     assert (class->info & CLS_CLASS);
        !           311:     assert (class->class_pointer->info & CLS_META);
        !           312:     DEBUG_PRINTF ("phase 1, processing class: %s\n", class->name);
        !           313: 
        !           314:     /* Store the class in the class table and assign class numbers.  */
        !           315:     addClassToHash (class);
        !           316: 
        !           317:     /* Store all of the selectors in the class and meta class.  */
        !           318:     record_methods_from_class (class);
        !           319:     record_methods_from_class ((Class_t)class->class_pointer);
        !           320: 
        !           321:     /* Initialize the cache pointers.  */
        !           322:     class->cache = &instance_method_record;
        !           323:     class->class_pointer->cache = &factory_method_record;
        !           324:   }
        !           325: 
        !           326:   /* Replace referenced selectors.  */
        !           327:   for (i=0; i < symtab->sel_ref_cnt; ++i)
        !           328:     (*selectors)[i] = record_selector ((const char*)(*selectors)[i]);
        !           329: 
        !           330:   /* Try to build the class hierarchy and initialize the data structures.  */
        !           331:   object_class = objc_getClass ("Object");
        !           332:   if (object_class) {
        !           333:     
        !           334:     /* Make sure we have what we think we have.  */
        !           335:     assert (object_class->class_pointer->info & CLS_META);
        !           336:     assert (object_class->info & CLS_CLASS);
        !           337:     
        !           338:     /* Connect the classes together (at least as much as we can).  */ 
        !           339:     for (node = hash_next (class_hash_table, NULL); node;
        !           340:         node = hash_next (class_hash_table, node)) {
        !           341:       Class_t class1 = node->value;
        !           342: 
        !           343:       /* Make sure we have what we think we have.  */
        !           344:       assert (class1->info & CLS_CLASS);
        !           345:       assert (class1->class_pointer->info & CLS_META);
        !           346: 
        !           347:       /* The class_pointer of all meta classes point to Object's meta class.  */
        !           348:       class1->class_pointer->class_pointer = object_class->class_pointer; 
        !           349: 
        !           350:       /* Assign super class pointers */
        !           351:       if (class1->super_class) {
        !           352:        Class_t aSuperClass = objc_getClass ((char*)class1->super_class);
        !           353: 
        !           354:        if (aSuperClass) {
        !           355: 
        !           356:          DEBUG_PRINTF ("making class connections for: %s\n", 
        !           357:                        class1->name);
        !           358: 
        !           359:          class1->super_class = aSuperClass; 
        !           360:          if (class1->class_pointer->super_class)
        !           361:            class1->class_pointer->super_class = class1->super_class->class_pointer;
        !           362: 
        !           363:          /* Mark the class as initialized.  */
        !           364:          class1->info |= CLS_RTI;
        !           365:        } else
        !           366:          /* Couldn't find the class's super class.  */
        !           367:          incomplete = 1;
        !           368:       }
        !           369:     }
        !           370:   } else
        !           371:     /* Couldn't find class Object.  */
        !           372:     incomplete = 1;
        !           373: 
        !           374:   /* Process category information from the module.  */
        !           375:   for (i = 0; i < symtab->cat_def_cnt; ++i) {
        !           376:     Category_t  category = symtab->defs[i + symtab->cls_def_cnt];
        !           377:     Class_t     class = objc_getClass (category->class_name);
        !           378: 
        !           379:     /* If the class for the category exists then append its
        !           380:        methods.  */
        !           381:     if (class) {
        !           382: 
        !           383:       DEBUG_PRINTF ("processing categories from (module,object): %s, %s\n",
        !           384:                    module->name, 
        !           385:                    class_getClassName (class));
        !           386: 
        !           387:       /* Do instance methods.  */
        !           388:       if (category->instance_methods)
        !           389:         addMethodsToClass (class, category->instance_methods);
        !           390: 
        !           391:       /* Do class methods.  */
        !           392:       if (category->class_methods)
        !           393:         addMethodsToClass ((Class_t)class->class_pointer, category->class_methods);
        !           394:     } else {
        !           395:       /* The object to which the category methods belong can't
        !           396:         be found.  Save the information.  */
        !           397:       hash_add (&unclaimed_category_hash_table, category, category);
        !           398: 
        !           399:       incomplete = 1;
        !           400:     }
        !           401:   }
        !           402: 
        !           403:   /* Scan the unclaimed category hash.  
        !           404:      Attempt to attach any unclaimed categories to objects.  */
        !           405:   for (node = hash_next (unclaimed_category_hash_table, NULL); node;
        !           406:        node = hash_next (unclaimed_category_hash_table, node)) {
        !           407:     Category_t  category = node->value;
        !           408:     Class_t     class = objc_getClass (category->class_name);
        !           409: 
        !           410:     if (class) {
        !           411: 
        !           412:       DEBUG_PRINTF ("attaching stored categories to object: %s\n",
        !           413:                    class_getClassName (class));
        !           414: 
        !           415:       /* Delete this class from the hash table.  */
        !           416:       hash_remove (unclaimed_category_hash_table, category);
        !           417:       node = NULL;
        !           418: 
        !           419:       if (category->instance_methods)
        !           420:        addMethodsToClass (class, category->instance_methods);
        !           421: 
        !           422:       if (category->class_methods)
        !           423:        addMethodsToClass ((Class_t)class->class_pointer,
        !           424:                           category->class_methods);
        !           425:     } else
        !           426:       incomplete = 1;
        !           427:   }
        !           428: 
        !           429:   /* Can we finish the run time initialization? */
        !           430:   if (!incomplete) {
        !           431: 
        !           432:     initialize_dispatch_tables ();
        !           433: 
        !           434:     /* Debug run time test.
        !           435:        We're initialized! */
        !           436:     initialized = 1;
        !           437: 
        !           438:     /* Print out class tables if debugging.  */
        !           439:     DEBUG_PRINTF ("dump of class tables from objcInit\n");
        !           440:     debug_dump_classes ();
        !           441:   }
        !           442: 
        !           443: }
        !           444: 
        !           445: 
        !           446: IMP  
        !           447: objc_msgSend (id receiver, SEL sel)
        !           448: {
        !           449:   /*
        !           450:    * A method is always called by the compiler.  If a method wasn't
        !           451:    * found then supply a default. 
        !           452:    */
        !           453:   IMP  imp = nil_method;
        !           454: 
        !           455: 
        !           456:   /* The run time must be initialized at this point.
        !           457:      Otherwise we get a message sent to a object with a bogus selector.  */
        !           458:   assert (initialized);
        !           459: 
        !           460:   /* Objective-C allows messages to be sent to a nil object.  */
        !           461:   if (receiver) {
        !           462: 
        !           463:     /* Check for common programmer error.  */
        !           464:     if (!receiver->class_pointer) {
        !           465:       fprintf (stderr, "method %s sent to deallocated object %#x\n", 
        !           466:               sel_getName (sel), receiver);
        !           467:       abort ();
        !           468:     }
        !           469:     
        !           470:     /* Initialize the class if need be.  */
        !           471:     if (!(receiver->class_pointer->info & CLS_INITIALIZED))
        !           472:       initialize_class (receiver->class_pointer->name);
        !           473: 
        !           474:     /*
        !           475:      * If we're passed a object then its class_pointer is a Class.  If
        !           476:      * we're passed a Class then its class_pointer is a MetaClass. 
        !           477:      * Therefore, searching for a instance or class method
        !           478:      * requires no special decision making here. 
        !           479:      *
        !           480:      * Look for the method. 
        !           481:      */
        !           482:     imp = get_imp (receiver->class_pointer, sel);
        !           483: 
        !           484:     /* If the method cannot be found then perform error handling.  */
        !           485:     if (!imp)
        !           486:       imp = handle_runtime_error (receiver, sel);
        !           487:   }
        !           488: 
        !           489:   /* Nice debugging messages if enabled.  */
        !           490:   if (objc_trace) {
        !           491:     printf ("trace: objc_msgSend , obj=%#x, class=%s, method=%s\n",
        !           492:            receiver, 
        !           493:            receiver->class_pointer->name, 
        !           494:            sel_getName (sel));
        !           495:     fflush (stdout);
        !           496:   }
        !           497:   
        !           498:   return imp;
        !           499: }
        !           500: 
        !           501: 
        !           502: IMP 
        !           503: objc_msgSendSuper (Super_t super, SEL sel)
        !           504: {
        !           505:   IMP  imp;
        !           506: 
        !           507: 
        !           508:   assert (initialized);
        !           509: 
        !           510:   if (!(super->class->info & CLS_INITIALIZED))
        !           511:     initialize_class (super->class->name);
        !           512:   if (!(super->receiver->class_pointer->info & CLS_INITIALIZED))
        !           513:     initialize_class (super->receiver->class_pointer->name);
        !           514: 
        !           515:   imp = get_imp (super->class, sel);
        !           516:   
        !           517:   if (!imp)
        !           518:     imp = handle_runtime_error (super->receiver, sel);
        !           519: 
        !           520:   if (objc_trace) {
        !           521:     printf ("trace: objc_msgSendSuper , obj=%#x, class=%s, method=%s\n",
        !           522:            super->receiver, 
        !           523:            super->receiver->class_pointer->name, 
        !           524:            sel_getName (sel));
        !           525:     fflush (stdout);
        !           526:   }
        !           527: 
        !           528:   return imp;
        !           529: }
        !           530: 
        !           531: 
        !           532: /*
        !           533:  * This function is called by objc_msgSend or objc_msgSendSuper when a
        !           534:  * message is sent to a object which it does not recognize. 
        !           535:  */
        !           536: static IMP  
        !           537: handle_runtime_error (id object, SEL sel)
        !           538: {
        !           539:   IMP  imp;
        !           540: 
        !           541: 
        !           542:   /*
        !           543:    * If the object recognizes the doesNotRecognize: method then we're
        !           544:    * going to send it. 
        !           545:    */
        !           546:   imp = get_imp (object->class_pointer, sel_getUid ("doesNotRecognize:"));
        !           547:   if (imp)
        !           548:     error_static = (*imp)(object, sel_getUid ("doesNotRecognize:"), sel);
        !           549:   else {
        !           550:     /*
        !           551:      * The object doesn't recognize the method.  Check for
        !           552:      * responding to error:.  If it does then sent it. 
        !           553:      */
        !           554:     char msg[256 + strlen (sel_getName (sel)) 
        !           555:             + strlen (object->class_pointer->name)];
        !           556:         
        !           557:     sprintf (msg, "%s does not recognize %s", 
        !           558:             object->class_pointer->name, sel_getName (sel));
        !           559:         
        !           560:     imp = get_imp (object->class_pointer, sel_getUid ("error:"));
        !           561:     if (imp)
        !           562:       error_static = (*imp)(object, sel_getUid ("error:"), msg);
        !           563:     else {
        !           564:       /*
        !           565:        * The object doesn't respond to doesNotRecognize: or
        !           566:        * error:;  Therefore, a default action is taken. 
        !           567:        */
        !           568:       fprintf (stderr, "%s\n", msg);
        !           569:       abort ();
        !           570:     }
        !           571:   }
        !           572: 
        !           573:   /*
        !           574:    * Either doesNotRecognize: or error: has been overridden.  We have
        !           575:    * to return that value as the default action. 
        !           576:    */
        !           577:   return return_error_static;
        !           578: }
        !           579: 
        !           580: 
        !           581: /*
        !           582:  * This function is used by the run-time to provide a method where nil
        !           583:  * objects can receive messages. 
        !           584:  *
        !           585:  * This method simply returns self. 
        !           586:  */
        !           587: static id  
        !           588: nil_method (id object, SEL sel, ...)
        !           589: {
        !           590:   return object;
        !           591: }
        !           592: 
        !           593: 
        !           594: /*
        !           595:  * This function is used by the run-time to provide a method where nil
        !           596:  * objects can receive messages. 
        !           597:  *
        !           598:  * This method simply returns self. 
        !           599:  *
        !           600:  * Note: multiple thread problem area. 
        !           601:  */
        !           602: static id  
        !           603: return_error_static (id object, SEL sel, ...)
        !           604: {
        !           605:   return error_static;
        !           606: }
        !           607: 
        !           608: 
        !           609: /*
        !           610:  * These variables provide a way for the defalut methods of object
        !           611:  * allocation, destruction, and reallocation to be overridden. 
        !           612:  */
        !           613: id    (*_alloc)(Class_t)                  = objc_object_create;
        !           614: id    (*_dealloc)(id)                     = objc_object_dispose;
        !           615: id    (*_realloc)(id, unsigned int)              = objc_object_realloc;
        !           616: id    (*_copy)(id)                        = objc_object_copy;
        !           617: void  (*_error)(id, const char*, va_list) = objc_error;
        !           618: 
        !           619: 
        !           620: id 
        !           621: objc_object_create (Class_t class)
        !           622: {
        !           623:   id     object;
        !           624: 
        !           625: 
        !           626:   assert (class);
        !           627: 
        !           628:   /*
        !           629:    * Allocate memory for the object, initialize the memory to 0, and
        !           630:    * set the object's class_pointer. 
        !           631:    *
        !           632:    * The object's class_pointer is the class's TEXT image.  It is used by
        !           633:    * the messager as the key to the class hash for methods. 
        !           634:    *
        !           635:    * No need to initialize the class.  That was done in objcInit. 
        !           636:    */
        !           637:   object = (id) xcalloc (1, class->instance_size);
        !           638:   object->class_pointer = class;
        !           639: 
        !           640:   return object;
        !           641: }
        !           642: 
        !           643: 
        !           644: id  
        !           645: objc_object_dispose (id object)
        !           646: {
        !           647:   object->class_pointer = NULL;
        !           648:   free (object);
        !           649: 
        !           650:   return nil;
        !           651: }
        !           652: 
        !           653: 
        !           654: id  
        !           655: objc_object_realloc (id object, unsigned int length)
        !           656: {
        !           657:   id  obj;
        !           658:   /* Can't resize a object smaller than its instance size.  */
        !           659:   /* Don't use assert here;
        !           660:      checks for user errors shouldn't depend on NDEBUG.  */
        !           661:   if (length < object->class_pointer->instance_size)
        !           662:     abort ();
        !           663: 
        !           664:   obj = (id) realloc (object, length);
        !           665:   bzero ((char*)obj + object->class_pointer->instance_size,  
        !           666:         length - object->class_pointer->instance_size);
        !           667:   
        !           668:   return obj;
        !           669: }
        !           670: 
        !           671: 
        !           672: id  
        !           673: objc_object_copy (id object)
        !           674: {
        !           675:   id  obj;
        !           676:   obj = class_createInstance (object->class_pointer);
        !           677:   bcopy (object, obj, objc_classSize (object));
        !           678:   
        !           679:   return obj;
        !           680: }
        !           681: 
        !           682: 
        !           683: void  
        !           684: objc_error (id object, const char *fmt, va_list ap)
        !           685: {
        !           686:   vfprintf (stderr, fmt, ap);
        !           687:   abort ();
        !           688: }
        !           689: 
        !           690: 
        !           691: /* Silly function to skip past a sequence of digits in a string.  */
        !           692: static inline const char *
        !           693: skip_digits (const char *str)
        !           694: {
        !           695:   while (isdigit (*str))
        !           696:     ++str;
        !           697: 
        !           698:   return str;
        !           699: }
        !           700: 
        !           701: 
        !           702: unsigned int 
        !           703: method_getNumberOfArguments (Method_t method)
        !           704: {
        !           705:   unsigned int       num = 0;
        !           706:   const char *args = &method->method_types[1];
        !           707:   
        !           708:   
        !           709:   while (*args) {
        !           710:   
        !           711:     /* Skip past size info.  */
        !           712:     args = skip_digits (args);
        !           713:     
        !           714:     /* Argument type next.  */
        !           715:     assert (*args);
        !           716:     ++num;
        !           717:     
        !           718:     /* Step to next arg.  */
        !           719:     ++args;
        !           720:   }
        !           721:   
        !           722:   assert (num >= 2);
        !           723:   return num;
        !           724: }
        !           725: 
        !           726: 
        !           727: unsigned int 
        !           728: method_getArgumentInfo (Method_t method, int indx, const char **type, 
        !           729:                        int *offset)
        !           730: {
        !           731:   const char *args = skip_digits (&method->method_types[1]);
        !           732:   int         i;
        !           733: 
        !           734:   
        !           735:   assert (method_getNumberOfArguments (method) >= indx);
        !           736: 
        !           737:   /* Step to arg.  */
        !           738:   for (i = 0; i < indx; ++i) {
        !           739:     ++args;
        !           740:     args = skip_digits (args);
        !           741:   }
        !           742:   
        !           743:   /* Return arg data.  */
        !           744:   *type = args++;
        !           745:   *offset = atoi (args);
        !           746:   
        !           747:   return indx;
        !           748: }
        !           749: 
        !           750: 
        !           751: /* This function is not thread safe.  */
        !           752: Ivar_t  
        !           753: object_getIvarAddress (id object, const char *name)
        !           754: {
        !           755:   Class_t class = object->class_pointer; /* Here is the thread safe problem.  */
        !           756:   Ivar_t  ivar = NULL;
        !           757:   
        !           758: 
        !           759:   do {
        !           760:     IvarList_t  ivars = class->ivars;
        !           761:     int         i;
        !           762:       
        !           763:     /* Look at all of the ivar names.  */
        !           764:     for (i = 0; i < ivars->ivar_count; ++i)
        !           765:       if (!strcmp (name, ivars->ivar_list[i].ivar_name))
        !           766:         ivar = &ivars->ivar_list[i];
        !           767:            
        !           768:     /*
        !           769:      * If the ivar wasn't found then lets look to the
        !           770:      * super class. 
        !           771:      *
        !           772:      * If the class is Object then the super class is NULL
        !           773:      * and we're done. 
        !           774:      */
        !           775:     class = class->super_class;
        !           776:         
        !           777:   } while (!ivar && class);
        !           778: 
        !           779:   return ivar;
        !           780: }
        !           781: 
        !           782: 
        !           783: /*
        !           784:  * Search for a method starting from the current class up its hierarchy.  
        !           785:  *
        !           786:  * Return a pointer to the method's method structure if found.  NULL otherwise. 
        !           787:  */
        !           788: Method_t  
        !           789: searchForMethodInHierarchy (Class_t class, SEL sel)
        !           790: {
        !           791:   Method_t     method = NULL;
        !           792:   const char*  name;
        !           793: 
        !           794:   if (sel == 0)
        !           795:     return NULL;
        !           796: 
        !           797:   name = sel_getName (sel);
        !           798: 
        !           799:   if (name == 0)
        !           800:     return NULL;
        !           801: 
        !           802:   /*
        !           803:    * Scan the method list of the class.  If the method isn't found in
        !           804:    * the list then step to its super class. 
        !           805:    */
        !           806:   do {
        !           807:     
        !           808:     method = searchForMethodInList (class->methods, name);
        !           809:     class = class->super_class;
        !           810: 
        !           811:   } while (!method && class);
        !           812:     
        !           813:   return method;
        !           814: }
        !           815: 
        !           816: 
        !           817: /*
        !           818:  * Given a linked list of method and a method's name.  Search for the named
        !           819:  * method's method structure. 
        !           820:  *
        !           821:  * Return a pointer to the method's method structure if found.  NULL otherwise. 
        !           822:  */
        !           823: Method_t  
        !           824: searchForMethodInList (MethodList_t list, const char *name)
        !           825: {
        !           826:   MethodList_t  method_list = list;
        !           827:   
        !           828: 
        !           829:   /* Check for bumbling.  */
        !           830:   /* ??? Who generates the name?  Is it the user, or part of this file?
        !           831:      If we crash here, whose fault is it?  */
        !           832:   assert (name);
        !           833: 
        !           834:   /* If not found then we'll search the list.  */
        !           835:   while (method_list) {
        !           836:     int   i;
        !           837:   
        !           838:     /* Search the method list.  */
        !           839:     for (i = 0; i < method_list->method_count; ++i) {
        !           840:       Method_t method = &method_list->method_list[i];
        !           841: 
        !           842:       if (method->method_name)
        !           843:        if (!strcmp (method->method_name, name))
        !           844:          return method;
        !           845:     }
        !           846:         
        !           847:     /* The method wasn't found.  Follow the link to the next list of 
        !           848:        methods.  */
        !           849:     method_list = method_list->method_next;
        !           850:   }
        !           851:   
        !           852:   return NULL;
        !           853: }
        !           854: 
        !           855: 
        !           856: /*
        !           857:  * This function adds a method list to a class.  
        !           858:  *
        !           859:  * This function is typically called by another function specific to the
        !           860:  * run-time.  As such this function does not worry about thread safe issued.  
        !           861:  */
        !           862: void  
        !           863: addMethodsToClass (Class_t class, MethodList_t list)
        !           864: {
        !           865:   int i;
        !           866:   
        !           867:   
        !           868:   /* Passing of a linked list is not allowed.  Do multiple calls.  */
        !           869:   assert (!list->method_next);
        !           870: 
        !           871:   /* Check for duplicates.  */ 
        !           872:   for (i = 0; i < list->method_count; ++i) {
        !           873:     Method_t  method = &list->method_list[i];
        !           874: 
        !           875:     if (method->method_name)   /* Sometimes these are NULL */
        !           876:       if (searchForMethodInList (class->methods, method->method_name)) {
        !           877:        /*
        !           878:         * Duplication. Print a error message an change the
        !           879:         * method name to NULL. 
        !           880:         */
        !           881:        fprintf (stderr, "attempt to add a existing method: %s\n",
        !           882:                 method->method_name);
        !           883:        method->method_name = NULL;
        !           884:       }
        !           885:   }
        !           886:   
        !           887:   /* Add the methods to the class's method list.  */
        !           888:   list->method_next = class->methods;
        !           889:   class->methods = list;
        !           890: }
        !           891: 
        !           892: 
        !           893: /*
        !           894:  * This function removes the instance and factory methods in the passed list
        !           895:  * from a class.  
        !           896:  *
        !           897:  * Methods are removed from a class by replacing the method's name with NULL. 
        !           898:  *
        !           899:  *
        !           900:  * This function is typically called by another function specific to the
        !           901:  * run-time.  As such this function does not worry about thread safe issued.  
        !           902:  */
        !           903: void  
        !           904: class_removeMethods (Class_t class, MethodList_t method_list)
        !           905: {
        !           906:   int i;
        !           907:   
        !           908:   
        !           909:   /* Passing of a linked list is not allowed.  Do multiple calls.  */
        !           910:   assert (!method_list->method_next);
        !           911: 
        !           912:   /*
        !           913:    * For each method in the list search the method lists erasing any
        !           914:    * entries found. 
        !           915:    */
        !           916:   for (i = 0; i < method_list->method_count; ++i) {
        !           917:     Method_t  kill_method = &method_list->method_list[i];
        !           918:     Method_t  method;
        !           919: 
        !           920:     /* Remove any instance method found.  */
        !           921:     method = searchForMethodInList (class->methods, 
        !           922:                                    kill_method->method_name);
        !           923:     if (method)
        !           924:       method->method_name = NULL;
        !           925:       
        !           926:     /* Remove any factory method found.  */
        !           927:     method = searchForMethodInList (class->class_pointer->methods, 
        !           928:                                    kill_method->method_name);
        !           929:     if (method)
        !           930:       method->method_name = NULL;
        !           931:   }
        !           932: }
        !           933: 
        !           934: 
        !           935: /*
        !           936:  * This is a incomplete implementation of posing.   This function does the
        !           937:  * bulk of the work but does not initialize the class method caches.  That is
        !           938:  * a run-time specific operation. 
        !           939:  *
        !           940:  * I implement posing by hiding SUPER_CLASS, creating new class and meta
        !           941:  * class structures, initializing it with IMPOSTOR, and changing it such
        !           942:  * that it is identified as SUPER_CLASS. SUPER_CLASS remains in the
        !           943:  * hierarchy but is inaccessible by the means. The class hierarchy is then re
        !           944:  * arranged such that all of the subclasses of SUPER_CLASS now inherit from
        !           945:  * the new class structures -- except the impostor itself. The only dramatic
        !           946:  * effect on the application is that subclasses of SUPER_CLASS cannot do a 
        !           947:  * [ ....  superClass ] and expect their real super class. 
        !           948:  */
        !           949: Class_t 
        !           950: class_poseAs (Class_t impostor, Class_t super_class)
        !           951: {
        !           952:   Class_t     new_class = (Class_t) calloc (1, sizeof (Class));
        !           953:   MetaClass_t new_meta_class = (MetaClass_t) calloc (1, sizeof (MetaClass));
        !           954:   node_ptr node;
        !           955:   char        *new_name = (char *) malloc (strlen (super_class->name) + 12);
        !           956: 
        !           957:   
        !           958:   assert (new_class);
        !           959:   assert (new_meta_class);
        !           960:   assert (new_name);
        !           961: 
        !           962:   /* No dispatching while the the posing class is being built.
        !           963:      The dispatch tables will be hacked on.  */
        !           964:   MUTEX_LOCK (runtimeMutex);
        !           965:        
        !           966:   assert (impostor->info & CLS_CLASS);
        !           967:   assert (super_class->info & CLS_CLASS);
        !           968: 
        !           969:   assert (impostor->instance_size == super_class->instance_size);
        !           970: 
        !           971:   /* Create the impostor class.  */
        !           972:   new_class->class_pointer     = new_meta_class;
        !           973:   new_class->super_class       = super_class;
        !           974:   new_class->name              = super_class->name;
        !           975:   new_class->version           = super_class->version;
        !           976:   new_class->info              = super_class->info;
        !           977:   new_class->instance_size     = super_class->instance_size;
        !           978:   new_class->ivars             = super_class->ivars;
        !           979:   new_class->methods           = impostor->methods;
        !           980:   new_class->cache           = &instance_method_record;
        !           981:   
        !           982:   /* Create the impostor meta class.  */
        !           983:   new_meta_class->class_pointer = super_class->class_pointer->class_pointer;
        !           984:   new_meta_class->super_class   = super_class->class_pointer->super_class;
        !           985:   new_meta_class->name          = super_class->class_pointer->name;
        !           986:   new_meta_class->version       = super_class->class_pointer->version;
        !           987:   new_meta_class->info          = super_class->class_pointer->info;
        !           988:   new_meta_class->instance_size = super_class->class_pointer->instance_size;
        !           989:   new_meta_class->ivars         = super_class->class_pointer->ivars;
        !           990:   new_meta_class->methods       = impostor->class_pointer->methods;
        !           991:   new_meta_class->cache              = &factory_method_record;
        !           992: 
        !           993:   /*
        !           994:    * Delete the class from the hash table, change its name so that it
        !           995:    * can no longer be found, then place it back into the hash table
        !           996:    * using its new name. 
        !           997:    *
        !           998:    * Don't worry about the class number.  It is already assigned. 
        !           999:    *
        !          1000:    * Don't worry about dangling pointers.  Life's a bitch.  (A little bit
        !          1001:    * of memory is lost with the hash key.)
        !          1002:    */
        !          1003:   hash_remove (class_hash_table, super_class->name);
        !          1004:   sprintf (new_name, "%s*", super_class->name);
        !          1005:   super_class->name       = new_name;
        !          1006:   super_class->class_pointer->name  = new_name;
        !          1007:   hash_add (&class_hash_table, super_class->name, super_class);
        !          1008:   
        !          1009:   /*
        !          1010:    * Now change all of the classes derived from super_class to be
        !          1011:    * derived from a impostor (except the impostor's impostor. 
        !          1012:    */
        !          1013:   for (node = hash_next (class_hash_table, NULL); node;
        !          1014:        node = hash_next (class_hash_table, node)) {
        !          1015:                
        !          1016:     Class_t    class1 = node->value;
        !          1017:     
        !          1018:     if (class1->super_class == super_class)
        !          1019:       if (class1 != impostor)
        !          1020:         class1->super_class = new_class;
        !          1021:   }
        !          1022: 
        !          1023:   /* Place the impostor class in class hash table
        !          1024:      and assign it a class number.  */
        !          1025:   addClassToHash (new_class);
        !          1026: 
        !          1027:   /* Reinitialize the dispatch tables.  */
        !          1028:   initialize_dispatch_tables ();
        !          1029: 
        !          1030:   MUTEX_UNLOCK (runtimeMutex);
        !          1031: 
        !          1032:   /* Print out class tables if debugging.  */
        !          1033:   DEBUG_PRINTF ("dump of class tables class_poseAs\n");
        !          1034:   debug_dump_classes ();
        !          1035: 
        !          1036:   return new_class;
        !          1037: }
        !          1038: 
        !          1039: 
        !          1040: /*
        !          1041:  * This routine is given a class and records all of the methods in its class
        !          1042:  * structure in the record table.  
        !          1043:  */
        !          1044: static void
        !          1045: record_methods_from_class (Class_t class)
        !          1046: {
        !          1047:   MethodList_t method_list;
        !          1048:        
        !          1049:        
        !          1050:   method_list = class->methods;
        !          1051:   while (method_list) {
        !          1052:     record_methods_from_list (method_list);
        !          1053:     method_list = method_list->method_next;
        !          1054:   }
        !          1055: }
        !          1056: 
        !          1057: 
        !          1058: /*
        !          1059:  * This routine is given a list of methods and records each of the methods in
        !          1060:  * the record table.  This is the routine that does the actual recording
        !          1061:  * work. 
        !          1062:  */
        !          1063: static void
        !          1064: record_methods_from_list (MethodList_t method_list)
        !          1065: {
        !          1066:   int  i;
        !          1067:        
        !          1068:        
        !          1069:   for (i = 0; i < method_list->method_count; ++i) {
        !          1070:     Method_t method = &method_list->method_list[i];
        !          1071: 
        !          1072:     record_selector (method->method_name);
        !          1073:   }
        !          1074: }
        !          1075: 
        !          1076: 
        !          1077: SEL
        !          1078: sel_getUid (const STR name)
        !          1079: {
        !          1080:   int i;
        !          1081:        
        !          1082:        
        !          1083:   for (i = 1; i <= record_entries (selector_record); ++i)
        !          1084:     if (!strcmp (name, record_get (i, selector_record)))
        !          1085:       return (SEL)i;
        !          1086:        
        !          1087:   /* Unable to locate selector.  Return error value.  */
        !          1088:   return (SEL)0;
        !          1089: }
        !          1090: 
        !          1091: 
        !          1092: STR
        !          1093: sel_getName (SEL selector)
        !          1094: {
        !          1095:   return record_get ((unsigned int)selector, selector_record);
        !          1096: }
        !          1097: 
        !          1098: 
        !          1099: /*
        !          1100:  * Store the passed selector name in the selector record and return its
        !          1101:  * selector value (value returned by sel_getUid). 
        !          1102:  */
        !          1103: static SEL
        !          1104: record_selector (const char *sel)
        !          1105: {
        !          1106:   int j;
        !          1107:        
        !          1108:                        
        !          1109:   /* Find either the selector in the table or an empty slot.  */
        !          1110:   for (j = 1; j <= record_entries (selector_record); ++j)
        !          1111:     if (!strcmp (sel,  record_get (j, selector_record)))
        !          1112:       return (SEL)j;
        !          1113:                        
        !          1114:   /* Save the selector name.  */
        !          1115:   record_store (my_strdup (sel), selector_record);
        !          1116:   DEBUG_PRINTF ("Record: %s as: %#x\n", sel, j);
        !          1117: 
        !          1118:   return (SEL)j;               
        !          1119: }
        !          1120: 
        !          1121: 
        !          1122: /*
        !          1123:  * Initialize the dispatch tables.  This requires the initialization of the
        !          1124:  * instance_method_record and factory_method_record arrays and the arrays they
        !          1125:  * point to. 
        !          1126:  *
        !          1127:  * The first array is indexed by a class number.  Therefore its size is the
        !          1128:  * number of classes in the executable.  The second array is indexed by a
        !          1129:  * selector id.  Therefore its size is the number of unique selectors in the
        !          1130:  * application. 
        !          1131:  *
        !          1132:  * When a method is sent to a object its class number is extracted from the
        !          1133:  * class structure and used in the first array.  The selector id is used in
        !          1134:  * the second.  The result value is a method implementation. 
        !          1135:  */
        !          1136: static void
        !          1137: initialize_dispatch_tables (void)
        !          1138: {
        !          1139:   int  i;
        !          1140: 
        !          1141: 
        !          1142:   /* Check to make sure things are in place.  */
        !          1143:   assert (selector_record);
        !          1144: 
        !          1145:   /* Blow away the instance and factory method records.  */
        !          1146:   if (factory_method_record) {
        !          1147:     for (i = 1; i <= record_entries (factory_method_record); ++i)
        !          1148:       record_delete (record_get (i, factory_method_record));
        !          1149:     record_delete (factory_method_record);
        !          1150:   }
        !          1151:   if (instance_method_record) {
        !          1152:     for (i = 1; i <= record_entries (instance_method_record); ++i)
        !          1153:       record_delete (record_get (i, instance_method_record));
        !          1154:     record_delete (instance_method_record);
        !          1155:   }
        !          1156: 
        !          1157:   /* Reallocate the instance and factory method records.  */
        !          1158:   factory_method_record = record_new ();
        !          1159:   instance_method_record = record_new ();
        !          1160:   for (i = 1; i <= record_entries (selector_record); ++i) {
        !          1161:     record_store (record_new (), factory_method_record);
        !          1162:     record_store (record_new (), instance_method_record);
        !          1163:   }
        !          1164:        
        !          1165:   /* Fool all of the secondary records into thinking they have data.  */
        !          1166:   for (i = 1; i <= record_entries (selector_record); ++i) {
        !          1167:     struct record *record;
        !          1168:     node_ptr   node;
        !          1169:        
        !          1170:     record = record_get (i, factory_method_record);
        !          1171:     for (node = hash_next (module_hash_table, NULL); node;
        !          1172:         node = hash_next (module_hash_table, node))
        !          1173:       record_store (NULL, record);
        !          1174:                        
        !          1175:     record = record_get (i, instance_method_record);
        !          1176:     for (node = hash_next (module_hash_table, NULL); node;
        !          1177:         node = hash_next (module_hash_table, node))
        !          1178:       record_store (NULL, record);
        !          1179:   }    
        !          1180:        
        !          1181:   /* For all classes fill in the methods implemented by the class and visiable
        !          1182:      from the class in the hierarchy.  Those methods are assigned to the
        !          1183:      class.  */
        !          1184:   for (i = 1; i <= record_entries (selector_record); ++i) { /* i is a sel */
        !          1185:     node_ptr   node;
        !          1186:        
        !          1187:     for (node = hash_next (class_hash_table, NULL); node;
        !          1188:         node = hash_next (class_hash_table, node)) {
        !          1189:       Class_t     class = node->value;
        !          1190:       MetaClass_t meta_class = class->class_pointer;
        !          1191:       int        class_number = getClassNumber (class);
        !          1192:       Method_t    method;
        !          1193: 
        !          1194:       /* DEBUG_PRINTF ("Assignment of sel=%s, class=%s (%#x, %#x)\n", 
        !          1195:         sel_getName ((SEL)i), class->name,
        !          1196:         searchForMethodInHierarchy (class, (SEL)i),
        !          1197:         searchForMethodInHierarchy ((Class_t)meta_class, (SEL)i)); */
        !          1198: 
        !          1199:       method = searchForMethodInHierarchy (class, (SEL)i);
        !          1200:       if (method)
        !          1201:        record_store_at (class_number, method->method_imp,
        !          1202:                         record_get (i, instance_method_record));
        !          1203: 
        !          1204:       assert (class_number == getClassNumber ((Class_t)class->class_pointer));
        !          1205:       method = searchForMethodInHierarchy ((Class_t)meta_class, (SEL)i);
        !          1206:       if (method)
        !          1207:         record_store_at (class_number, method->method_imp,
        !          1208:                          record_get (i, factory_method_record));
        !          1209:     }
        !          1210:   }
        !          1211: }
        !          1212: 
        !          1213: 
        !          1214: /*
        !          1215:  * This method is called by the dispatch routines when a class has not been
        !          1216:  * initialized.  This method is responsible for initializing the class.  This
        !          1217:  * is accomplished by first testing the class itself for responding to the
        !          1218:  * +initialize method.  If such a method is implemented then it is called. 
        !          1219:  * Before exit, irregardless if the class implements +initialize, the class
        !          1220:  * is marked as initialized. 
        !          1221:  */
        !          1222: static void            
        !          1223: initialize_class (const char *name)
        !          1224: {
        !          1225:   Method_t     method = NULL;
        !          1226:   Class_t      class = objc_getClass (name);
        !          1227:   SEL          sel = sel_getUid ("initialize");
        !          1228: 
        !          1229:        
        !          1230:   /* The class should not be initialized at this point.  */
        !          1231:   assert (!(class->info & CLS_INITIALIZED));
        !          1232:   assert (!(class->class_pointer->info & CLS_INITIALIZED));
        !          1233: 
        !          1234:   /* Search for the +initialize method.
        !          1235:      Call it if it exists.  */
        !          1236:   if (sel)
        !          1237:     method = searchForMethodInList (class->class_pointer->methods,
        !          1238:                                    sel_getName (sel));
        !          1239:   if (method) {
        !          1240:     IMP        imp;
        !          1241: 
        !          1242:     DEBUG_PRINTF ("Class: %s sending +%s\n", 
        !          1243:                  name, sel_getName (sel));
        !          1244:     imp = get_imp ((Class_t)class->class_pointer, sel);
        !          1245:     assert (imp);
        !          1246:     (*imp)((id)class, sel);
        !          1247:   }
        !          1248: 
        !          1249:   /* Mark the class as initialized.  */
        !          1250:   class->info  |= CLS_INITIALIZED;
        !          1251:   class->class_pointer->info   |= CLS_INITIALIZED;
        !          1252: }
        !          1253: 
        !          1254: 
        !          1255: /*
        !          1256:  * Silly little function that checks to make sure the class hash table is
        !          1257:  * initialized.  If it isn't initialized then do it. 
        !          1258:  */
        !          1259: static inline void
        !          1260: class_hash_init (void)
        !          1261: {
        !          1262:   static unsigned int  init = 0;
        !          1263:        
        !          1264:        
        !          1265:   if (!init)
        !          1266:     class_hash_table = hash_new (CLASS_HASH_SIZE, 
        !          1267:                                 (hash_func_type)hash_string,
        !          1268:                                 (compare_func_type)compare_strings);
        !          1269:   init = 1;
        !          1270: }
        !          1271: 
        !          1272: 
        !          1273: Class_t 
        !          1274: objc_getClass (const char *name)
        !          1275: {
        !          1276:   Class_t      class;
        !          1277: 
        !          1278: 
        !          1279:   /* Make sure the class hash table exists.  */
        !          1280:   class_hash_init ();
        !          1281: 
        !          1282:   class = hash_value_for_key (class_hash_table, name);
        !          1283:        
        !          1284:   return class;
        !          1285: }
        !          1286: 
        !          1287: 
        !          1288: MetaClass_t 
        !          1289: objc_getMetaClass (const char *name)
        !          1290: {
        !          1291:   /* Meta classes are pointed to by the class's class_pointer.
        !          1292:      Just get the class and return its class_pointer.  */
        !          1293:   return (objc_getClass (name))->class_pointer;
        !          1294: }
        !          1295: 
        !          1296: 
        !          1297: void
        !          1298: addClassToHash (Class_t class)
        !          1299: {
        !          1300:   Class_t      hClass;
        !          1301:        
        !          1302:        
        !          1303:   class_hash_init ();
        !          1304: 
        !          1305:   /* Check to see if the class is already in the hash table.  */
        !          1306:   hClass = hash_value_for_key (class_hash_table, class->name);
        !          1307:   if (!hClass) {
        !          1308:     
        !          1309:     /* The class isn't in the hash table.  Add the class and 
        !          1310:        assign a class number.  */
        !          1311:     static unsigned int        class_number = 1;
        !          1312:        
        !          1313:     setClassNumber (class, class_number);
        !          1314:     setClassNumber ((Class_t)class->class_pointer, class_number);
        !          1315:     ++class_number;
        !          1316:     
        !          1317:     hash_add (&class_hash_table, class->name, class);
        !          1318:   }
        !          1319: }
        !          1320: 
        !          1321: 
        !          1322: void  
        !          1323: debug_dump_classes (void)
        !          1324: {
        !          1325:   node_ptr node;
        !          1326:   int         i;
        !          1327: 
        !          1328: 
        !          1329:   DEBUG_PRINTF ("class tables\n");
        !          1330:   i = 0;
        !          1331:   for (node = hash_next (class_hash_table, NULL); node; 
        !          1332:        node = hash_next (class_hash_table, node)) {
        !          1333: 
        !          1334:     Class_t class = node->value;
        !          1335:       
        !          1336:     DEBUG_PRINTF ("Class { /*%#x*/\n", class);
        !          1337:     DEBUG_PRINTF ("   MetaClass_t  class_pointer = %#x\n", class->class_pointer);
        !          1338:     DEBUG_PRINTF ("   Class_t      super_class   = %#x\n", class->super_class);
        !          1339:     DEBUG_PRINTF ("   char         *name          = %s\n", class->name);
        !          1340:     DEBUG_PRINTF ("   long         version       = %ld\n", class->version);
        !          1341:     DEBUG_PRINTF ("   long         info          = %#x\n", class->info);
        !          1342:     DEBUG_PRINTF ("   long         instance_size = %ld\n", class->instance_size);
        !          1343:     DEBUG_PRINTF ("   IvarList_t   ivars         = %#x\n", class->ivars);
        !          1344:     DEBUG_PRINTF ("   MethodList_t methods       = %#x\n", class->methods);
        !          1345:     DEBUG_PRINTF ("   cache_ptr      cache         = %#x\n", class->cache);
        !          1346:     DEBUG_PRINTF ("}[%d];\n", i++);
        !          1347:   }
        !          1348:     
        !          1349:   i = 0;
        !          1350:   for (node = hash_next (class_hash_table, NULL); node; 
        !          1351:     node = hash_next (class_hash_table, node)) {
        !          1352: 
        !          1353:     Class_t class = (Class_t)((Class_t)(node->value))->class_pointer;
        !          1354:       
        !          1355:     DEBUG_PRINTF ("MetaClass { /*%#x*/\n", class);
        !          1356:     DEBUG_PRINTF ("   MetaClass_t  class_pointer = %#x\n", class->class_pointer);
        !          1357:     DEBUG_PRINTF ("   MetaClass_t  super_class   = %#x\n", class->super_class);
        !          1358:     DEBUG_PRINTF ("   char         *name          = %s\n", class->name);
        !          1359:     DEBUG_PRINTF ("   long         version       = %ld\n", class->version);
        !          1360:     DEBUG_PRINTF ("   long         info          = %#x\n", class->info);
        !          1361:     DEBUG_PRINTF ("   long         instance_size = %ld\n", class->instance_size);
        !          1362:     DEBUG_PRINTF ("   IvarList_t   ivars         = %#x\n", class->ivars);
        !          1363:     DEBUG_PRINTF ("   MethodList_t methods       = %#x\n", class->methods);
        !          1364:     DEBUG_PRINTF ("   cache_ptr      cache         = %#x\n", class->cache);
        !          1365:     DEBUG_PRINTF ("}[%d];\n", i++);
        !          1366:   }
        !          1367: }
        !          1368: 

unix.superglobalmegacorp.com

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