Annotation of objc/objc-class.m, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.0 (the 'License').  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License."
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: /*
                     25:  *     objc-class.m
                     26:  *     Copyright 1988, NeXT, Inc.
                     27:  *     Author: s. naroff
                     28:  *
                     29:  */
                     30: 
                     31: static int _class_uncache = 1;
                     32: static int _class_slow_grow = 1;
                     33: 
                     34: #import <mach/mach_interface.h>
                     35: 
                     36: #ifdef SHLIB
                     37: #import "shlib.h"
                     38: #endif SHLIB
                     39: 
                     40: #include <mach-o/ldsyms.h>
                     41: #import "objc-private.h"
                     42: #ifdef RUNTIME_DYLD
                     43: #include <mach-o/dyld.h>
                     44: #endif
                     45: #import "objc-runtime.h"
                     46: #import "objc.h"
                     47: #import "Object.h"
                     48: #import "maptable.h"
                     49: 
                     50: #ifdef RUNTIME_DYLD
                     51: void *getsectdatafromheaderinfo(const struct header_info * info, 
                     52:                                char * segname, 
                     53:                                char * sectname, 
                     54:                                int * size);
                     55: void _objc_bindModuleContainingList (struct objc_method_list*);
                     56: #endif
                     57: void *getsectdatafromheader(const struct mach_header *, char *, char *, int *);
                     58: 
                     59: #ifdef KERNEL
                     60: 
                     61: #undef bzero(x,y)
                     62: #define        vm_page_size    8192
                     63: 
                     64: #else /* KERNEL */
                     65: 
                     66: #import <mach/mach.h>
                     67: #import <mach/thread_status.h>
                     68: 
                     69: #endif /* KERNEL */
                     70: 
                     71: /* CACHE_SIZE and META_CACHE_SIZE must be a power of two */
                     72: #define CACHE_SIZE             4       // let's try 4 instead (was 16)
                     73: #define META_CACHE_SIZE                4       // let's try 4 instead (8)
                     74: 
                     75: #define ISCLASS(cls)           ((cls)->info & CLS_CLASS)
                     76: #define ISMETA(cls)            ((cls)->info & CLS_META) 
                     77: #define GETMETA(cls)           (ISMETA(cls) ? cls : cls->isa)
                     78: 
                     79: #define ISINITIALIZED(cls)     (GETMETA(cls)->info & CLS_INITIALIZED)
                     80: #define MARKINITIALIZED(cls)   (GETMETA(cls)->info |= CLS_INITIALIZED)
                     81: 
                     82: static void _cache_fill(Class, Method);
                     83: static Cache _cache_expand(Class);
                     84: static void _cache_flush (Class);
                     85: 
                     86: #ifdef OBJC_COLLECTING_CACHE
                     87: static void _cache_collect_free(void *data, BOOL tryCollect);
                     88: #endif
                     89: 
                     90: // Error Messages
                     91: static const char
                     92:        _errNoMem[] = "failed -- out of memory(%s, %u)",
                     93:        _errAllocNil[] = "allocating nil object",
                     94:        _errFreedObject[] = "message %s sent to freed object=0x%lx",
                     95: #if RUNTIME_DYLD
                     96:         _errNonExistentObject[] = "message %s sent to non-existent object=0x%lx",
                     97: #endif
                     98:        _errBadSel[] = "invalid selector %s",
                     99: #if 0
                    100:        _errDoesntRecognize[] = "Does not recognize selector %s",
                    101: #endif
                    102:        _errNotSuper[]  = "[%s poseAs:%s]: target not immediate superclass",
                    103:        _errNewVars[]   = "[%s poseAs:%s]: %s defines new instance variables";
                    104: 
                    105: /* Information about multithtread support:
                    106:    
                    107:    Since we do not lock many operations which walk the superclass, method
                    108:    and ivar chains, these chains must remain intact once a class is published
                    109:    by inserting it into the class hashtable.  All modifications must be
                    110:    atomic so that someone walking these chains will always geta valid
                    111:    result. */
                    112: 
                    113: /* Lock for messaging. (Private extern) */
                    114: 
                    115: #ifdef OBJC_COLLECTING_CACHE
                    116: static OBJC_DECLARE_LOCK (cacheUpdateLock);
                    117: static OBJC_DECLARE_LOCK (cacheCollectionLock);
                    118: #endif
                    119: 
                    120: /* This is the read lock */
                    121: OBJC_DECLARE_LOCK (messageLock);
                    122: 
                    123: 
                    124: static void *objc_malloc (int size);
                    125: 
                    126: 
                    127: /* A static empty cache.  All classes initially point at this cache.
                    128:    When the first message is sent it misses in the cache, and when
                    129:    the cache is grown it checks for this case and uses malloc rather
                    130:    than realloc.  This avoids the need to check for NULL caches in the
                    131:    messenger. */
                    132: 
                    133: const struct objc_cache emptyCache =
                    134: {
                    135:   0,                           /* mask */
                    136:   0,                           /* occupied */
                    137: #ifdef OBJC_COPY_CACHE
                    138:   { 0, 0 }                     /* buckets */
                    139: #else
                    140:   { NULL }                     /* buckets */
                    141: #endif
                    142: };
                    143: 
                    144: /* Freed objects have their isa set to point to this dummy class.
                    145:    This avoids the need to check for Nil classes in the messenger.  */
                    146: 
                    147: static const struct objc_class freedObjectClass =
                    148: {
                    149:   Nil,                         /* isa */
                    150:   Nil,                         /* super_class */
                    151:   "FREED(id)",                 /* name */
                    152:   0,                           /* version */
                    153:   0,                           /* info */
                    154:   0,                           /* instance_size */
                    155:   NULL,                                /* ivars */
                    156:   NULL,                                /* methods */
                    157:   (Cache) &emptyCache,         /* cache */
                    158:   NULL                         /* protocols */
                    159: };
                    160: 
                    161: #ifdef RUNTIME_DYLD
                    162: 
                    163: static const struct objc_class nonexistentObjectClass =
                    164: {
                    165:   Nil,                         /* isa */
                    166:   Nil,                         /* super_class */
                    167:   "NONEXISTENT(id)",                   /* name */
                    168:   0,                           /* version */
                    169:   0,                           /* info */
                    170:   0,                           /* instance_size */
                    171:   NULL,                                /* ivars */
                    172:   NULL,                                /* methods */
                    173:   (Cache) &emptyCache,         /* cache */
                    174:   NULL                         /* protocols */
                    175: };
                    176: 
                    177: #endif
                    178: 
                    179: const char *object_getClassName(id obj)
                    180: {
                    181:        if (obj == nil) 
                    182:                return "nil";
                    183:        else
                    184:                return ((Class)obj->isa)->name;
                    185: }
                    186: 
                    187: void *object_getIndexedIvars(id obj)
                    188: {
                    189:        return ((char *)obj) + obj->isa->instance_size;
                    190: }
                    191: 
                    192: // Allocate new instance of aClass with nBytes bytes of indexed vars
                    193: 
                    194: id _internal_class_createInstanceFromZone(Class aClass, unsigned nBytes, NXZone *zone) 
                    195: {
                    196:        id obj; 
                    197:        register unsigned siz;
                    198: 
                    199:        if (aClass == Nil)
                    200:                __objc_error((id)aClass, _errAllocNil, 0);
                    201: 
                    202:        siz = aClass->instance_size + nBytes;
                    203: 
                    204:        if ((obj = (id)NXZoneMalloc(zone, siz))) { 
                    205:                bzero((char *)obj, siz);
                    206:                obj->isa = aClass; 
                    207:                return obj;
                    208:        } else {
                    209:                __objc_error((id)aClass, _errNoMem, aClass->name, nBytes);
                    210:                 return nil;
                    211:         }
                    212: } 
                    213: 
                    214: id class_createInstanceFromZone(Class aClass, unsigned nBytes, NXZone *zone) 
                    215: {
                    216:        return (*_zoneAlloc)(aClass, nBytes, zone);
                    217: } 
                    218: 
                    219: id _internal_class_createInstance(Class aClass, unsigned nBytes) 
                    220: {
                    221:     return _internal_class_createInstanceFromZone(aClass, nBytes, NXDefaultMallocZone());
                    222: } 
                    223: 
                    224: id class_createInstance(Class aClass, unsigned nBytes) 
                    225: {
                    226:        return (*_alloc)(aClass, nBytes);
                    227: } 
                    228: 
                    229: void class_setVersion(Class aClass, int version)
                    230: {
                    231:        aClass->version = version;
                    232: }
                    233: 
                    234: int class_getVersion(Class aClass)
                    235: {
                    236:        return aClass->version;
                    237: }
                    238: 
                    239: static inline Method class_getMethod(Class cls, SEL sel)
                    240: {
                    241:        do {
                    242:                register int n;
                    243:                register Method smt;
                    244:                struct objc_method_list *mlist;
                    245: 
                    246:                for (mlist = cls->methods; mlist; mlist = mlist->method_next) {
                    247:                   smt = mlist->method_list;
                    248:                   n = mlist->method_count;
                    249: 
                    250:                   while (--n >= 0) {
                    251:                      if (sel == smt->method_name)
                    252: #ifdef RUNTIME_DYLD
                    253:                        {
                    254:                          _objc_bindModuleContainingList (mlist);
                    255:                          return smt;
                    256:                        }
                    257: #else
                    258:                      return smt;
                    259: #endif
                    260:                      smt++;
                    261:                   }
                    262:                }
                    263:        } while ((cls = cls->super_class));
                    264: 
                    265:        return 0;
                    266: }
                    267: 
                    268: Method class_getInstanceMethod(Class aClass, SEL aSelector)
                    269: {
                    270:        if (aClass && aSelector)
                    271:                return class_getMethod(aClass, aSelector);
                    272:                else 
                    273:                return 0;
                    274: }
                    275: 
                    276: Method class_getClassMethod(Class aClass, SEL aSelector)
                    277: {
                    278:        if (aClass && aSelector)
                    279:                return class_getMethod(GETMETA(aClass), aSelector);
                    280:                else 
                    281:                return 0;
                    282: }
                    283: 
                    284: static Ivar class_getVariable(Class cls, const char *name)
                    285: {
                    286:        do {
                    287:                if (cls->ivars) {
                    288:                        int i;
                    289:                        Ivar ivars = cls->ivars->ivar_list;
                    290: 
                    291:                        for (i = 0; i < cls->ivars->ivar_count; i++)    
                    292:                                if (strcmp(name,ivars[i].ivar_name) == 0)
                    293:                                        return &ivars[i];
                    294:                }
                    295:        } while ((cls = cls->super_class));
                    296: 
                    297:        return 0;
                    298: }
                    299: 
                    300: Ivar class_getInstanceVariable(Class aClass, const char *name)
                    301: {
                    302:        if (aClass && name)
                    303:                return class_getVariable(aClass, name); 
                    304:        else
                    305:                return 0;
                    306: }
                    307: 
                    308: /* Someday add class_getClassVariable(). */
                    309: 
                    310: 
                    311: /* Flush the instance and optionally class method caches of all subclasses. */
                    312: 
                    313: static void flush_caches(Class cls, BOOL flush_meta)
                    314: {
                    315:        NXHashTable *class_hash;
                    316:        NXHashState state;
                    317:        Class clsObject;
                    318: 
                    319:         if (cls->cache == 0)
                    320:             return;
                    321: 
                    322:        OBJC_LOCK (&classLock);
                    323: 
                    324:        class_hash = objc_getClasses();
                    325:        state = NXInitHashState(class_hash);
                    326: 
                    327:        while (NXNextHashState(class_hash, &state, (void **)&clsObject)) {
                    328: 
                    329:                Class clsIter = clsObject;
                    330: 
                    331:                while (clsIter) {
                    332: 
                    333:                        if (clsIter == cls) {
                    334:                                // it is `aKindOf' the class that has
                    335:                                // been modified - flush!
                    336:                                _cache_flush (clsObject);
                    337:                                if (flush_meta)
                    338:                                        _cache_flush (clsObject->isa);
                    339:                                clsIter = 0;
                    340:                        } else if (clsIter->isa == cls) {
                    341:                                _cache_flush (clsObject);
                    342:                                clsIter = 0;
                    343:                         } else if (CLS_GETINFO(clsIter, CLS_INITIALIZED)) {
                    344:                                 clsIter = clsIter->super_class;
                    345:                         } else {
                    346:                                 clsIter = 0;
                    347:                         }
                    348:                }
                    349:        }
                    350: 
                    351:        OBJC_UNLOCK (&classLock);
                    352: }
                    353: 
                    354: /* Private extern.  Flush instance and class method caches. */
                    355: 
                    356: void _objc_flush_caches (Class cls)
                    357: {
                    358:   flush_caches (cls, YES);
                    359: }
                    360: 
                    361: /* Formerly class_addInstanceMethods(). */
                    362: 
                    363: void class_addMethods(Class cls, struct objc_method_list *meths)
                    364: {
                    365:        // Insert atomically.
                    366:        meths->method_next = cls->methods;
                    367:         cls->methods = meths;
                    368:        // must flush when dynamically adding methods.
                    369:        flush_caches (cls, NO);
                    370: }
                    371: 
                    372: /* Obsolete (for binary compatibility only). */
                    373: 
                    374: void class_addClassMethods(Class cls, struct objc_method_list *meths)
                    375: {
                    376:        class_addMethods (cls->isa, meths);
                    377: }
                    378: 
                    379: void class_removeMethods(Class cls, struct objc_method_list *meths)
                    380: {
                    381:        // Remove atomically.
                    382:        if (cls->methods == meths) {
                    383:                /* it is at the front of the list - take it out */
                    384:                cls->methods = meths->method_next;
                    385:        } else {
                    386:                struct objc_method_list *mlist, *prev;
                    387: 
                    388:                /* it is not at the front of the list - look for it */
                    389:                prev = cls->methods;
                    390:                mlist = prev->method_next;
                    391: 
                    392:                while (mlist) {
                    393:                        if (mlist == meths) {
                    394:                                prev->method_next = mlist->method_next;
                    395:                                mlist = 0;
                    396:                        } else {
                    397:                                prev = mlist;
                    398:                                mlist = prev->method_next;
                    399:                        }
                    400:                }
                    401:        }
                    402:        // must flush when dynamically removing methods.
                    403:        flush_caches (cls, NO); 
                    404: }
                    405: 
                    406: /* Private extern */
                    407: void _class_removeProtocols(Class cls, struct objc_protocol_list *protos)
                    408: {
                    409:        // Remove atomically.
                    410:        if (cls->protocols == protos) {
                    411:                /* it is at the front of the list - take it out */
                    412:                cls->protocols = protos->next;
                    413:        } else {
                    414:                struct objc_protocol_list *plist, *prev;
                    415: 
                    416:                /* it is not at the front of the list - look for it */
                    417:                prev = cls->protocols;
                    418:                plist = prev->next;
                    419: 
                    420:                while (plist) {
                    421:                        if (plist == protos) {
                    422:                                prev->next = plist->next;
                    423:                                plist = 0;
                    424:                        } else {
                    425:                                prev = plist;
                    426:                                plist = prev->next;
                    427:                        }
                    428:                }
                    429:        }
                    430: }
                    431: 
                    432: 
                    433: /*
                    434:  * This is a hash table of classes involved in a posing
                    435:  * situation.  We use this when we need to get to the "original" 
                    436:  * class for some particular name though the function
                    437:  * objc_getOrigClass.   For instance, the implementation of
                    438:  * [super ...] will use this to be sure that it gets hold of the 
                    439:  * correct super class, so that no infinite loops will occur
                    440:  * if the class it appears in is involved in posing.
                    441:  * We use the classLock to guard this hash table.
                    442:  * See tracker bug #51856.
                    443:  */
                    444: 
                    445: static NXHashTable *posed_class_hash = 0;
                    446: 
                    447: 
                    448: 
                    449: Class
                    450: objc_getOrigClass (const char *name)
                    451: {
                    452:     Class ret = 0;
                    453: 
                    454:     OBJC_LOCK (&classLock);
                    455:     if (posed_class_hash)
                    456:       {
                    457:         ret = (Class)NXMapGet(posed_class_hash, name);
                    458:       }
                    459:     OBJC_UNLOCK (&classLock);
                    460: 
                    461:     if (ret == nil)
                    462:       {
                    463:         ret = objc_getClass (name);
                    464:       }
                    465: 
                    466:     return ret;
                    467: }
                    468: 
                    469: /*
                    470:  * This function is only used from class_poseAs.  It's purpose is to
                    471:  * register the original class names, before they get obscured by 
                    472:  * posing, so that [super ..] will work correctly from categories 
                    473:  * in posing classes and in categories in classes being posed for.
                    474:  */
                    475: 
                    476: static void
                    477: _objc_addOrigClass (Class origClass)
                    478: {
                    479:     OBJC_LOCK (&classLock);
                    480: 
                    481:     if (posed_class_hash == 0)
                    482:       {
                    483:         posed_class_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype,
                    484:                                                      8,
                    485:                                                      _objc_create_zone ());
                    486:       }
                    487: 
                    488:     if (NXMapGet(posed_class_hash, origClass->name) == 0)
                    489:       {
                    490:         NXMapInsert(posed_class_hash, origClass->name, origClass);
                    491:       }
                    492: 
                    493:     OBJC_UNLOCK (&classLock);
                    494: }
                    495: 
                    496: /* !!! class_poseAs() does not currently flush any caches. */
                    497: 
                    498: Class class_poseAs(Class imposter, Class original) 
                    499: {
                    500:        Class clsObject;
                    501:        char imposterName[256], *imposterNamePtr; 
                    502:        NXHashTable *class_hash;
                    503:        NXHashState state;
                    504:        Class copy;
                    505:        unsigned int hidx, header_count = _objc_headerCount ();
                    506:        struct header_info *header_vector = _objc_headerVector (NULL);
                    507: 
                    508:        if (imposter == original) 
                    509:                return imposter;
                    510: 
                    511:        if (imposter->super_class != original)
                    512:                return (Class)[(id)imposter error:_errNotSuper, 
                    513:                                        imposter->name, original->name];
                    514:        if (imposter->ivars)
                    515:                return (Class)[(id)imposter error:_errNewVars, imposter->name, 
                    516:                                        original->name, imposter->name];
                    517: 
                    518:        // Build a string to use to replace the name of the original class.
                    519:        strcpy (imposterName, "_%"); 
                    520:        strcat (imposterName, original->name);
                    521: 
                    522:        imposterNamePtr = objc_malloc (strlen(imposterName)+1); 
                    523:        strcpy (imposterNamePtr, imposterName);
                    524: 
                    525:        // We lock the class hashtable, so we are thread safe with respect to
                    526:        // calls to objc_getClass().  However, the class names are not
                    527:        // changed atomically, nor are all of the subclasses updated
                    528:        // atomically.  I have ordered the operations so that you will
                    529:        // never crash, but you may get inconsistent results....
                    530: 
                    531:         // register the original class so that [super ..] knows
                    532:         // exactly which classes are the "original" classes.
                    533:         _objc_addOrigClass (original);
                    534:         _objc_addOrigClass (imposter);
                    535: 
                    536:        OBJC_LOCK (&classLock);
                    537: 
                    538:        class_hash = objc_getClasses ();
                    539: 
                    540:        // Remove both the imposter and the original class.
                    541:        NXHashRemove(class_hash, imposter);
                    542:        NXHashRemove(class_hash, original);
                    543: 
                    544:        // Copy the imposter, so that the imposter can continue
                    545:        // its normal life in addition to changing the behaviour of
                    546:        // the original.  As a hack we don't bother to copy the metaclass.
                    547:        // For some reason we modify the original rather than the copy.
                    548:        copy = object_copy ((Object *) imposter, 0);
                    549:        NXHashInsert (class_hash, copy);
                    550: 
                    551:        // Mark the imposter as such (this doesn't appear to be used).
                    552:        CLS_SETINFO(imposter, CLS_POSING);
                    553:        CLS_SETINFO(imposter->isa, CLS_POSING);
                    554: 
                    555:        // Change the name of the imposter to that of the original class.
                    556:        imposter->name = original->name;
                    557:        imposter->isa->name = original->isa->name;
                    558: 
                    559:        // Also copy the version field to avoid archiving problems.
                    560:        imposter->version = original->version;
                    561: 
                    562:         state = NXInitHashState(class_hash);
                    563: 
                    564:        // Change all subclasses of the original to point to the imposter.
                    565:        while (NXNextHashState(class_hash, &state, (void **)&clsObject))
                    566:          {
                    567:            while (clsObject && clsObject != imposter && clsObject != copy)
                    568:              {
                    569:                if (clsObject->super_class == original)
                    570:                  {
                    571:                    clsObject->super_class = imposter;
                    572:                    clsObject->isa->super_class = imposter->isa;
                    573:                    // We must flush caches here!
                    574:                    break;
                    575:                  }
                    576:                clsObject = clsObject->super_class;
                    577:              }
                    578:          }
                    579: 
                    580: #ifdef OBJC_CLASS_REFS
                    581:        
                    582:        for (hidx = 0; hidx < header_count; hidx++)
                    583:          {
                    584:            Class *cls_refs;
                    585:            unsigned int size;
                    586:            
                    587: #ifdef RUNTIME_DYLD
                    588:            cls_refs = (Class *) getsectdatafromheaderinfo
                    589:                                             (&header_vector[hidx],
                    590:                                              SEG_OBJC, "__cls_refs", &size);
                    591: #else
                    592:            cls_refs = (Class *) getsectdatafromheader
                    593:                                             (header_vector[hidx].mhdr,
                    594:                                              SEG_OBJC, "__cls_refs", &size);
                    595: #endif
                    596:            if (cls_refs)
                    597:              {
                    598:                unsigned int i;
                    599:                
                    600:                for (i = 0; i < size / sizeof (Class); i++)
                    601:                  if (cls_refs[i] == original)
                    602:                    cls_refs[i] = imposter;
                    603:              }
                    604:          }
                    605: #endif /* OBJC_CLASS_REFS */
                    606: 
                    607:        // Change the name of the original class.
                    608:        original->name = imposterNamePtr+1;
                    609:        original->isa->name = imposterNamePtr;
                    610: 
                    611:        // Restore the imposter and the original class with their new names.
                    612:        NXHashInsert(class_hash, imposter);
                    613:        NXHashInsert(class_hash, original);
                    614: 
                    615:        OBJC_UNLOCK (&classLock);
                    616: 
                    617:        return imposter;
                    618: }
                    619: 
                    620: 
                    621: static void _freedHandler(id self, SEL sel) 
                    622: {
                    623:        __objc_error(self, _errFreedObject, SELNAME(sel), self);
                    624: }
                    625: 
                    626: #ifdef RUNTIME_DYLD
                    627: static void _nonexistentHandler(id self, SEL sel)
                    628: {
                    629:         __objc_error(self, _errNonExistentObject, SELNAME(sel), self);
                    630: }
                    631: #endif
                    632: 
                    633: /*
                    634:  *     Purpose: Send the 'initialize' message on demand to any un-initialized 
                    635:  *              class. Force initialization of superclasses first.
                    636:  */
                    637: 
                    638: /* Called only from _class_lookupMethodAndLoadCache (or itself).
                    639: #ifdef OBJC_COLLECTING_CACHE
                    640:    The messageLock can be in either state.
                    641: #else
                    642:    The messageLock is already assumed to be taken out.
                    643:    It is temporarily released while the initialize method is sent. 
                    644: #endif
                    645: 
                    646: */
                    647: 
                    648: static id class_initialize(Class clsDesc)
                    649: {
                    650:        Class super = clsDesc->super_class;
                    651: 
                    652:        if (ISINITIALIZED(clsDesc))
                    653:                return clsDesc;
                    654: 
                    655:        // force initialization of superclasses first
                    656:        if (super != Nil && !ISINITIALIZED(super))
                    657:                class_initialize(super);
                    658: 
                    659:        // Initializing the super class might have initialized us,
                    660:        // or another thread might have intialized us during this time.
                    661:        if (ISINITIALIZED(clsDesc))
                    662:                return clsDesc;
                    663: 
                    664:        MARKINITIALIZED(clsDesc);
                    665: 
                    666: #ifndef OBJC_COLLECTING_CACHE
                    667:        OBJC_UNLOCK (&messageLock);
                    668: #endif
                    669: 
                    670:        [clsDesc initialize];
                    671: 
                    672: #ifndef OBJC_COLLECTING_CACHE
                    673:        OBJC_LOCK (&messageLock);
                    674: #endif
                    675: 
                    676:        return clsDesc;
                    677: }
                    678: 
                    679: /* make a private extern in shlib */
                    680: 
                    681: void _class_install_relationships(Class class, long version)
                    682: {
                    683:        Class meta, clstmp;
                    684:        int errflag = 0;
                    685: 
                    686:        meta = class->isa;
                    687:        
                    688:        meta->version = version;
                    689: 
                    690:        if (class->super_class) {
                    691:          if ((clstmp = objc_getClass((const char *)class->super_class)))
                    692:            class->super_class = clstmp;
                    693:          else
                    694:            errflag = 1;
                    695:        }
                    696: 
                    697:        if ((clstmp = objc_getClass((const char *)meta->isa)))
                    698:          meta->isa = clstmp->isa;
                    699:        else 
                    700:          errflag = 1;
                    701: 
                    702:        if (meta->super_class) {
                    703:            if ((clstmp = objc_getClass((const char *)meta->super_class)))
                    704:               meta->super_class = clstmp->isa;
                    705:          else
                    706:            errflag = 1;
                    707:        }
                    708:        else /* `tie' the meta class down to its class */
                    709:          meta->super_class = class;
                    710: 
                    711:        /* point all classes and meta-classes at static empty cache.  */
                    712:        if (class->cache == NULL)
                    713:          class->cache = (Cache) &emptyCache;
                    714:        if (meta->cache == NULL)
                    715:          meta->cache = (Cache) &emptyCache;
                    716: 
                    717:        if (errflag)
                    718:                _objc_fatal("please link appropriate classes in your program");
                    719: }
                    720: 
                    721: static void *objc_malloc(int size)
                    722: {
                    723:        void *space = NXZoneMalloc(_objc_create_zone(), size);
                    724: 
                    725:        if (space == 0 && size != 0)
                    726:          _objc_fatal("unable to allocate space");
                    727: 
                    728:        return space;
                    729: }
                    730: 
                    731: 
                    732: /* Called from -[Object respondsTo:] and +[Object instancesRespondTo:]. */
                    733: 
                    734: BOOL class_respondsToMethod(Class savCls, SEL sel)
                    735: {
                    736:        Class cls = savCls;
                    737: #ifdef OBJC_COPY_CACHE
                    738:         struct objc_cache_bucket *buckets;
                    739: #else
                    740:        Method *buckets;
                    741: #endif
                    742:        int index, mask;
                    743:        
                    744:        if (sel == 0) 
                    745:                return NO;
                    746: 
                    747:        OBJC_LOCK (&messageLock);
                    748: 
                    749:        mask = cls->cache->mask;
                    750:        buckets = cls->cache->buckets;
                    751: 
                    752:        index = (unsigned int) sel & mask;
                    753: 
                    754:        for (;;) {
                    755:            if (! CACHE_BUCKET_VALID (buckets[index]))
                    756:              goto cacheMiss;
                    757:            if (CACHE_BUCKET_NAME (buckets[index]) == sel)
                    758:              {
                    759:                if (CACHE_BUCKET_IMP (buckets[index]) == &_objc_msgForward)
                    760:                  {
                    761:                    OBJC_UNLOCK (&messageLock);
                    762:                    return NO;
                    763:                  }
                    764:                else
                    765:                  {
                    766:                    OBJC_UNLOCK (&messageLock);
                    767:                    return YES;
                    768:                  }
                    769:              }
                    770:            index++;
                    771:            index &= mask;
                    772:        }
                    773: 
                    774: cacheMiss:
                    775:        
                    776:        do {
                    777:                register int n;
                    778:                register Method smt;
                    779:                struct objc_method_list *mlist;
                    780: 
                    781:                for (mlist = cls->methods; mlist; mlist = mlist->method_next) {
                    782:                   smt = mlist->method_list;
                    783:                   n = mlist->method_count;
                    784: 
                    785:                   while (--n >= 0) {
                    786:                        if (sel == smt->method_name)
                    787:                          {
                    788: #ifdef RUNTIME_DYLD
                    789:                            _objc_bindModuleContainingList (mlist);
                    790: #endif
                    791: #ifdef OBJC_COLLECTING_CACHE
                    792:                             OBJC_UNLOCK (&messageLock);
                    793:                             _cache_fill(savCls, smt);
                    794: #else
                    795:                             _cache_fill(savCls, smt);
                    796:                             OBJC_UNLOCK (&messageLock);
                    797: #endif
                    798:                            return YES;
                    799:                          }
                    800:                        smt++;
                    801:                   }
                    802:                }
                    803:        } while ((cls = cls->super_class));
                    804:                
                    805:        {
                    806:          Method smt = NXZoneMalloc (NXDefaultMallocZone(), sizeof (struct objc_method));
                    807:          
                    808:          smt->method_name = sel;
                    809:          smt->method_types = "";
                    810:          smt->method_imp = &_objc_msgForward;
                    811: #ifdef OBJC_COLLECTING_CACHE
                    812:           OBJC_UNLOCK (&messageLock);
                    813:           _cache_fill(savCls, smt);
                    814: #else
                    815:           _cache_fill(savCls, smt);
                    816:           OBJC_UNLOCK (&messageLock);
                    817: #endif
                    818:           return NO;
                    819:        }
                    820:        
                    821: }
                    822: 
                    823: 
                    824: /* Called from -[Object methodFor:] and +[Object instanceMethodFor:]. */
                    825: 
                    826: IMP class_lookupMethod(Class cls, SEL sel)
                    827: {
                    828: #ifdef OBJC_COPY_CACHE
                    829:     struct objc_cache_bucket *buckets;
                    830: #else
                    831:     Method *buckets;
                    832: #endif
                    833:        int index, mask;
                    834:        IMP result;
                    835:        
                    836:        if (sel == 0) 
                    837:                [(id)cls error:_errBadSel, sel];
                    838: 
                    839:        OBJC_LOCK (&messageLock);
                    840: 
                    841:        mask = cls->cache->mask;
                    842:        buckets = cls->cache->buckets;
                    843: 
                    844:        index = (unsigned int) sel & mask;
                    845: 
                    846:        for (;;) {
                    847:            if (! CACHE_BUCKET_VALID (buckets[index]))
                    848:              goto cacheMiss;
                    849:            if (CACHE_BUCKET_NAME (buckets[index]) == sel)
                    850:              {
                    851:                result = CACHE_BUCKET_IMP (buckets[index]);
                    852:                
                    853:                OBJC_UNLOCK (&messageLock);
                    854:                return result;
                    855:              }
                    856:            index++;
                    857:            index &= mask;
                    858:        }
                    859: 
                    860: cacheMiss:
                    861:        result = _class_lookupMethodAndLoadCache(cls, sel);
                    862:        OBJC_UNLOCK (&messageLock);
                    863:        return result;
                    864: }
                    865: 
                    866: 
                    867: /* Private extern.  Called from objc-load.m and _objc_callLoads(). */
                    868: 
                    869: IMP class_lookupMethodInMethodList(struct objc_method_list *mlist, SEL sel)
                    870: {
                    871:        register int n;
                    872:        register Method smt;
                    873: 
                    874:        smt = mlist->method_list;
                    875:        n = mlist->method_count;
                    876: 
                    877:        while (--n >= 0) {
                    878:                if (sel == smt->method_name)
                    879: #ifdef RUNTIME_DYLD
                    880:                  {
                    881:                    _objc_bindModuleContainingList (mlist);
                    882:                    return smt->method_imp;
                    883:                  }
                    884: #else
                    885:                        return smt->method_imp;
                    886: #endif
                    887:                smt++;
                    888:        }
                    889:        return 0;
                    890: }
                    891: 
                    892: #ifdef OBJC_COPY_CACHE
                    893: #define BUCKETSIZE(size)       ((size-1) * sizeof(struct objc_cache_bucket))
                    894: #else
                    895: #define BUCKETSIZE(size)       ((size-1) * sizeof(Method))
                    896: #endif
                    897: 
                    898: /* Private extern.  Called from _cache_expand() and objc_addClass(). */
                    899: 
                    900: Cache _cache_create(Class class)
                    901: {
                    902:        Cache new_cache;
                    903:        int size, i;
                    904: 
                    905:        size = (ISMETA (class)) ? META_CACHE_SIZE : CACHE_SIZE;
                    906: 
                    907:        // allocate and initialize table...
                    908:        new_cache = NXZoneMalloc (NXDefaultMallocZone(),
                    909:                        sizeof(struct objc_cache) + BUCKETSIZE(size)); 
                    910: 
                    911:        for (i = 0; i < size; i++)
                    912:           CACHE_BUCKET_VALID (new_cache->buckets[i]) = (void*)0;
                    913:        new_cache->occupied = 0;
                    914:        new_cache->mask = size - 1;
                    915: 
                    916:        // install the cache
                    917:        class->cache = new_cache;
                    918: 
                    919:        // Reset the cache flush flag
                    920:        class->info &= ~(CLS_FLUSH_CACHE);
                    921: 
                    922:         if (_class_slow_grow)
                    923:           {
                    924:            // reset the grow flag
                    925:             class->info &= ~(CLS_GROW_CACHE);
                    926:           }
                    927: 
                    928:        return new_cache;
                    929: }
                    930: 
                    931: 
                    932: /* Called from _cache_fill().
                    933: #ifdef OBJC_COLLECTING_CACHE
                    934:    The cacheUpdateLock is assumed to be taken at this point. 
                    935: #endif
                    936: */
                    937: 
                    938: static Cache _cache_expand(Class class)
                    939: {
                    940:        Cache old_cache, new_cache;
                    941:        unsigned int size, i;
                    942: 
                    943:        old_cache = class->cache;
                    944: 
                    945:        if (old_cache == &emptyCache)
                    946:          return _cache_create (class);
                    947: 
                    948:         if (_class_slow_grow)
                    949:           {
                    950:             if ((class->info & CLS_GROW_CACHE) == 0)
                    951:               {
                    952:                 old_cache->occupied = 0;
                    953:                 for (i = 0; i < old_cache->mask + 1; i++)
                    954:                   {
                    955:                     if (CACHE_BUCKET_VALID (old_cache->buckets[i]))
                    956:                       {
                    957: #ifndef OBJC_COPY_CACHE
                    958:                         if (CACHE_BUCKET_IMP (old_cache->buckets[i])
                    959:                            == &_objc_msgForward) {
                    960: #ifdef OBJC_COLLECTING_CACHE
                    961:                             _cache_collect_free(old_cache->buckets[i], 0);
                    962: #else
                    963:                             NXZoneFree(NXDefaultMallocZone(), old_cache->buckets[i]);
                    964: #endif
                    965:                         }
                    966: #endif
                    967:                         CACHE_BUCKET_VALID (old_cache->buckets[i]) = (void*)0;
                    968:                     }
                    969:                   }
                    970:                 class->info |= CLS_GROW_CACHE;
                    971:                 return old_cache;
                    972:               }
                    973:             else
                    974:               {
                    975:                 class->info &= ~CLS_GROW_CACHE;
                    976:               }
                    977:           }
                    978: 
                    979:        /* make sure size is a power of 2 */
                    980:        size = (old_cache->mask + 1) << 1;
                    981: 
                    982:        /* allocate and initialize table... */
                    983:        new_cache = NXZoneMalloc (NXDefaultMallocZone(),
                    984:                        sizeof(struct objc_cache) + BUCKETSIZE(size));
                    985: 
                    986:        // Zero out new cache
                    987:        new_cache->mask = size - 1;
                    988:        new_cache->occupied = 0;
                    989:        
                    990:        for (i = 0; i < size; i++)
                    991:           CACHE_BUCKET_VALID (new_cache->buckets[i]) = (void*)0;
                    992: 
                    993:         if (_class_uncache == 0)
                    994:           {
                    995:            // Insert old cache entries into new cache
                    996:             for (i = 0; i < old_cache->mask + 1; i++)
                    997:               {
                    998:                 if (CACHE_BUCKET_VALID (old_cache->buckets[i]))
                    999:                   {
                   1000:                     int mask = new_cache->mask;
                   1001:                     int index = (unsigned int) CACHE_BUCKET_NAME (old_cache->buckets[i]) & mask;
                   1002: 
                   1003:                     for (;;)
                   1004:                       {
                   1005:                         if (! CACHE_BUCKET_VALID (new_cache->buckets[index]))
                   1006:                           {
                   1007:                             new_cache->buckets[index] = old_cache->buckets[i];
                   1008:                             break;
                   1009:                           }
                   1010:                         index++;
                   1011:                         index &= mask;
                   1012:                       }
                   1013:                     new_cache->occupied++;
                   1014:                   }
                   1015:               }
                   1016:        
                   1017:            // Set the cache flush flag so that we will flush this cache
                   1018:            // before expanding it again.
                   1019:             class->info |= CLS_FLUSH_CACHE;
                   1020:           }
                   1021:         else
                   1022:           {
                   1023:            // free any malloced method descriptors...class_respondsToMethod()
                   1024:            // does this for negative caching.
                   1025: #ifndef OBJC_COPY_CACHE
                   1026:             for (i = 0; i < old_cache->mask + 1; i++) {
                   1027:                 if (CACHE_BUCKET_VALID (old_cache->buckets[i]) &&
                   1028:                     CACHE_BUCKET_IMP (old_cache->buckets[i]) == &_objc_msgForward) {
                   1029: #ifdef OBJC_COLLECTING_CACHE
                   1030:                     _cache_collect_free(old_cache->buckets[i], 0);
                   1031: #else
                   1032:                     NXZoneFree(NXDefaultMallocZone(), old_cache->buckets[i]);
                   1033: #endif
                   1034:                 }
                   1035:              }
                   1036: #endif
                   1037:           }
                   1038: 
                   1039:        class->cache = new_cache;
                   1040: 
                   1041: #ifdef OBJC_COLLECTING_CACHE
                   1042:         _cache_collect_free(old_cache, 1);
                   1043: #else
                   1044:        NXZoneFree(NXDefaultMallocZone(), old_cache);
                   1045: #endif
                   1046:        return new_cache;
                   1047: }
                   1048: 
                   1049: /* Called only from _class_lookupMethodAndLoadCache and class_respondsToMethod.
                   1050: #ifdef OBJC_COLLECTING_CACHE
                   1051:    It doesn't matter if someone has the messageLock when we enter this function.
                   1052:    This function will fail to do the update if someone else is already updating
                   1053:    the cache, i.e. they have the cacheUpdateLock.
                   1054: #else
                   1055:    The messageLock is already assumed to be taken out.
                   1056: #endif
                   1057:  */
                   1058: 
                   1059: static void _cache_fill(Class class, Method smt)
                   1060: {
                   1061:     Cache cache;
                   1062:     SEL sel = smt->method_name;
                   1063: #ifdef OBJC_COPY_CACHE
                   1064:     IMP imp = smt->method_imp;
                   1065:     struct objc_cache_bucket *buckets;
                   1066: #else
                   1067:     Method *buckets;
                   1068: #endif
                   1069:     int index, mask;
                   1070:     unsigned int new_count;
                   1071: 
                   1072: #ifdef OBJC_COLLECTING_CACHE
                   1073:     if (! OBJC_TRYLOCK (&cacheUpdateLock))
                   1074:         return;
                   1075: 
                   1076:     cache = class->cache;
                   1077:     mask = cache->mask;
                   1078:     index = (unsigned int) sel & mask;
                   1079:     buckets = cache->buckets;
                   1080: 
                   1081:     for (;;) {
                   1082:         if (! CACHE_BUCKET_VALID (buckets[index]))
                   1083:             break;
                   1084:         if (CACHE_BUCKET_NAME (buckets[index]) == sel)
                   1085:           {
                   1086:             OBJC_UNLOCK (&cacheUpdateLock);
                   1087:             return;
                   1088:           }
                   1089:         index++;
                   1090:         index &= mask;
                   1091:     }
                   1092: 
                   1093: #else
                   1094:     cache = class->cache;
                   1095:     mask = cache->mask;
                   1096: #endif
                   1097: 
                   1098: 
                   1099:     /* Expand or flush the cache if more than 3/4 full.  */
                   1100:     new_count = cache->occupied + 1;
                   1101:     if ((new_count * 4) > (mask + 1) * 3)
                   1102:       {
                   1103:         if (class->info & CLS_FLUSH_CACHE)
                   1104:             _cache_flush (class);              // Clears CLS_FLUSH_CACHE bit
                   1105:         else
                   1106:           {
                   1107:             cache = _cache_expand (class);     // Sets CLS_FLUSH_CACHE bit
                   1108:             mask = cache->mask;
                   1109:           }
                   1110:         cache->occupied++;
                   1111:       }
                   1112:     else
                   1113:         cache->occupied = new_count;
                   1114: 
                   1115:     buckets = cache->buckets;
                   1116: 
                   1117:     index = (unsigned int)sel & mask;
                   1118:     
                   1119: #ifdef OBJC_COPY_CACHE
                   1120:     imp = smt->method_imp;
                   1121:     sel = smt->method_name;
                   1122: #endif
                   1123:     for (;;)
                   1124:       {
                   1125: #ifdef OBJC_COPY_CACHE
                   1126: #ifdef OBJC_COLLECTING_CACHE
                   1127:         if (! CACHE_BUCKET_VALID (buckets[index]))
                   1128:           {
                   1129:             CACHE_BUCKET_IMP  (buckets[index]) = imp;
                   1130:             CACHE_BUCKET_NAME (buckets[index]) = sel;
                   1131: 
                   1132:             /* we can free it right away, because it was just
                   1133:                allocated from _class_lookupMethodAndLoadCache */
                   1134:             if (smt->method_imp == &_objc_msgForward)
                   1135:                 NXZoneFree (NXDefaultMallocZone (), smt);
                   1136:             break;
                   1137:           }
                   1138: #else
                   1139:         struct objc_cache_bucket prev = buckets[index];
                   1140: 
                   1141:         CACHE_BUCKET_NAME (buckets[index]) = sel;
                   1142:         CACHE_BUCKET_IMP  (buckets[index]) = imp;
                   1143: 
                   1144:         if (! CACHE_BUCKET_VALID (prev))
                   1145:           {
                   1146:             if (smt->method_imp == &_objc_msgForward)
                   1147:                 NXZoneFree (NXDefaultMallocZone (), smt);
                   1148:             break;
                   1149:           }
                   1150: 
                   1151:         sel = CACHE_BUCKET_NAME (prev);
                   1152:         imp = CACHE_BUCKET_IMP  (prev);
                   1153: #endif /* OBJC_COLLECTING_CACHE */
                   1154:         index++;
                   1155:         index &= mask;
                   1156: #else
                   1157:         Method prev = buckets[index];
                   1158:         buckets[index] = smt;
                   1159: 
                   1160:         if (prev == NULL)
                   1161:             break;
                   1162: 
                   1163:         smt = prev;
                   1164:         index++;
                   1165:         index &= mask;
                   1166: #endif 
                   1167:       }
                   1168: 
                   1169: #ifdef OBJC_COLLECTING_CACHE
                   1170:     OBJC_UNLOCK (&cacheUpdateLock);
                   1171: #endif
                   1172: }
                   1173: 
                   1174: 
                   1175: /* Called from flush_caches(). */
                   1176: 
                   1177: static void _cache_flush (Class class)
                   1178: {
                   1179:   Cache cache = class->cache;
                   1180:   unsigned int i;
                   1181:   
                   1182:   if (cache == &emptyCache)
                   1183:     return;
                   1184:   
                   1185:   // free any malloced method descriptors...class_respondsToMethod()
                   1186:   // does this for negative caching.
                   1187:   for (i = 0; i <= cache->mask; i++)
                   1188:     {
                   1189: #ifndef OBJC_COPY_CACHE
                   1190:       if (cache->buckets[i] &&
                   1191:          cache->buckets[i]->method_imp == &_objc_msgForward)
                   1192: #ifdef OBJC_COLLECTING_CACHE
                   1193:                     _cache_collect_free(cache->buckets[i], 0);
                   1194: #else
                   1195:                     NXZoneFree(NXDefaultMallocZone(), cache->buckets[i]);
                   1196: #endif
                   1197: #endif
                   1198:       CACHE_BUCKET_VALID (cache->buckets[i]) = (void*)0;
                   1199:     }
                   1200:   
                   1201:   cache->occupied = 0;
                   1202:   
                   1203:   // Reset the cache flush flag
                   1204:   class->info &= ~CLS_FLUSH_CACHE;
                   1205: }
                   1206: 
                   1207: 
                   1208: /* Called only from _class_lookupMethodAndLoadCache.
                   1209:    The messageLock is already assumed to be taken out. */
                   1210: 
                   1211: static inline Method _class_lookupMethod(Class cls, SEL sel)
                   1212: {
                   1213:        register int n;
                   1214:        register Method smt;
                   1215:        struct objc_method_list *mlist;
                   1216: 
                   1217:        for (mlist = cls->methods; mlist; mlist = mlist->method_next) {
                   1218:                smt = mlist->method_list;
                   1219:                n = mlist->method_count;
                   1220: 
                   1221:                while (--n >= 0) {
                   1222:                        if (sel == smt->method_name) {
                   1223: #ifdef RUNTIME_DYLD
                   1224:                          {
                   1225:                            _objc_bindModuleContainingList (mlist);
                   1226:                            return smt;
                   1227:                          }
                   1228: #else
                   1229:                          return smt;
                   1230: #endif
                   1231:                        }
                   1232:                        smt++;
                   1233:                }
                   1234:        }
                   1235:        return 0;
                   1236: }
                   1237: 
                   1238: 
                   1239: /* Returns a pointer to the dummy freed object class (private extern).  */
                   1240: 
                   1241: Class _objc_getFreedObjectClass (void) { return (Class) &freedObjectClass; }
                   1242: 
                   1243: #ifdef RUNTIME_DYLD
                   1244: Class _objc_getNonexistentClass (void) { return (Class) &nonexistentObjectClass; }
                   1245: #endif
                   1246: 
                   1247: 
                   1248: /* Called only from objc_msgSend, objc_msgSendSuper and class_lookupMethod.
                   1249:    (*NOT*) The messageLock is already assumed to be taken out. */
                   1250: 
                   1251: IMP _class_lookupMethodAndLoadCache(Class savCls, SEL sel)
                   1252: {
                   1253:        register Class cls = savCls;
                   1254:        Method method;
                   1255: 
                   1256:        if (cls == &freedObjectClass)
                   1257:          return (IMP)_freedHandler;
                   1258: #ifdef RUNTIME_DYLD
                   1259:         if (cls == &nonexistentObjectClass)
                   1260:           return (IMP)_nonexistentHandler;
                   1261: #endif
                   1262: 
                   1263:        // lazy initialization...
                   1264:        if (CLS_GETINFO(cls,CLS_META) && !ISINITIALIZED(cls))
                   1265:                class_initialize(objc_getClass (cls->name));
                   1266: 
                   1267:        do {
                   1268:                method = _class_lookupMethod(cls, sel);
                   1269:                if (method) {
                   1270:                        _cache_fill(savCls, method);
                   1271:                        return method->method_imp;
                   1272:                }
                   1273:        } while ((cls = cls->super_class));
                   1274: 
                   1275:        // class does not respond -- try forwarding
                   1276:        {
                   1277:                Method smt = NXZoneMalloc(NXDefaultMallocZone(), sizeof(struct objc_method));
                   1278:                smt->method_name = sel;
                   1279:                smt->method_types = "";
                   1280:                smt->method_imp = &_objc_msgForward;
                   1281:                _cache_fill(savCls, smt);
                   1282:        }
                   1283:        return &_objc_msgForward;
                   1284: }
                   1285: 
                   1286: /* delegation */
                   1287: 
                   1288: static int SubTypeUntil (const char *type, char end) 
                   1289: {
                   1290:     int                level = 0;
                   1291:     const char *head = type;
                   1292:     while (*type) {
                   1293:        if (!*type || (! level && (*type == end)))
                   1294:            return (int)(type - head);
                   1295:        switch (*type) {
                   1296:            case ']': case '}': case ')': level--; break;
                   1297:            case '[': case '{': case '(': level++; break;
                   1298:        }
                   1299:        type ++;
                   1300:     }
                   1301:     _NXLogError("Object: SubTypeUntil: end of type encountered prematurely\n");
                   1302:     return 0;
                   1303: }
                   1304: 
                   1305: static const char *SkipFirstType (const char *type) 
                   1306: {
                   1307:   while (1)
                   1308:     {
                   1309:     switch (*type++) 
                   1310:       {
                   1311:        case 'O':       /* bycopy */
                   1312:        case 'n':       /* in */
                   1313:        case 'o':       /* out */
                   1314:        case 'N':       /* inout */
                   1315:        case 'r':       /* const */
                   1316:        case 'V':       /* oneway */
                   1317:        case '^':       /* pointers */
                   1318:                break;
                   1319: 
                   1320:        /* arrays */
                   1321:        case '[':
                   1322:                while ('0' <= *type && '9' >= *type) type++;
                   1323:                return type + SubTypeUntil(type, ']') + 1;
                   1324: 
                   1325:        /* structures */
                   1326:        case '{':
                   1327:                return type + SubTypeUntil(type, '}') + 1;
                   1328: 
                   1329:        /* unions */
                   1330:        case '(':
                   1331:                return type + SubTypeUntil(type, ')') + 1;
                   1332:            
                   1333:        /* basic types */
                   1334:        default: 
                   1335:                return type;
                   1336:       }
                   1337:     }
                   1338: }
                   1339: 
                   1340: unsigned method_getNumberOfArguments(Method method)
                   1341: {
                   1342:        const char *typedesc = method->method_types;
                   1343:        unsigned nargs = 0;
                   1344: 
                   1345:        /* first, skip the return type */
                   1346:        typedesc = SkipFirstType(typedesc);
                   1347: 
                   1348:        /* next, skip stack size */
                   1349:        while ('0' <= *typedesc && '9' >= *typedesc) 
                   1350:                typedesc++;
                   1351: 
                   1352:        /* now, we have the arguments - count how many */
                   1353:        while (*typedesc) {
                   1354: 
                   1355:                /* skip argument type */
                   1356:                typedesc = SkipFirstType(typedesc);
                   1357:                
                   1358:                /* next is the argument offset, blow it off */
                   1359:                if (*typedesc == '-')  /* skip negative sign in offset */
                   1360:                        typedesc++;
                   1361:                while ('0' <= *typedesc && '9' >= *typedesc) 
                   1362:                        typedesc++;
                   1363: 
                   1364:                nargs++;
                   1365:        }
                   1366:        return nargs;
                   1367: }
                   1368: 
                   1369: unsigned method_getSizeOfArguments(Method method)
                   1370: {
                   1371:        const char *typedesc = method->method_types;
                   1372:        unsigned stack_size = 0;
                   1373: 
                   1374:        /* first, skip the return type */
                   1375:        typedesc = SkipFirstType(typedesc);
                   1376: 
                   1377:        while ('0' <= *typedesc && '9' >= *typedesc) 
                   1378:                stack_size = stack_size * 10 + (*typedesc++ - '0');
                   1379: 
                   1380:        return stack_size;
                   1381: }
                   1382: 
                   1383: unsigned method_getArgumentInfo(Method method, int arg, 
                   1384:                                const char **type, int *offset)
                   1385: {
                   1386:        const char *typedesc = method->method_types;
                   1387:        unsigned nargs = 0;
                   1388:        unsigned self_offset = 0;
                   1389:        BOOL offset_is_negative = NO;
                   1390: 
                   1391:        /* first, skip the return type */
                   1392:        typedesc = SkipFirstType(typedesc);
                   1393: 
                   1394:        /* next, skip stack size */
                   1395:        while ('0' <= *typedesc && '9' >= *typedesc) 
                   1396:                typedesc++;
                   1397: 
                   1398:        /* now, we have the arguments - position typedesc to the appropriate argument */
                   1399:        while (*typedesc && nargs != arg) {
                   1400: 
                   1401:                /* skip argument type */
                   1402:                typedesc = SkipFirstType(typedesc);
                   1403:                
                   1404:                if (nargs == 0) {
                   1405:                        if (*typedesc == '-') { /* skip negative sign in offset */
                   1406:                                offset_is_negative = YES;
                   1407:                                typedesc++;
                   1408:                        } else {
                   1409:                                offset_is_negative = NO;
                   1410:                        }
                   1411:                        while ('0' <= *typedesc && '9' >= *typedesc) 
                   1412:                                self_offset = self_offset * 10 + (*typedesc++ - '0');
                   1413:                        if (offset_is_negative) 
                   1414:                                self_offset = - self_offset;
                   1415:                } else {
                   1416:                        /* next is the argument offset, blow it off */
                   1417:                        if (*typedesc == '-') 
                   1418:                                typedesc++;
                   1419:                        while ('0' <= *typedesc && '9' >= *typedesc) 
                   1420:                                typedesc++;
                   1421:                }
                   1422:                nargs++;
                   1423:        }
                   1424:        if (*typedesc) {
                   1425:                unsigned arg_offset = 0;
                   1426: 
                   1427:                *type = typedesc;
                   1428:                typedesc = SkipFirstType(typedesc);
                   1429: 
                   1430:                if (arg == 0) {
                   1431: #if hppa
                   1432:                        *offset = -sizeof(id);
                   1433: #else
                   1434:                        *offset = 0;
                   1435: #endif hppa                    
                   1436:                } else {
                   1437:                        if (*typedesc == '-') { /* skip negative sign in offset */
                   1438:                                offset_is_negative = YES;
                   1439:                                typedesc++;
                   1440:                        } else {
                   1441:                                offset_is_negative = NO;
                   1442:                        }
                   1443:                        while ('0' <= *typedesc && '9' >= *typedesc) 
                   1444:                                arg_offset = arg_offset * 10 + (*typedesc++ - '0');
                   1445:                        if (offset_is_negative) 
                   1446:                                arg_offset = - arg_offset;
                   1447:                                
                   1448: #if hppa
                   1449:                        /*
                   1450:                         * For stacks which grow up, since margs points
                   1451:                         * to the top of the stack or the END of the args, 
                   1452:                         * the first offset is at -sizeof(id) rather than 0.
                   1453:                         */
                   1454:                        self_offset += sizeof(id);
                   1455: #endif
                   1456:                        *offset = arg_offset - self_offset;
                   1457:                }
                   1458:        } else {
                   1459:                *type = 0; *offset = 0;
                   1460:        }
                   1461:        return nargs;
                   1462: }
                   1463: 
                   1464: 
                   1465: /* Private extern. */
                   1466: 
                   1467: NXZone *_objc_create_zone (void)
                   1468: {
                   1469:   static NXZone *_objc_zone = 0;
                   1470: 
                   1471:   if (!_objc_zone)
                   1472:     {
                   1473:       _objc_zone = NXCreateZone (vm_page_size, vm_page_size, YES);
                   1474:       NXNameZone (_objc_zone, "ObjC");
                   1475:     }
                   1476:   
                   1477:   return _objc_zone;
                   1478: }
                   1479: 
                   1480: 
                   1481: 
                   1482: /* cache collection */
                   1483: #ifdef OBJC_COLLECTING_CACHE
                   1484: 
                   1485: #ifdef hppa
                   1486: static unsigned long
                   1487: _get_pc_for_thread (thread_t thread)
                   1488: {
                   1489:     struct hp_pa_frame_thread_state state;
                   1490:     unsigned int count = HPPA_FRAME_THREAD_STATE_COUNT;
                   1491:     thread_get_state (thread, HPPA_FRAME_THREAD_STATE, (thread_state_t)&state, &count);
                   1492:     return state.ts_pcoq_front;
                   1493: }
                   1494: #elif defined (i386)
                   1495: static unsigned long
                   1496: _get_pc_for_thread (thread_t thread)
                   1497: {
                   1498:     i386_thread_state_t state;
                   1499:     unsigned int count = i386_THREAD_STATE_COUNT;
                   1500:     thread_get_state (thread, i386_THREAD_STATE, (thread_state_t)&state, &count);
                   1501:     return state.eip;
                   1502: }
                   1503: 
                   1504: #elif defined (m68k)
                   1505: static unsigned long
                   1506: _get_pc_for_thread (thread_t thread)
                   1507: {
                   1508:     struct m68k_thread_state_regs state;
                   1509:     unsigned int count = M68K_THREAD_STATE_REGS_COUNT;
                   1510:     thread_get_state (thread, M68K_THREAD_STATE_REGS, (thread_state_t)&state, &count);
                   1511:     return state.pc;
                   1512: }
                   1513: 
                   1514: #else
                   1515: /* if OBJC_COLLECTING_CACHE is defined, you need the function above... */
                   1516: { you loose; }
                   1517: #endif
                   1518: 
                   1519: extern unsigned long objc_entryPoints[];
                   1520: extern unsigned long objc_exitPoints[];
                   1521: 
                   1522: static int
                   1523: _collecting_in_critical ()
                   1524: {
                   1525:     thread_array_t threads;
                   1526:     unsigned number, count;
                   1527:     kern_return_t ret;
                   1528:     int result = 0;
                   1529: 
                   1530:     ret = task_threads (task_self (), &threads, &number);
                   1531:     if (ret != KERN_SUCCESS)
                   1532:       {
                   1533:         _NXLogError ("objc: task_thread failed\n");
                   1534:         exit (1);
                   1535:       }
                   1536: 
                   1537:     for (count = 0; !result && count < number; count++)
                   1538:       {
                   1539:         int region;
                   1540:         unsigned long pc;
                   1541: 
                   1542:         if (threads[count] == thread_self ())
                   1543:             continue;
                   1544: 
                   1545:         pc = _get_pc_for_thread (threads[count]);
                   1546: 
                   1547:         for (region = 0; objc_entryPoints[region]; region++)
                   1548:           {
                   1549:             if (   pc >= objc_entryPoints[region]
                   1550:                 && pc <= objc_exitPoints[region])
                   1551:               {
                   1552:                 result = 1;
                   1553:               }
                   1554:           }
                   1555:       }
                   1556: 
                   1557:     vm_deallocate(task_self(), (vm_address_t)threads, sizeof(threads)*count);
                   1558:     return result;
                   1559: }
                   1560: 
                   1561: 
                   1562: static int garbage_byte_size = 0;
                   1563: static int garbage_threshold = 1024;
                   1564: 
                   1565: static void **garbage_refs = 0;
                   1566: static int garbage_count = 0;
                   1567: static int garbage_max = 0;
                   1568: 
                   1569: static void
                   1570: _garbage_make_room ()
                   1571: {
                   1572:     static int first = 1;
                   1573: 
                   1574:     if (first)
                   1575:       {
                   1576:         first = 0;
                   1577:         garbage_refs = NXZoneMalloc (NXDefaultMallocZone (), 128 * sizeof (void*));
                   1578:         garbage_max = 128;
                   1579:       }
                   1580:     else if (garbage_count == garbage_max)
                   1581:       {
                   1582:         garbage_refs = NXZoneRealloc (NXDefaultMallocZone (), garbage_refs, garbage_max*2);
                   1583:         garbage_max *= 2;
                   1584:       }
                   1585: }
                   1586: 
                   1587: static void _cache_collect_free(void *data, BOOL tryCollect)
                   1588: {
                   1589:     char * report_garbage = getenv ("OBJC_REPORT_GARBAGE");
                   1590:     OBJC_LOCK (&cacheCollectionLock);
                   1591: 
                   1592:     /* insert new element in garbage list */
                   1593:     _garbage_make_room ();    
                   1594:     garbage_byte_size += malloc_size (data);
                   1595:     garbage_refs[garbage_count++] = data;
                   1596: 
                   1597:     if (tryCollect && report_garbage)
                   1598:       {
                   1599:         _NXLogError ("objc: total of %d bytes of garbage ...", garbage_byte_size);
                   1600:       }
                   1601: 
                   1602:     if (!tryCollect || garbage_byte_size < garbage_threshold)
                   1603:       {
                   1604:         OBJC_UNLOCK (&cacheCollectionLock);
                   1605:         if (tryCollect && report_garbage)
                   1606:           {
                   1607:             _NXLogError ("below threshold\n");
                   1608:           }
                   1609: 
                   1610:         return;
                   1611:       }
                   1612: 
                   1613:      /* If someone has the explicit read lock, we don't 
                   1614:         try to garbage collect */
                   1615:     if (OBJC_TRYLOCK (&messageLock))
                   1616:       {
                   1617:         if (! _collecting_in_critical ())
                   1618:           {
                   1619:             if (tryCollect && report_garbage)
                   1620:               {
                   1621:                 _NXLogError ("collecting!\n");
                   1622:               }
                   1623: 
                   1624:             while (garbage_count)
                   1625:                 free (garbage_refs[--garbage_count]);
                   1626: 
                   1627:             garbage_byte_size = 0;
                   1628:           }
                   1629:         else if (tryCollect && report_garbage)
                   1630:           {
                   1631:             _NXLogError ("in critical region\n");
                   1632:           }
                   1633: 
                   1634:         OBJC_UNLOCK (&messageLock);
                   1635:       }
                   1636:     else if (tryCollect && report_garbage)
                   1637:       {
                   1638:         _NXLogError ("messageLock taken\n");
                   1639:       }
                   1640: 
                   1641:     OBJC_UNLOCK (&cacheCollectionLock);
                   1642:     return;
                   1643: 
                   1644: }
                   1645: 
                   1646: #endif /* OBJC_COLLECTING_CACHE */
                   1647: 
                   1648: 
                   1649: 
                   1650: #ifndef KERNEL
                   1651: 
                   1652: static void _cache_print (Cache cache)
                   1653: {
                   1654:   unsigned int i, count = cache->mask + 1;
                   1655:   
                   1656:   for (i = 0; i < count; i++)
                   1657:     if (CACHE_BUCKET_VALID (cache->buckets[i]))
                   1658:       {
                   1659:        if (CACHE_BUCKET_IMP (cache->buckets[i]) == &_objc_msgForward)
                   1660:          printf ("does not recognize \n");
                   1661:        printf ("%s\n", (const char *) CACHE_BUCKET_NAME (cache->buckets[i]));
                   1662:       }
                   1663: }
                   1664: 
                   1665: 
                   1666: void _class_printMethodCaches (Class class)
                   1667: {
                   1668:   if (class->cache == &emptyCache)
                   1669:     printf ("no instance-method cache for class %s\n", class->name);
                   1670:   else
                   1671:     {
                   1672:       printf ("instance-method cache for class %s:\n", class->name);
                   1673:       _cache_print (class->cache);
                   1674:     }
                   1675:   
                   1676:   if (class->isa->cache == &emptyCache)
                   1677:     printf ("no class-method cache for class %s\n", class->name);
                   1678:   else
                   1679:     {
                   1680:       printf ("class-method cache for class %s:\n", class->name);
                   1681:       _cache_print (class->isa->cache);
                   1682:     }
                   1683: }
                   1684: 
                   1685: 
                   1686: static unsigned int log2 (unsigned int x)
                   1687: {
                   1688:   unsigned int log = 0;
                   1689:   
                   1690:   while (x >>= 1)
                   1691:     log++;
                   1692:   
                   1693:   return log;
                   1694: }
                   1695: 
                   1696: 
                   1697: #define MAX_LOG_SIZE 32
                   1698: #define MAX_CHAIN_SIZE 100
                   1699: 
                   1700: void _class_printMethodCacheStatistics (void)
                   1701: {
                   1702:   NXHashTable *class_hash = objc_getClasses ();
                   1703:   NXHashState state = NXInitHashState (class_hash);
                   1704:   Class class;
                   1705:   unsigned int classCount = 0;
                   1706:   unsigned int cacheCountBySize[2][MAX_LOG_SIZE] = {0};
                   1707:   unsigned int totalEntriesBySize[2][MAX_LOG_SIZE] = {0};
                   1708:   unsigned int maxEntriesBySize[2][MAX_LOG_SIZE] = {0};
                   1709:   unsigned int totalNegativeEntries = 0;
                   1710:   unsigned int totalChainBySize[2][MAX_LOG_SIZE] = {0};
                   1711:   unsigned int totalMissChainBySize[2][MAX_LOG_SIZE] = {0};
                   1712:   unsigned int totalMaxChainBySize[2][MAX_LOG_SIZE] = {0};
                   1713:   unsigned int totalMaxMissChainBySize[2][MAX_LOG_SIZE] = {0};
                   1714:   unsigned int maxChainBySize[2][MAX_LOG_SIZE] = {0};
                   1715:   unsigned int maxMissChainBySize[2][MAX_LOG_SIZE] = {0};
                   1716:   unsigned int chainCount[MAX_CHAIN_SIZE] = {0};
                   1717:   unsigned int missChainCount[MAX_CHAIN_SIZE] = {0};
                   1718:   
                   1719:   while (NXNextHashState (class_hash, &state, (void **) &class))
                   1720:     {
                   1721:       unsigned int isMeta;
                   1722:       
                   1723:       classCount++;
                   1724:       
                   1725:       for (isMeta = 0; isMeta <= 1; isMeta++)
                   1726:         {
                   1727:          Cache cache = isMeta ? class->isa->cache : class->cache;
                   1728:          
                   1729:          if (cache != &emptyCache)
                   1730:            {
                   1731:              unsigned int i;
                   1732:              unsigned int mask = cache->mask;
                   1733:              unsigned int count = mask + 1;
                   1734:              unsigned int size = log2 (count);
                   1735:              unsigned int entries = 0;
                   1736:              unsigned int negativeEntries = 0;
                   1737:              unsigned int totalChain = 0;
                   1738:              unsigned int totalMissChain = 0;
                   1739:              unsigned int maxChain = 0;
                   1740:              unsigned int maxMissChain = 0;
                   1741:              
                   1742:              cacheCountBySize[isMeta][size]++;
                   1743:              
                   1744:              for (i = 0; i < count; i++)
                   1745:                {
                   1746: #ifdef OBJC_COPY_CACHE
                   1747:                  struct objc_cache_bucket *buckets = cache->buckets;
                   1748: #else
                   1749:                  Method *buckets = cache->buckets;
                   1750: #endif
                   1751:                  
                   1752:                  if (CACHE_BUCKET_VALID (buckets[i]))
                   1753:                    {
                   1754: #ifdef OBJC_COPY_CACHE
                   1755:                      struct objc_cache_bucket method = buckets[i];
                   1756: #else
                   1757:                      Method method = buckets[i];
                   1758: #endif
                   1759:                      unsigned int hash = (unsigned int) CACHE_BUCKET_NAME (method);
                   1760:                      unsigned int chain = (i - hash) & mask;
                   1761:                      unsigned int missChain;
                   1762:                      unsigned int j = i;
                   1763:                      
                   1764:                      entries++;
                   1765:                      
                   1766:                      if (CACHE_BUCKET_IMP (method) == &_objc_msgForward)
                   1767:                        negativeEntries++;
                   1768:                      
                   1769:                      if (chain < MAX_CHAIN_SIZE)
                   1770:                        chainCount[chain]++;
                   1771:                      totalChain += chain;
                   1772:                      if (chain > maxChain)
                   1773:                        maxChain = chain;
                   1774:                      
                   1775:                      while (CACHE_BUCKET_VALID (buckets[j]))
                   1776:                        {
                   1777:                          j++;
                   1778:                          j &= mask;
                   1779:                        }
                   1780:                      
                   1781:                      missChain = (j - i) & mask;
                   1782:                      if (missChain < MAX_CHAIN_SIZE)
                   1783:                        missChainCount[missChain]++;
                   1784:                      totalMissChain += missChain;
                   1785:                      if (missChain > maxMissChain)
                   1786:                        maxMissChain = missChain;
                   1787:                    }
                   1788:                  else
                   1789:                    missChainCount[0]++;
                   1790:                }
                   1791:              
                   1792:              totalEntriesBySize[isMeta][size] += entries;
                   1793:              if (entries > maxEntriesBySize[isMeta][size])
                   1794:                maxEntriesBySize[isMeta][size] = entries;
                   1795:              totalNegativeEntries += negativeEntries;
                   1796:              totalChainBySize[isMeta][size] += totalChain;
                   1797:              totalMissChainBySize[isMeta][size] += totalMissChain;
                   1798:              totalMaxChainBySize[isMeta][size] += maxChain;
                   1799:              totalMaxMissChainBySize[isMeta][size] += maxMissChain;
                   1800:              if (maxChain > maxChainBySize[isMeta][size])
                   1801:                maxChainBySize[isMeta][size] = maxChain;
                   1802:              if (maxMissChain > maxMissChainBySize[isMeta][size])
                   1803:                maxMissChainBySize[isMeta][size] = maxMissChain;
                   1804:            }
                   1805:        }
                   1806:     }
                   1807:   
                   1808:     {
                   1809:       unsigned int isMeta, i;
                   1810:       unsigned int cacheCount[2] = {0};
                   1811:       unsigned int totalCacheCount = 0;
                   1812:       unsigned int totalEntries = 0;
                   1813:       unsigned int totalSize = 0;
                   1814:       unsigned int totalChain = 0;
                   1815:       unsigned int maxChain = 0;
                   1816:       unsigned int totalMissChain = 0;
                   1817:       unsigned int maxMissChain = 0;
                   1818:       
                   1819:       for (isMeta = 0; isMeta <= 1; isMeta++)
                   1820:         {
                   1821:          for (i = 0; i < MAX_LOG_SIZE; i++)
                   1822:            {
                   1823:              cacheCount[isMeta] += cacheCountBySize[isMeta][i];
                   1824:              totalEntries += totalEntriesBySize[isMeta][i];
                   1825:              totalSize += cacheCountBySize[isMeta][i] * (1 << i);
                   1826:              totalChain += totalChainBySize[isMeta][i];
                   1827:              if (maxChainBySize[isMeta][i] > maxChain)
                   1828:                maxChain = maxChainBySize[isMeta][i];
                   1829:              totalMissChain += totalMissChainBySize[isMeta][i];
                   1830:              if (maxMissChainBySize[isMeta][i] > maxMissChain)
                   1831:                maxMissChain = maxMissChainBySize[isMeta][i];
                   1832:            }
                   1833:          
                   1834:          totalCacheCount += cacheCount[isMeta];
                   1835:        }
                   1836:       
                   1837:       for (isMeta = 0; isMeta <= 1; isMeta++)
                   1838:         {
                   1839:          printf ("%u %s-method caches (out of %u classes):\n",
                   1840:                  cacheCount[isMeta],
                   1841:                  isMeta ? "class" : "instance",
                   1842:                  classCount);
                   1843:          
                   1844:          printf ("\n");
                   1845:          
                   1846:          printf ("%s-method cache size distribution:\n",
                   1847:                  isMeta ? "class" : "instance");
                   1848: 
                   1849:          for (i = 0; i < MAX_LOG_SIZE; i++)
                   1850:            if (cacheCountBySize[isMeta][i])
                   1851:              printf ("  %d slots: %u\n", 1 << i, cacheCountBySize[isMeta][i]);
                   1852:          
                   1853:          printf ("\n");
                   1854:          
                   1855:          for (i = 0; i < MAX_LOG_SIZE; i++)
                   1856:            if (cacheCountBySize[isMeta][i])
                   1857:              {
                   1858:                printf ("  %u %s-method caches with %d slots (%u%% efficiency):\n",
                   1859:                        cacheCountBySize[isMeta][i],
                   1860:                        isMeta ? "class" : "instance",
                   1861:                        1 << i,
                   1862:                        (100 * totalEntriesBySize[isMeta][i] + 50) /
                   1863:                        (cacheCountBySize[isMeta][i] * (1 << i)));
                   1864:                printf ("  %.2f average entries (%u maximum)\n",
                   1865:                        (float) totalEntriesBySize[isMeta][i] /
                   1866:                        (float) cacheCountBySize[isMeta][i],
                   1867:                        maxEntriesBySize[isMeta][i]);
                   1868:                printf ("  %.2f average lookup chain (%u maximum)\n",
                   1869:                        (float) totalChainBySize[isMeta][i] /
                   1870:                        (float) totalEntriesBySize[isMeta][i],
                   1871:                        maxChainBySize[isMeta][i]);
                   1872:                printf ("  %.2f average miss chain (%u maximum)\n",
                   1873:                        (float) totalMissChainBySize[isMeta][i] /
                   1874:                        (float) (cacheCountBySize[isMeta][i] * (1 << i)),
                   1875:                        maxMissChainBySize[isMeta][i]);
                   1876:       
                   1877:                printf ("\n");
                   1878:              }
                   1879:        }
                   1880:       
                   1881:       printf ("cummulative method cache statistics:\n");
                   1882:       printf ("  %u entries in %u slots (%u%% efficiency)\n",
                   1883:              totalEntries, totalSize,
                   1884:              (100 * totalEntries + 50) / totalSize);
                   1885:       printf ("  %u negative entries (%u%%)\n",
                   1886:              totalNegativeEntries,
                   1887:              (100 * totalNegativeEntries + 50) / totalEntries);
                   1888:       printf ("  %.2f average lookup chain (%u maximum)\n",
                   1889:              (float) totalChain / (float) totalEntries,
                   1890:              maxChain);
                   1891:       printf ("  %.2f average miss chain (%u maximum)\n",
                   1892:              (float) totalMissChain / (float) totalSize,
                   1893:              maxMissChain);
                   1894: #ifdef OBJC_COPY_CACHE
                   1895:       printf ("  %lu bytes malloced data\n",
                   1896:              totalCacheCount * (sizeof (struct objc_cache) - sizeof (struct objc_cache_bucket))+
                   1897:              totalSize * sizeof (struct objc_cache_bucket) +
                   1898:              totalNegativeEntries * sizeof (struct objc_method));
                   1899: #else
                   1900:       printf ("  %lu bytes malloced data\n",
                   1901:              totalCacheCount * (sizeof (struct objc_cache) - sizeof (Method))+
                   1902:              totalSize * sizeof (Method) +
                   1903:              totalNegativeEntries * sizeof (struct objc_method));
                   1904: #endif
                   1905:       
                   1906:       printf ("\n");
                   1907:       
                   1908:       printf ("lookup chain length distribution:\n");
                   1909:       
                   1910:       for (i = 0; i < MAX_CHAIN_SIZE; i++)
                   1911:         if (chainCount[i])
                   1912:          printf ("  length %u: %u\n", i, chainCount[i]);
                   1913:       
                   1914:       printf ("\n");
                   1915:       
                   1916:       printf ("miss chain length distribution:\n");
                   1917:       
                   1918:       for (i = 0; i < MAX_CHAIN_SIZE; i++)
                   1919:         if (missChainCount[i])
                   1920:          printf ("  length %u: %u\n", i, missChainCount[i]);
                   1921:       
                   1922:       printf ("\n");
                   1923:     }
                   1924: }
                   1925: 
                   1926: #endif /* KERNEL */

unix.superglobalmegacorp.com

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