2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.1 (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
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
22 * @APPLE_LICENSE_HEADER_END@
24 /***********************************************************************
26 * Copyright 1988-1997, Apple Computer, Inc.
28 **********************************************************************/
31 /***********************************************************************
32 * Method cache locking (GrP 2001-1-14)
34 * For speed, objc_msgSend does not acquire any locks when it reads
35 * method caches. Instead, all cache changes are performed so that any
36 * objc_msgSend running concurrently with the cache mutator will not
37 * crash or hang or get an incorrect result from the cache.
39 * When cache memory becomes unused (e.g. the old cache after cache
40 * expansion), it is not immediately freed, because a concurrent
41 * objc_msgSend could still be using it. Instead, the memory is
42 * disconnected from the data structures and placed on a garbage list.
43 * The memory is now only accessible to instances of objc_msgSend that
44 * were running when the memory was disconnected; any further calls to
45 * objc_msgSend will not see the garbage memory because the other data
46 * structures don't point to it anymore. The collecting_in_critical
47 * function checks the PC of all threads and returns FALSE when all threads
48 * are found to be outside objc_msgSend. This means any call to objc_msgSend
49 * that could have had access to the garbage has finished or moved past the
50 * cache lookup stage, so it is safe to free the memory.
52 * All functions that modify cache data or structures must acquire the
53 * cacheUpdateLock to prevent interference from concurrent modifications.
54 * The function that frees cache garbage must acquire the cacheUpdateLock
55 * and use collecting_in_critical() to flush out cache readers.
57 * Cache readers (PC-checked by collecting_in_critical())
62 * Cache writers (hold cacheUpdateLock while reading or writing; not PC-checked)
63 * _cache_fill (acquires lock)
64 * _cache_expand (only called from cache_fill)
65 * _cache_create (only called from cache_expand)
66 * bcopy (only called from instrumented cache_expand)
67 * flush_caches (acquires lock)
68 * _cache_flush (only called from cache_fill and flush_caches)
69 * _cache_collect_free (only called from cache_expand and cache_flush)
71 * UNPROTECTED cache readers (NOT thread-safe; used for debug info only)
73 * _class_printMethodCaches
74 * _class_printDuplicateCacheEntries
75 * _class_printMethodCacheStatistics
77 * _class_lookupMethodAndLoadCache is a special case. It may read a
78 * method triplet out of one cache and store it in another cache. This
79 * is unsafe if the method triplet is a forward:: entry, because the
80 * triplet itself could be freed unless _class_lookupMethodAndLoadCache
81 * were PC-checked or used a lock. Additionally, storing the method
82 * triplet in both caches would result in double-freeing if both caches
83 * were flushed or expanded. The solution is for _cache_getMethod to
84 * ignore all entries whose implementation is _objc_msgForward, so
85 * _class_lookupMethodAndLoadCache cannot look at a forward:: entry
86 * unsafely or place it in multiple caches.
87 ***********************************************************************/
89 /***********************************************************************
90 * Thread-safety during class initialization (GrP 2001-9-24)
92 * Initial state: CLS_INITIALIZING and CLS_INITIALIZED both clear.
93 * During initialization: CLS_INITIALIZING is set
94 * After initialization: CLS_INITIALIZING clear and CLS_INITIALIZED set.
95 * CLS_INITIALIZING and CLS_INITIALIZED are never set at the same time.
96 * CLS_INITIALIZED is never cleared once set.
98 * Only one thread is allowed to actually initialize a class and send
99 * +initialize. Enforced by allowing only one thread to set CLS_INITIALIZING.
101 * Additionally, threads trying to send messages to a class must wait for
102 * +initialize to finish. During initialization of a class, that class's
103 * method cache is kept empty. objc_msgSend will revert to
104 * class_lookupMethodAndLoadCache, which checks CLS_INITIALIZED before
105 * messaging. If CLS_INITIALIZED is clear but CLS_INITIALIZING is set,
106 * the thread must block, unless it is the thread that started
107 * initializing the class in the first place.
109 * Each thread keeps a list of classes it's initializing.
110 * The global classInitLock is used to synchronize changes to CLS_INITIALIZED
111 * and CLS_INITIALIZING: the transition to CLS_INITIALIZING must be
112 * an atomic test-and-set with respect to itself and the transition
113 * to CLS_INITIALIZED.
114 * The global classInitWaitCond is used to block threads waiting for an
115 * initialization to complete. The classInitLock synchronizes
116 * condition checking and the condition variable.
117 **********************************************************************/
119 /***********************************************************************
120 * +initialize deadlock case when a class is marked initializing while
121 * its superclass is initialized. Solved by completely initializing
122 * superclasses before beginning to initialize a class.
124 * OmniWeb class hierarchy:
129 * OWAddressEntry OWController
131 * OWConsoleController
133 * Thread 1 (evil testing thread):
134 * initialize OWAddressEntry
135 * super init OFObject
136 * super init OBObject
137 * [OBObject initialize] runs OBPostLoader, which inits lots of classes...
138 * initialize OWConsoleController
139 * super init OWController - wait for Thread 2 to finish OWController init
141 * Thread 2 (normal OmniWeb thread):
142 * initialize OWController
143 * super init OFObject - wait for Thread 1 to finish OFObject init
147 * Solution: fully initialize super classes before beginning to initialize
148 * a subclass. Then the initializing+initialized part of the class hierarchy
149 * will be a contiguous subtree starting at the root, so other threads
150 * can't jump into the middle between two initializing classes, and we won't
151 * get stuck while a superclass waits for its subclass which waits for the
153 **********************************************************************/
157 /***********************************************************************
159 **********************************************************************/
161 #import <mach/mach_interface.h>
162 #include <mach-o/ldsyms.h>
163 #include <mach-o/dyld.h>
165 #include <sys/types.h>
169 #include <sys/fcntl.h>
171 #import "objc-class.h"
173 #import <objc/Object.h>
174 #import <objc/objc-runtime.h>
175 #import "objc-private.h"
176 #import "hashtable2.h"
179 #include <sys/types.h>
181 #include <CoreFoundation/CFDictionary.h>
183 // Needed functions not in any header file
184 size_t malloc_size (const void * ptr);
186 // Needed kernel interface
187 #import <mach/mach.h>
188 #import <mach/thread_status.h>
191 /***********************************************************************
193 **********************************************************************/
195 // Define PRELOAD_SUPERCLASS_CACHES to cause method lookups to add the
196 // method the appropriate superclass caches, in addition to the normal
197 // encaching in the subclass where the method was messaged. Doing so
198 // will speed up messaging the same method from instances of the
199 // superclasses, but also uses up valuable cache space for a speculative
201 // See radar 2364264 about incorrectly propogating _objc_forward entries
202 // and double freeing them, first, before turning this on!
203 // (Radar 2364264 is now "inactive".)
204 // Double-freeing is also a potential problem when this is off. See
205 // note about _class_lookupMethodAndLoadCache in "Method cache locking".
206 //#define PRELOAD_SUPERCLASS_CACHES
208 /***********************************************************************
210 **********************************************************************/
212 #ifdef OBJC_INSTRUMENTED
214 CACHE_HISTOGRAM_SIZE = 512
217 unsigned int CacheHitHistogram [CACHE_HISTOGRAM_SIZE];
218 unsigned int CacheMissHistogram [CACHE_HISTOGRAM_SIZE];
221 /***********************************************************************
222 * Constants and macros internal to this module.
223 **********************************************************************/
225 // INIT_CACHE_SIZE and INIT_META_CACHE_SIZE must be a power of two
227 INIT_CACHE_SIZE_LOG2 = 2,
228 INIT_META_CACHE_SIZE_LOG2 = 2,
229 INIT_CACHE_SIZE = (1 << INIT_CACHE_SIZE_LOG2),
230 INIT_META_CACHE_SIZE = (1 << INIT_META_CACHE_SIZE_LOG2)
233 // Amount of space required for count hash table buckets, knowing that
234 // one entry is embedded in the cache structure itself
235 #define TABLE_SIZE(count) ((count - 1) * sizeof(Method))
238 /***********************************************************************
239 * Types internal to this module.
240 **********************************************************************/
242 #ifdef OBJC_INSTRUMENTED
243 struct CacheInstrumentation
245 unsigned int hitCount; // cache lookup success tally
246 unsigned int hitProbes; // sum entries checked to hit
247 unsigned int maxHitProbes; // max entries checked to hit
248 unsigned int missCount; // cache lookup no-find tally
249 unsigned int missProbes; // sum entries checked to miss
250 unsigned int maxMissProbes; // max entries checked to miss
251 unsigned int flushCount; // cache flush tally
252 unsigned int flushedEntries; // sum cache entries flushed
253 unsigned int maxFlushedEntries; // max cache entries flushed
255 typedef struct CacheInstrumentation CacheInstrumentation;
257 // Cache instrumentation data follows table, so it is most compatible
258 #define CACHE_INSTRUMENTATION(cache) (CacheInstrumentation *) &cache->buckets[cache->mask + 1];
261 /***********************************************************************
262 * Function prototypes internal to this module.
263 **********************************************************************/
265 static Ivar class_getVariable (Class cls, const char * name);
266 static void flush_caches (Class cls, BOOL flush_meta);
267 static void addClassToOriginalClass (Class posingClass, Class originalClass);
268 static void _objc_addOrigClass (Class origClass);
269 static void _freedHandler (id self, SEL sel);
270 static void _nonexistentHandler (id self, SEL sel);
271 static void class_initialize (Class cls);
272 static Cache _cache_expand (Class cls);
273 static int LogObjCMessageSend (BOOL isClassMethod, const char * objectsClass, const char * implementingClass, SEL selector);
274 static BOOL _cache_fill (Class cls, Method smt, SEL sel);
275 static void _cache_addForwardEntry(Class cls, SEL sel);
276 static void _cache_flush (Class cls);
277 static int SubtypeUntil (const char * type, char end);
278 static const char * SkipFirstType (const char * type);
280 static unsigned long _get_pc_for_thread (mach_port_t thread);
281 static int _collecting_in_critical (void);
282 static void _garbage_make_room (void);
283 static void _cache_collect_free (void * data, BOOL tryCollect);
285 static void _cache_print (Cache cache);
286 static unsigned int log2 (unsigned int x);
287 static void PrintCacheHeader (void);
288 #ifdef OBJC_INSTRUMENTED
289 static void PrintCacheHistogram (char * title, unsigned int * firstEntry, unsigned int entryCount);
292 /***********************************************************************
293 * Static data internal to this module.
294 **********************************************************************/
296 // When _class_uncache is non-zero, cache growth copies the existing
297 // entries into the new (larger) cache. When this flag is zero, new
298 // (larger) caches start out empty.
299 static int _class_uncache = 1;
301 // When _class_slow_grow is non-zero, any given cache is actually grown
302 // only on the odd-numbered times it becomes full; on the even-numbered
303 // times, it is simply emptied and re-used. When this flag is zero,
304 // caches are grown every time.
305 static int _class_slow_grow = 1;
307 // Lock for cache access.
308 // Held when modifying a cache in place.
309 // Held when installing a new cache on a class.
310 // Held when adding to the cache garbage list.
311 // Held when disposing cache garbage.
312 // See "Method cache locking" above for notes about cache locking.
313 static OBJC_DECLARE_LOCK(cacheUpdateLock);
315 // classInitLock protects classInitWaitCond and examination and modification
316 // of CLS_INITIALIZED and CLS_INITIALIZING.
317 OBJC_DECLARE_LOCK(classInitLock);
318 // classInitWaitCond is signalled when any class is done initializing.
319 // Threads that are waiting for a class to finish initializing wait on this.
320 pthread_cond_t classInitWaitCond = PTHREAD_COND_INITIALIZER;
322 CFMutableDictionaryRef _classIMPTables = NULL;
324 // When traceDuplicates is non-zero, _cacheFill checks whether the method
325 // being encached is already there. The number of times it finds a match
326 // is tallied in cacheFillDuplicates. When traceDuplicatesVerbose is
327 // non-zero, each duplication is logged when found in this way.
328 static int traceDuplicates = 0;
329 static int traceDuplicatesVerbose = 0;
330 static int cacheFillDuplicates = 0;
332 #ifdef OBJC_INSTRUMENTED
334 static unsigned int LinearFlushCachesCount = 0;
335 static unsigned int LinearFlushCachesVisitedCount = 0;
336 static unsigned int MaxLinearFlushCachesVisitedCount = 0;
337 static unsigned int NonlinearFlushCachesCount = 0;
338 static unsigned int NonlinearFlushCachesClassCount = 0;
339 static unsigned int NonlinearFlushCachesVisitedCount = 0;
340 static unsigned int MaxNonlinearFlushCachesVisitedCount = 0;
341 static unsigned int IdealFlushCachesCount = 0;
342 static unsigned int MaxIdealFlushCachesCount = 0;
345 // Method call logging
346 typedef int (*ObjCLogProc)(BOOL, const char *, const char *, SEL);
348 static int totalCacheFills = 0;
349 static int objcMsgLogFD = (-1);
350 static ObjCLogProc objcMsgLogProc = &LogObjCMessageSend;
351 static int objcMsgLogEnabled = 0;
355 _errNoMem[] = "failed -- out of memory(%s, %u)",
356 _errAllocNil[] = "allocating nil object",
357 _errFreedObject[] = "message %s sent to freed object=0x%lx",
358 _errNonExistentObject[] = "message %s sent to non-existent object=0x%lx",
359 _errBadSel[] = "invalid selector %s",
360 _errNotSuper[] = "[%s poseAs:%s]: target not immediate superclass",
361 _errNewVars[] = "[%s poseAs:%s]: %s defines new instance variables";
363 /***********************************************************************
364 * Information about multi-thread support:
366 * Since we do not lock many operations which walk the superclass, method
367 * and ivar chains, these chains must remain intact once a class is published
368 * by inserting it into the class hashtable. All modifications must be
369 * atomic so that someone walking these chains will always geta valid
371 ***********************************************************************/
372 /***********************************************************************
373 * A static empty cache. All classes initially point at this cache.
374 * When the first message is sent it misses in the cache, and when
375 * the cache is grown it checks for this case and uses malloc rather
376 * than realloc. This avoids the need to check for NULL caches in the
378 ***********************************************************************/
380 const struct objc_cache emptyCache =
387 // Freed objects have their isa set to point to this dummy class.
388 // This avoids the need to check for Nil classes in the messenger.
389 static const struct objc_class freedObjectClass =
399 (Cache) &emptyCache, // cache
403 static const struct objc_class nonexistentObjectClass =
407 "NONEXISTENT(id)", // name
413 (Cache) &emptyCache, // cache
417 /***********************************************************************
418 * object_getClassName.
419 **********************************************************************/
420 const char * object_getClassName (id obj)
422 // Even nil objects have a class name, sort of
426 // Retrieve name from object's class
427 return ((struct objc_class *) obj->isa)->name;
430 /***********************************************************************
431 * object_getIndexedIvars.
432 **********************************************************************/
433 void * object_getIndexedIvars (id obj)
435 // ivars are tacked onto the end of the object
436 return ((char *) obj) + ((struct objc_class *) obj->isa)->instance_size;
440 /***********************************************************************
441 * _internal_class_createInstanceFromZone. Allocate an instance of the
442 * specified class with the specified number of bytes for indexed
443 * variables, in the specified zone. The isa field is set to the
444 * class, all other fields are zeroed.
445 **********************************************************************/
446 static id _internal_class_createInstanceFromZone (Class aClass,
451 register unsigned byteCount;
453 // Can't create something for nothing
456 __objc_error ((id) aClass, _errAllocNil, 0);
460 // Allocate and initialize
461 byteCount = ((struct objc_class *) aClass)->instance_size + nIvarBytes;
462 obj = (id) malloc_zone_calloc (z, 1, byteCount);
465 __objc_error ((id) aClass, _errNoMem, ((struct objc_class *) aClass)->name, nIvarBytes);
469 // Set the isa pointer
474 /***********************************************************************
475 * _internal_class_createInstance. Allocate an instance of the specified
476 * class with the specified number of bytes for indexed variables, in
477 * the default zone, using _internal_class_createInstanceFromZone.
478 **********************************************************************/
479 static id _internal_class_createInstance (Class aClass,
482 return _internal_class_createInstanceFromZone (aClass,
484 malloc_default_zone ());
487 id (*_poseAs)() = (id (*)())class_poseAs;
488 id (*_alloc)(Class, unsigned) = _internal_class_createInstance;
489 id (*_zoneAlloc)(Class, unsigned, void *) = _internal_class_createInstanceFromZone;
491 /***********************************************************************
492 * class_createInstanceFromZone. Allocate an instance of the specified
493 * class with the specified number of bytes for indexed variables, in
494 * the specified zone, using _zoneAlloc.
495 **********************************************************************/
496 id class_createInstanceFromZone (Class aClass,
500 // _zoneAlloc can be overridden, but is initially set to
501 // _internal_class_createInstanceFromZone
502 return (*_zoneAlloc) (aClass, nIvarBytes, z);
505 /***********************************************************************
506 * class_createInstance. Allocate an instance of the specified class with
507 * the specified number of bytes for indexed variables, using _alloc.
508 **********************************************************************/
509 id class_createInstance (Class aClass,
512 // _alloc can be overridden, but is initially set to
513 // _internal_class_createInstance
514 return (*_alloc) (aClass, nIvarBytes);
517 /***********************************************************************
518 * class_setVersion. Record the specified version with the class.
519 **********************************************************************/
520 void class_setVersion (Class aClass,
523 ((struct objc_class *) aClass)->version = version;
526 /***********************************************************************
527 * class_getVersion. Return the version recorded with the class.
528 **********************************************************************/
529 int class_getVersion (Class aClass)
531 return ((struct objc_class *) aClass)->version;
534 static void _addListIMPsToTable(CFMutableDictionaryRef table, struct objc_method_list *mlist, Class cls, void **iterator) {
536 struct objc_method_list *new_mlist;
538 /* Work from end of list so that categories override */
539 new_mlist = _class_inlinedNextMethodList(cls, iterator);
540 _addListIMPsToTable(table, new_mlist, cls, iterator);
541 for (i = 0; i < mlist->method_count; i++) {
542 CFDictionarySetValue(table, mlist->method_list[i].method_name, mlist->method_list[i].method_imp);
546 static void _addClassIMPsToTable(CFMutableDictionaryRef table, Class cls) {
547 struct objc_method_list *mlist;
549 #ifdef INCLUDE_SUPER_IMPS_IN_IMP_TABLE
550 if (cls->super_class) { /* Do superclass first so subclass overrides */
551 CFMutableDictionaryRef super_table = CFDictionaryGetValue(_classIMPTables, cls->super_class);
554 const void **keys, **values, *buffer1[128], *buffer2[128];
555 cnt = CFDictionaryGetCount(super_table);
556 keys = (cnt <= 128) ? buffer1 : CFAllocatorAllocate(NULL, cnt * sizeof(void *), 0);
557 values = (cnt <= 128) ? buffer2 : CFAllocatorAllocate(NULL, cnt * sizeof(void *), 0);
558 CFDictionaryGetKeysAndValues(super_table, keys, values);
560 CFDictionarySetValue(table, keys[cnt], values[cnt]);
562 if (keys != buffer1) CFAllocatorDeallocate(NULL, keys);
563 if (values != buffer2) CFAllocatorDeallocate(NULL, values);
565 _addClassIMPsToTable(table, cls->super_class);
569 mlist = _class_inlinedNextMethodList(cls, &iterator);
570 _addListIMPsToTable(table, mlist, cls, &iterator);
573 CFMutableDictionaryRef _getClassIMPTable(Class cls) {
574 CFMutableDictionaryRef table;
575 if (NULL == _classIMPTables) {
576 // maps Classes to mutable dictionaries
577 _classIMPTables = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
579 table = (CFMutableDictionaryRef)CFDictionaryGetValue(_classIMPTables, cls);
580 // IMP table maps SELs to IMPS
582 table = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
583 _addClassIMPsToTable(table, cls);
584 CFDictionaryAddValue(_classIMPTables, cls, table);
589 static inline Method _findNamedMethodInList(struct objc_method_list * mlist, const char *meth_name) {
591 if (!mlist) return NULL;
592 for (i = 0; i < mlist->method_count; i++) {
593 Method m = &mlist->method_list[i];
594 if (*((const char *)m->method_name) == *meth_name && 0 == strcmp((const char *)(m->method_name), meth_name)) {
601 /* These next three functions are the heart of ObjC method lookup. */
602 static inline Method _findMethodInList(struct objc_method_list * mlist, SEL sel) {
604 if (!mlist) return NULL;
605 for (i = 0; i < mlist->method_count; i++) {
606 Method m = &mlist->method_list[i];
607 if (m->method_name == sel) {
614 static inline Method _findMethodInClass(Class cls, SEL sel) {
615 struct objc_method_list *mlist;
617 while ((mlist = _class_inlinedNextMethodList(cls, &iterator))) {
618 Method m = _findMethodInList(mlist, sel);
624 static inline Method _getMethod(Class cls, SEL sel) {
625 for (; cls; cls = cls->super_class) {
626 Method m = _findMethodInClass(cls, sel);
633 /***********************************************************************
634 * class_getInstanceMethod. Return the instance method for the
635 * specified class and selector.
636 **********************************************************************/
637 Method class_getInstanceMethod (Class aClass,
640 // Need both a class and a selector
641 if (!aClass || !aSelector)
645 return _getMethod (aClass, aSelector);
648 /***********************************************************************
649 * class_getClassMethod. Return the class method for the specified
650 * class and selector.
651 **********************************************************************/
652 Method class_getClassMethod (Class aClass,
655 // Need both a class and a selector
656 if (!aClass || !aSelector)
659 // Go to the class or isa
660 return _getMethod (GETMETA(aClass), aSelector);
663 /***********************************************************************
664 * class_getVariable. Return the named instance variable.
665 **********************************************************************/
666 static Ivar class_getVariable (Class cls,
669 struct objc_class * thisCls;
671 // Outer loop - search the class and its superclasses
672 for (thisCls = cls; thisCls != Nil; thisCls = ((struct objc_class *) thisCls)->super_class)
677 // Skip class having no ivars
681 // Inner loop - search the given class
682 thisIvar = &thisCls->ivars->ivar_list[0];
683 for (index = 0; index < thisCls->ivars->ivar_count; index += 1)
685 // Check this ivar's name. Be careful because the
686 // compiler generates ivar entries with NULL ivar_name
687 // (e.g. for anonymous bit fields).
688 if ((thisIvar->ivar_name) &&
689 (strcmp (name, thisIvar->ivar_name) == 0))
701 /***********************************************************************
702 * class_getInstanceVariable. Return the named instance variable.
704 * Someday add class_getClassVariable ().
705 **********************************************************************/
706 Ivar class_getInstanceVariable (Class aClass,
709 // Must have a class and a name
710 if (!aClass || !name)
714 return class_getVariable (aClass, name);
717 /***********************************************************************
718 * flush_caches. Flush the instance and optionally class method caches
719 * of cls and all its subclasses.
721 * Specifying Nil for the class "all classes."
722 **********************************************************************/
723 static void flush_caches(Class cls, BOOL flush_meta)
725 int numClasses = 0, newNumClasses;
726 struct objc_class * * classes = NULL;
728 struct objc_class * clsObject;
729 #ifdef OBJC_INSTRUMENTED
730 unsigned int classesVisited;
731 unsigned int subclassCount;
734 // Do nothing if class has no cache
735 // This check is safe to do without any cache locks.
736 if (cls && !((struct objc_class *) cls)->cache)
739 newNumClasses = objc_getClassList((Class *)NULL, 0);
740 while (numClasses < newNumClasses) {
741 numClasses = newNumClasses;
742 classes = realloc(classes, sizeof(Class) * numClasses);
743 newNumClasses = objc_getClassList((Class *)classes, numClasses);
745 numClasses = newNumClasses;
747 OBJC_LOCK(&cacheUpdateLock);
749 // Handle nil and root instance class specially: flush all
750 // instance and class method caches. Nice that this
751 // loop is linear vs the N-squared loop just below.
752 if (!cls || !((struct objc_class *) cls)->super_class)
754 #ifdef OBJC_INSTRUMENTED
755 LinearFlushCachesCount += 1;
759 // Traverse all classes in the hash table
760 for (i = 0; i < numClasses; i++)
762 struct objc_class * metaClsObject;
763 #ifdef OBJC_INSTRUMENTED
766 clsObject = classes[i];
768 // Skip class that is known not to be a subclass of this root
769 // (the isa pointer of any meta class points to the meta class
771 // NOTE: When is an isa pointer of a hash tabled class ever nil?
772 metaClsObject = clsObject->isa;
773 if (cls && metaClsObject && cls->isa != metaClsObject->isa)
778 #ifdef OBJC_INSTRUMENTED
782 _cache_flush (clsObject);
783 if (flush_meta && metaClsObject != NULL) {
784 _cache_flush (metaClsObject);
787 #ifdef OBJC_INSTRUMENTED
788 LinearFlushCachesVisitedCount += classesVisited;
789 if (classesVisited > MaxLinearFlushCachesVisitedCount)
790 MaxLinearFlushCachesVisitedCount = classesVisited;
791 IdealFlushCachesCount += subclassCount;
792 if (subclassCount > MaxIdealFlushCachesCount)
793 MaxIdealFlushCachesCount = subclassCount;
796 OBJC_UNLOCK(&cacheUpdateLock);
801 // Outer loop - flush any cache that could now get a method from
802 // cls (i.e. the cache associated with cls and any of its subclasses).
803 #ifdef OBJC_INSTRUMENTED
804 NonlinearFlushCachesCount += 1;
808 for (i = 0; i < numClasses; i++)
810 struct objc_class * clsIter;
812 #ifdef OBJC_INSTRUMENTED
813 NonlinearFlushCachesClassCount += 1;
815 clsObject = classes[i];
817 // Inner loop - Process a given class
822 #ifdef OBJC_INSTRUMENTED
825 // Flush clsObject instance method cache if
826 // clsObject is a subclass of cls, or is cls itself
827 // Flush the class method cache if that was asked for
830 #ifdef OBJC_INSTRUMENTED
833 _cache_flush (clsObject);
835 _cache_flush (clsObject->isa);
841 // Flush clsObject class method cache if cls is
842 // the meta class of clsObject or of one
843 // of clsObject's superclasses
844 else if (clsIter->isa == cls)
846 #ifdef OBJC_INSTRUMENTED
849 _cache_flush (clsObject->isa);
853 // Move up superclass chain
854 else if (ISINITIALIZED(clsIter))
855 clsIter = clsIter->super_class;
857 // clsIter is not initialized, so its cache
858 // must be empty. This happens only when
859 // clsIter == clsObject, because
860 // superclasses are initialized before
861 // subclasses, and this loop traverses
862 // from sub- to super- classes.
867 #ifdef OBJC_INSTRUMENTED
868 NonlinearFlushCachesVisitedCount += classesVisited;
869 if (classesVisited > MaxNonlinearFlushCachesVisitedCount)
870 MaxNonlinearFlushCachesVisitedCount = classesVisited;
871 IdealFlushCachesCount += subclassCount;
872 if (subclassCount > MaxIdealFlushCachesCount)
873 MaxIdealFlushCachesCount = subclassCount;
876 OBJC_UNLOCK(&cacheUpdateLock);
880 /***********************************************************************
881 * _objc_flush_caches. Flush the caches of the specified class and any
882 * of its subclasses. If cls is a meta-class, only meta-class (i.e.
883 * class method) caches are flushed. If cls is an instance-class, both
884 * instance-class and meta-class caches are flushed.
885 **********************************************************************/
886 void _objc_flush_caches (Class cls)
888 flush_caches (cls, YES);
891 /***********************************************************************
892 * do_not_remove_this_dummy_function.
893 **********************************************************************/
894 void do_not_remove_this_dummy_function (void)
896 (void) class_nextMethodList (NULL, NULL);
899 /***********************************************************************
900 * class_nextMethodList.
903 * void * iterator = 0;
904 * while (class_nextMethodList (cls, &iterator)) {...}
905 **********************************************************************/
906 OBJC_EXPORT struct objc_method_list * class_nextMethodList (Class cls,
909 return _class_inlinedNextMethodList(cls, it);
912 /***********************************************************************
914 **********************************************************************/
917 (void) class_nextMethodList (Nil, NULL);
920 /***********************************************************************
923 * Formerly class_addInstanceMethods ()
924 **********************************************************************/
925 void class_addMethods (Class cls,
926 struct objc_method_list * meths)
928 // Insert atomically.
929 _objc_insertMethods (meths, &((struct objc_class *) cls)->methodLists);
931 // Must flush when dynamically adding methods. No need to flush
932 // all the class method caches. If cls is a meta class, though,
933 // this will still flush it and any of its sub-meta classes.
934 flush_caches (cls, NO);
937 /***********************************************************************
938 * class_addClassMethods.
940 * Obsolete (for binary compatibility only).
941 **********************************************************************/
942 void class_addClassMethods (Class cls,
943 struct objc_method_list * meths)
945 class_addMethods (((struct objc_class *) cls)->isa, meths);
948 /***********************************************************************
949 * class_removeMethods.
950 **********************************************************************/
951 void class_removeMethods (Class cls,
952 struct objc_method_list * meths)
954 // Remove atomically.
955 _objc_removeMethods (meths, &((struct objc_class *) cls)->methodLists);
957 // Must flush when dynamically removing methods. No need to flush
958 // all the class method caches. If cls is a meta class, though,
959 // this will still flush it and any of its sub-meta classes.
960 flush_caches (cls, NO);
963 /***********************************************************************
964 * addClassToOriginalClass. Add to a hash table of classes involved in
965 * a posing situation. We use this when we need to get to the "original"
966 * class for some particular name through the function objc_getOrigClass.
967 * For instance, the implementation of [super ...] will use this to be
968 * sure that it gets hold of the correct super class, so that no infinite
969 * loops will occur if the class it appears in is involved in posing.
971 * We use the classLock to guard the hash table.
973 * See tracker bug #51856.
974 **********************************************************************/
976 static NXMapTable * posed_class_hash = NULL;
977 static NXMapTable * posed_class_to_original_class_hash = NULL;
979 static void addClassToOriginalClass (Class posingClass,
982 // Install hash table when it is first needed
983 if (!posed_class_to_original_class_hash)
985 posed_class_to_original_class_hash =
986 NXCreateMapTableFromZone (NXPtrValueMapPrototype,
988 _objc_create_zone ());
991 // Add pose to hash table
992 NXMapInsert (posed_class_to_original_class_hash,
997 /***********************************************************************
998 * getOriginalClassForPosingClass.
999 **********************************************************************/
1000 Class getOriginalClassForPosingClass (Class posingClass)
1002 return NXMapGet (posed_class_to_original_class_hash, posingClass);
1005 /***********************************************************************
1006 * objc_getOrigClass.
1007 **********************************************************************/
1008 Class objc_getOrigClass (const char * name)
1010 struct objc_class * ret;
1012 // Look for class among the posers
1014 OBJC_LOCK(&classLock);
1015 if (posed_class_hash)
1016 ret = (Class) NXMapGet (posed_class_hash, name);
1017 OBJC_UNLOCK(&classLock);
1021 // Not a poser. Do a normal lookup.
1022 ret = objc_getClass (name);
1024 _objc_inform ("class `%s' not linked into application", name);
1029 /***********************************************************************
1030 * _objc_addOrigClass. This function is only used from class_poseAs.
1031 * Registers the original class names, before they get obscured by
1032 * posing, so that [super ..] will work correctly from categories
1033 * in posing classes and in categories in classes being posed for.
1034 **********************************************************************/
1035 static void _objc_addOrigClass (Class origClass)
1037 OBJC_LOCK(&classLock);
1039 // Create the poser's hash table on first use
1040 if (!posed_class_hash)
1042 posed_class_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype,
1044 _objc_create_zone ());
1047 // Add the named class iff it is not already there (or collides?)
1048 if (NXMapGet (posed_class_hash, ((struct objc_class *)origClass)->name) == 0)
1049 NXMapInsert (posed_class_hash, ((struct objc_class *)origClass)->name, origClass);
1051 OBJC_UNLOCK(&classLock);
1054 /***********************************************************************
1057 * !!! class_poseAs () does not currently flush any caches.
1058 **********************************************************************/
1059 Class class_poseAs (Class imposter,
1062 struct objc_class * clsObject;
1063 char * imposterNamePtr;
1064 NXHashTable * class_hash;
1066 struct objc_class * copy;
1067 #ifdef OBJC_CLASS_REFS
1068 header_info * hInfo;
1071 // Trivial case is easy
1072 if (imposter == original)
1075 // Imposter must be an immediate subclass of the original
1076 if (((struct objc_class *)imposter)->super_class != original) {
1077 __objc_error(imposter, _errNotSuper, ((struct objc_class *)imposter)->name, ((struct objc_class *)original)->name);
1080 // Can't pose when you have instance variables (how could it work?)
1081 if (((struct objc_class *)imposter)->ivars) {
1082 __objc_error(imposter, _errNewVars, ((struct objc_class *)imposter)->name, ((struct objc_class *)original)->name, ((struct objc_class *)imposter)->name);
1085 // Build a string to use to replace the name of the original class.
1086 #define imposterNamePrefix "_%"
1087 imposterNamePtr = malloc_zone_malloc(_objc_create_zone(), strlen(((struct objc_class *)original)->name) + strlen(imposterNamePrefix) + 1);
1088 strcpy(imposterNamePtr, imposterNamePrefix);
1089 strcat(imposterNamePtr, ((struct objc_class *)original)->name);
1090 #undef imposterNamePrefix
1092 // We lock the class hashtable, so we are thread safe with respect to
1093 // calls to objc_getClass (). However, the class names are not
1094 // changed atomically, nor are all of the subclasses updated
1095 // atomically. I have ordered the operations so that you will
1096 // never crash, but you may get inconsistent results....
1098 // Register the original class so that [super ..] knows
1099 // exactly which classes are the "original" classes.
1100 _objc_addOrigClass (original);
1101 _objc_addOrigClass (imposter);
1103 OBJC_LOCK(&classLock);
1105 class_hash = objc_getClasses ();
1107 // Remove both the imposter and the original class.
1108 NXHashRemove (class_hash, imposter);
1109 NXHashRemove (class_hash, original);
1111 // Copy the imposter, so that the imposter can continue
1112 // its normal life in addition to changing the behavior of
1113 // the original. As a hack we don't bother to copy the metaclass.
1114 // For some reason we modify the original rather than the copy.
1115 copy = (*_zoneAlloc)(imposter->isa, sizeof(struct objc_class), _objc_create_zone());
1116 memmove(copy, imposter, sizeof(struct objc_class));
1118 NXHashInsert (class_hash, copy);
1119 addClassToOriginalClass (imposter, copy);
1121 // Mark the imposter as such
1122 CLS_SETINFO(((struct objc_class *)imposter), CLS_POSING);
1123 CLS_SETINFO(((struct objc_class *)imposter)->isa, CLS_POSING);
1125 // Change the name of the imposter to that of the original class.
1126 ((struct objc_class *)imposter)->name = ((struct objc_class *)original)->name;
1127 ((struct objc_class *)imposter)->isa->name = ((struct objc_class *)original)->isa->name;
1129 // Also copy the version field to avoid archiving problems.
1130 ((struct objc_class *)imposter)->version = ((struct objc_class *)original)->version;
1132 // Change all subclasses of the original to point to the imposter.
1133 state = NXInitHashState (class_hash);
1134 while (NXNextHashState (class_hash, &state, (void **) &clsObject))
1136 while ((clsObject) && (clsObject != imposter) &&
1137 (clsObject != copy))
1139 if (clsObject->super_class == original)
1141 clsObject->super_class = imposter;
1142 clsObject->isa->super_class = ((struct objc_class *)imposter)->isa;
1143 // We must flush caches here!
1147 clsObject = clsObject->super_class;
1151 #ifdef OBJC_CLASS_REFS
1152 // Replace the original with the imposter in all class refs
1153 // Major loop - process all headers
1154 for (hInfo = _objc_headerStart(); hInfo != NULL; hInfo = hInfo->next)
1157 unsigned int refCount;
1160 // Get refs associated with this header
1161 cls_refs = (Class *) _getObjcClassRefs ((headerType *) hInfo->mhdr, &refCount);
1162 if (!cls_refs || !refCount)
1165 // Minor loop - process this header's refs
1166 cls_refs = (Class *) ((unsigned long) cls_refs + hInfo->image_slide);
1167 for (index = 0; index < refCount; index += 1)
1169 if (cls_refs[index] == original)
1170 cls_refs[index] = imposter;
1173 #endif // OBJC_CLASS_REFS
1175 // Change the name of the original class.
1176 ((struct objc_class *)original)->name = imposterNamePtr + 1;
1177 ((struct objc_class *)original)->isa->name = imposterNamePtr;
1179 // Restore the imposter and the original class with their new names.
1180 NXHashInsert (class_hash, imposter);
1181 NXHashInsert (class_hash, original);
1183 OBJC_UNLOCK(&classLock);
1188 /***********************************************************************
1190 **********************************************************************/
1191 static void _freedHandler (id self,
1194 __objc_error (self, _errFreedObject, SELNAME(sel), self);
1197 /***********************************************************************
1198 * _nonexistentHandler.
1199 **********************************************************************/
1200 static void _nonexistentHandler (id self,
1203 __objc_error (self, _errNonExistentObject, SELNAME(sel), self);
1206 /***********************************************************************
1207 * _class_install_relationships. Fill in the class pointers of a class
1208 * that was loaded before some or all of the classes it needs to point to.
1209 * The deal here is that the class pointer fields have been usurped to
1210 * hold the string name of the pertinent class. Our job is to look up
1211 * the real thing based on those stored names.
1212 **********************************************************************/
1213 void _class_install_relationships (Class cls,
1216 struct objc_class * meta;
1217 struct objc_class * clstmp;
1219 // Get easy access to meta class structure
1220 meta = ((struct objc_class *)cls)->isa;
1222 // Set version in meta class strucure
1223 meta->version = version;
1225 // Install superclass based on stored name. No name iff
1226 // cls is a root class.
1227 if (((struct objc_class *)cls)->super_class)
1229 clstmp = objc_getClass ((const char *) ((struct objc_class *)cls)->super_class);
1232 _objc_inform("failed objc_getClass(%s) for %s->super_class", (const char *)((struct objc_class *)cls)->super_class, ((struct objc_class *)cls)->name);
1236 ((struct objc_class *)cls)->super_class = clstmp;
1239 // Install meta's isa based on stored name. Meta class isa
1240 // pointers always point to the meta class of the root class
1241 // (root meta class, too, it points to itself!).
1242 clstmp = objc_getClass ((const char *) meta->isa);
1245 _objc_inform("failed objc_getClass(%s) for %s->isa->isa", (const char *) meta->isa, ((struct objc_class *)cls)->name);
1249 meta->isa = clstmp->isa;
1251 // Install meta's superclass based on stored name. No name iff
1252 // cls is a root class.
1253 if (meta->super_class)
1255 // Locate instance class of super class
1256 clstmp = objc_getClass ((const char *) meta->super_class);
1259 _objc_inform("failed objc_getClass(%s) for %s->isa->super_class", (const char *)meta->super_class, ((struct objc_class *)cls)->name);
1263 // Store meta class of super class
1264 meta->super_class = clstmp->isa;
1267 // cls is root, so `tie' the (root) meta class down to its
1268 // instance class. This way, class methods can come from
1269 // the root instance class.
1271 ((struct objc_class *)meta)->super_class = cls;
1273 // Use common static empty cache instead of NULL
1274 if (((struct objc_class *)cls)->cache == NULL)
1275 ((struct objc_class *)cls)->cache = (Cache) &emptyCache;
1276 if (((struct objc_class *)meta)->cache == NULL)
1277 ((struct objc_class *)meta)->cache = (Cache) &emptyCache;
1282 _objc_fatal ("please link appropriate classes in your program");
1285 /***********************************************************************
1286 * class_respondsToMethod.
1288 * Called from -[Object respondsTo:] and +[Object instancesRespondTo:]
1289 **********************************************************************/
1290 BOOL class_respondsToMethod (Class cls,
1296 // No one responds to zero!
1300 imp = _cache_getImp(cls, sel);
1302 // Found method in cache.
1303 // If the cache entry is forward::, the class does not respond to sel.
1304 return (imp != &_objc_msgForward);
1307 // Handle cache miss
1308 meth = _getMethod(cls, sel);
1310 _cache_fill(cls, meth, sel);
1314 // Not implemented. Use _objc_msgForward.
1315 _cache_addForwardEntry(cls, sel);
1321 /***********************************************************************
1322 * class_lookupMethod.
1324 * Called from -[Object methodFor:] and +[Object instanceMethodFor:]
1325 **********************************************************************/
1326 // GrP is this used anymore?
1327 IMP class_lookupMethod (Class cls,
1332 // No one responds to zero!
1334 __objc_error(cls, _errBadSel, sel);
1337 imp = _cache_getImp(cls, sel);
1338 if (imp) return imp;
1340 // Handle cache miss
1341 return _class_lookupMethodAndLoadCache (cls, sel);
1344 /***********************************************************************
1345 * class_lookupMethodInMethodList.
1347 * Called from objc-load.m and _objc_callLoads ()
1348 **********************************************************************/
1349 IMP class_lookupMethodInMethodList (struct objc_method_list * mlist,
1352 Method m = _findMethodInList(mlist, sel);
1353 return (m ? m->method_imp : NULL);
1356 IMP class_lookupNamedMethodInMethodList(struct objc_method_list *mlist,
1357 const char *meth_name)
1359 Method m = meth_name ? _findNamedMethodInList(mlist, meth_name) : NULL;
1360 return (m ? m->method_imp : NULL);
1364 /***********************************************************************
1367 * Called from _cache_create() and cache_expand()
1368 **********************************************************************/
1369 static Cache _cache_malloc(int slotCount)
1374 // Allocate table (why not check for failure?)
1375 size = sizeof(struct objc_cache) + TABLE_SIZE(slotCount);
1376 #ifdef OBJC_INSTRUMENTED
1377 size += sizeof(CacheInstrumentation);
1379 new_cache = malloc_zone_calloc (_objc_create_zone(), size, 1);
1381 // [c|v]allocated memory is zeroed, so all buckets are invalidated
1382 // and occupied == 0 and all instrumentation is zero.
1384 new_cache->mask = slotCount - 1;
1390 /***********************************************************************
1393 * Called from _cache_expand().
1394 * Cache locks: cacheUpdateLock must be held by the caller.
1395 **********************************************************************/
1396 Cache _cache_create (Class cls)
1401 // Select appropriate size
1402 slotCount = (ISMETA(cls)) ? INIT_META_CACHE_SIZE : INIT_CACHE_SIZE;
1404 new_cache = _cache_malloc(slotCount);
1406 // Install the cache
1407 ((struct objc_class *)cls)->cache = new_cache;
1409 // Clear the cache flush flag so that we will not flush this cache
1410 // before expanding it for the first time.
1411 ((struct objc_class * )cls)->info &= ~(CLS_FLUSH_CACHE);
1413 // Clear the grow flag so that we will re-use the current storage,
1414 // rather than actually grow the cache, when expanding the cache
1415 // for the first time
1416 if (_class_slow_grow)
1417 ((struct objc_class * )cls)->info &= ~(CLS_GROW_CACHE);
1419 // Return our creation
1423 /***********************************************************************
1426 * Called from _cache_fill ()
1427 * Cache locks: cacheUpdateLock must be held by the caller.
1428 **********************************************************************/
1429 static Cache _cache_expand (Class cls)
1433 unsigned int slotCount;
1436 // First growth goes from emptyCache to a real one
1437 old_cache = ((struct objc_class *)cls)->cache;
1438 if (old_cache == &emptyCache)
1439 return _cache_create (cls);
1441 // iff _class_slow_grow, trade off actual cache growth with re-using
1442 // the current one, so that growth only happens every odd time
1443 if (_class_slow_grow)
1445 // CLS_GROW_CACHE controls every-other-time behavior. If it
1446 // is non-zero, let the cache grow this time, but clear the
1447 // flag so the cache is reused next time
1448 if ((((struct objc_class * )cls)->info & CLS_GROW_CACHE) != 0)
1449 ((struct objc_class * )cls)->info &= ~CLS_GROW_CACHE;
1451 // Reuse the current cache storage this time
1454 // Clear the valid-entry counter
1455 old_cache->occupied = 0;
1457 // Invalidate all the cache entries
1458 for (index = 0; index < old_cache->mask + 1; index += 1)
1460 // Remember what this entry was, so we can possibly
1461 // deallocate it after the bucket has been invalidated
1462 Method oldEntry = old_cache->buckets[index];
1463 // Skip invalid entry
1464 if (!CACHE_BUCKET_VALID(old_cache->buckets[index]))
1467 // Invalidate this entry
1468 CACHE_BUCKET_VALID(old_cache->buckets[index]) = NULL;
1470 // Deallocate "forward::" entry
1471 if (CACHE_BUCKET_IMP(oldEntry) == &_objc_msgForward)
1473 _cache_collect_free (oldEntry, NO);
1477 // Set the slow growth flag so the cache is next grown
1478 ((struct objc_class * )cls)->info |= CLS_GROW_CACHE;
1480 // Return the same old cache, freshly emptied
1486 // Double the cache size
1487 slotCount = (old_cache->mask + 1) << 1;
1489 new_cache = _cache_malloc(slotCount);
1491 #ifdef OBJC_INSTRUMENTED
1492 // Propagate the instrumentation data
1494 CacheInstrumentation * oldCacheData;
1495 CacheInstrumentation * newCacheData;
1497 oldCacheData = CACHE_INSTRUMENTATION(old_cache);
1498 newCacheData = CACHE_INSTRUMENTATION(new_cache);
1499 bcopy ((const char *)oldCacheData, (char *)newCacheData, sizeof(CacheInstrumentation));
1503 // iff _class_uncache, copy old cache entries into the new cache
1504 if (_class_uncache == 0)
1508 newMask = new_cache->mask;
1510 // Look at all entries in the old cache
1511 for (index = 0; index < old_cache->mask + 1; index += 1)
1515 // Skip invalid entry
1516 if (!CACHE_BUCKET_VALID(old_cache->buckets[index]))
1519 // Hash the old entry into the new table
1520 index2 = CACHE_HASH(CACHE_BUCKET_NAME(old_cache->buckets[index]),
1523 // Find an available spot, at or following the hashed spot;
1524 // Guaranteed to not infinite loop, because table has grown
1527 if (!CACHE_BUCKET_VALID(new_cache->buckets[index2]))
1529 new_cache->buckets[index2] = old_cache->buckets[index];
1537 // Account for the addition
1538 new_cache->occupied += 1;
1541 // Set the cache flush flag so that we will flush this cache
1542 // before expanding it again.
1543 ((struct objc_class * )cls)->info |= CLS_FLUSH_CACHE;
1546 // Deallocate "forward::" entries from the old cache
1549 for (index = 0; index < old_cache->mask + 1; index += 1)
1551 if (CACHE_BUCKET_VALID(old_cache->buckets[index]) &&
1552 CACHE_BUCKET_IMP(old_cache->buckets[index]) == &_objc_msgForward)
1554 _cache_collect_free (old_cache->buckets[index], NO);
1559 // Install new cache
1560 ((struct objc_class *)cls)->cache = new_cache;
1562 // Deallocate old cache, try freeing all the garbage
1563 _cache_collect_free (old_cache, YES);
1567 /***********************************************************************
1568 * instrumentObjcMessageSends/logObjcMessageSends.
1569 **********************************************************************/
1570 static int LogObjCMessageSend (BOOL isClassMethod,
1571 const char * objectsClass,
1572 const char * implementingClass,
1577 // Create/open the log file
1578 if (objcMsgLogFD == (-1))
1580 snprintf (buf, sizeof(buf), "/tmp/msgSends-%d", (int) getpid ());
1581 objcMsgLogFD = open (buf, O_WRONLY | O_CREAT, 0666);
1584 // Make the log entry
1585 snprintf(buf, sizeof(buf), "%c %s %s %s\n",
1586 isClassMethod ? '+' : '-',
1591 write (objcMsgLogFD, buf, strlen(buf));
1593 // Tell caller to not cache the method
1597 void instrumentObjcMessageSends (BOOL flag)
1599 int enabledValue = (flag) ? 1 : 0;
1602 if (objcMsgLogEnabled == enabledValue)
1605 // If enabling, flush all method caches so we get some traces
1607 flush_caches (Nil, YES);
1609 // Sync our log file
1610 if (objcMsgLogFD != (-1))
1611 fsync (objcMsgLogFD);
1613 objcMsgLogEnabled = enabledValue;
1616 void logObjcMessageSends (ObjCLogProc logProc)
1620 objcMsgLogProc = logProc;
1621 objcMsgLogEnabled = 1;
1625 objcMsgLogProc = logProc;
1626 objcMsgLogEnabled = 0;
1629 if (objcMsgLogFD != (-1))
1630 fsync (objcMsgLogFD);
1634 /***********************************************************************
1635 * _cache_fill. Add the specified method to the specified class' cache.
1636 * Returns NO if the cache entry wasn't added: cache was busy,
1637 * class is still being initialized, new entry is a duplicate.
1639 * Called only from _class_lookupMethodAndLoadCache and
1640 * class_respondsToMethod and _cache_addForwardEntry.
1642 * Cache locks: cacheUpdateLock must not be held.
1643 **********************************************************************/
1644 static BOOL _cache_fill(Class cls, Method smt, SEL sel)
1646 unsigned int newOccupied;
1651 // Never cache before +initialize is done
1652 if (!ISINITIALIZED(cls)) {
1656 // Keep tally of cache additions
1657 totalCacheFills += 1;
1659 OBJC_LOCK(&cacheUpdateLock);
1661 cache = ((struct objc_class *)cls)->cache;
1663 // Check for duplicate entries, if we're in the mode
1664 if (traceDuplicates)
1667 arith_t mask = cache->mask;
1668 buckets = cache->buckets;
1671 for (index2 = 0; index2 < mask + 1; index2 += 1)
1673 // Skip invalid or non-duplicate entry
1674 if ((!CACHE_BUCKET_VALID(buckets[index2])) ||
1675 (strcmp ((char *) CACHE_BUCKET_NAME(buckets[index2]), (char *) smt->method_name) != 0))
1678 // Tally duplication, but report iff wanted
1679 cacheFillDuplicates += 1;
1680 if (traceDuplicatesVerbose)
1682 _objc_inform ("Cache fill duplicate #%d: found %x adding %x: %s\n",
1683 cacheFillDuplicates,
1684 (unsigned int) CACHE_BUCKET_NAME(buckets[index2]),
1685 (unsigned int) smt->method_name,
1686 (char *) smt->method_name);
1691 // Make sure the entry wasn't added to the cache by some other thread
1692 // before we grabbed the cacheUpdateLock.
1693 // Don't use _cache_getMethod() because _cache_getMethod() doesn't
1694 // return forward:: entries.
1695 if (_cache_getImp(cls, sel)) {
1696 OBJC_UNLOCK(&cacheUpdateLock);
1697 return NO; // entry is already cached, didn't add new one
1700 // Use the cache as-is if it is less than 3/4 full
1701 newOccupied = cache->occupied + 1;
1702 if ((newOccupied * 4) <= (cache->mask + 1) * 3) {
1703 // Cache is less than 3/4 full.
1704 cache->occupied = newOccupied;
1706 // Cache is too full. Flush it or expand it.
1707 if ((((struct objc_class * )cls)->info & CLS_FLUSH_CACHE) != 0) {
1710 cache = _cache_expand (cls);
1713 // Account for the addition
1714 cache->occupied += 1;
1717 // Insert the new entry. This can be done by either:
1718 // (a) Scanning for the first unused spot. Easy!
1719 // (b) Opening up an unused spot by sliding existing
1720 // entries down by one. The benefit of this
1721 // extra work is that it puts the most recently
1722 // loaded entries closest to where the selector
1723 // hash starts the search.
1725 // The loop is a little more complicated because there
1726 // are two kinds of entries, so there have to be two ways
1728 buckets = cache->buckets;
1729 index = CACHE_HASH(sel, cache->mask);
1732 // Slide existing entries down by one
1735 // Copy current entry to a local
1736 saveMethod = buckets[index];
1738 // Copy previous entry (or new entry) to current slot
1739 buckets[index] = smt;
1741 // Done if current slot had been invalid
1742 if (saveMethod == NULL)
1745 // Prepare to copy saved value into next slot
1748 // Move on to next slot
1750 index &= cache->mask;
1753 OBJC_UNLOCK(&cacheUpdateLock);
1755 return YES; // successfully added new cache entry
1759 /***********************************************************************
1760 * _cache_addForwardEntry
1761 * Add a forward:: entry for the given selector to cls's method cache.
1762 * Does nothing if the cache addition fails for any reason.
1763 * Called from class_respondsToMethod and _class_lookupMethodAndLoadCache.
1764 * Cache locks: cacheUpdateLock must not be held.
1765 **********************************************************************/
1766 static void _cache_addForwardEntry(Class cls, SEL sel)
1770 smt = malloc_zone_malloc(_objc_create_zone(), sizeof(struct objc_method));
1771 smt->method_name = sel;
1772 smt->method_types = "";
1773 smt->method_imp = &_objc_msgForward;
1774 if (! _cache_fill(cls, smt, sel)) {
1775 // Entry not added to cache. Don't leak the method struct.
1776 malloc_zone_free(_objc_create_zone(), smt);
1781 /***********************************************************************
1782 * _cache_flush. Invalidate all valid entries in the given class' cache,
1783 * and clear the CLS_FLUSH_CACHE in the cls->info.
1785 * Called from flush_caches() and _cache_fill()
1786 * Cache locks: cacheUpdateLock must be held by the caller.
1787 **********************************************************************/
1788 static void _cache_flush (Class cls)
1793 // Locate cache. Ignore unused cache.
1794 cache = ((struct objc_class *)cls)->cache;
1795 if (cache == NULL || cache == &emptyCache)
1798 #ifdef OBJC_INSTRUMENTED
1800 CacheInstrumentation * cacheData;
1803 cacheData = CACHE_INSTRUMENTATION(cache);
1804 cacheData->flushCount += 1;
1805 cacheData->flushedEntries += cache->occupied;
1806 if (cache->occupied > cacheData->maxFlushedEntries)
1807 cacheData->maxFlushedEntries = cache->occupied;
1811 // Traverse the cache
1812 for (index = 0; index <= cache->mask; index += 1)
1814 // Remember what this entry was, so we can possibly
1815 // deallocate it after the bucket has been invalidated
1816 Method oldEntry = cache->buckets[index];
1818 // Invalidate this entry
1819 CACHE_BUCKET_VALID(cache->buckets[index]) = NULL;
1821 // Deallocate "forward::" entry
1822 if (oldEntry && oldEntry->method_imp == &_objc_msgForward)
1823 _cache_collect_free (oldEntry, NO);
1826 // Clear the valid-entry counter
1827 cache->occupied = 0;
1829 // Clear the cache flush flag so that we will not flush this cache
1830 // before expanding it again.
1831 ((struct objc_class * )cls)->info &= ~CLS_FLUSH_CACHE;
1834 /***********************************************************************
1835 * _objc_getFreedObjectClass. Return a pointer to the dummy freed
1836 * object class. Freed objects get their isa pointers replaced with
1837 * a pointer to the freedObjectClass, so that we can catch usages of
1839 **********************************************************************/
1840 Class _objc_getFreedObjectClass (void)
1842 return (Class) &freedObjectClass;
1845 /***********************************************************************
1846 * _objc_getNonexistentClass. Return a pointer to the dummy nonexistent
1847 * object class. This is used when, for example, mapping the class
1848 * refs for an image, and the class can not be found, so that we can
1849 * catch later uses of the non-existent class.
1850 **********************************************************************/
1851 Class _objc_getNonexistentClass (void)
1853 return (Class) &nonexistentObjectClass;
1857 /***********************************************************************
1858 * struct _objc_initializing_classes
1859 * Per-thread list of classes currently being initialized by that thread.
1860 * During initialization, that thread is allowed to send messages to that
1861 * class, but other threads have to wait.
1862 * The list is a simple array of metaclasses (the metaclass stores
1863 * the initialization state).
1864 **********************************************************************/
1865 typedef struct _objc_initializing_classes {
1866 int classesAllocated;
1867 struct objc_class** metaclasses;
1868 } _objc_initializing_classes;
1871 /***********************************************************************
1872 * _fetchInitializingClassList
1873 * Return the list of classes being initialized by this thread.
1874 * If create == YES, create the list when no classes are being initialized by this thread.
1875 * If create == NO, return NULL when no classes are being initialized by this thread.
1876 **********************************************************************/
1877 static _objc_initializing_classes *_fetchInitializingClassList(BOOL create)
1879 _objc_pthread_data *data;
1880 _objc_initializing_classes *list;
1881 struct objc_class **classes;
1883 data = pthread_getspecific(_objc_pthread_key);
1888 data = calloc(1, sizeof(_objc_pthread_data));
1889 pthread_setspecific(_objc_pthread_key, data);
1893 list = data->initializingClasses;
1898 list = calloc(1, sizeof(_objc_initializing_classes));
1899 data->initializingClasses = list;
1903 classes = list->metaclasses;
1904 if (classes == NULL) {
1905 // If _objc_initializing_classes exists, allocate metaclass array,
1906 // even if create == NO.
1907 // Allow 4 simultaneous class inits on this thread before realloc.
1908 list->classesAllocated = 4;
1909 classes = calloc(list->classesAllocated, sizeof(struct objc_class *));
1910 list->metaclasses = classes;
1916 /***********************************************************************
1917 * _destroyInitializingClassList
1918 * Deallocate memory used by the given initialization list.
1919 * Any part of the list may be NULL.
1920 * Called from _objc_pthread_destroyspecific().
1921 **********************************************************************/
1922 void _destroyInitializingClassList(_objc_initializing_classes *list)
1925 if (list->metaclasses != NULL) {
1926 free(list->metaclasses);
1933 /***********************************************************************
1934 * _thisThreadIsInitializingClass
1935 * Return TRUE if this thread is currently initializing the given class.
1936 **********************************************************************/
1937 static BOOL _thisThreadIsInitializingClass(struct objc_class *cls)
1941 _objc_initializing_classes *list = _fetchInitializingClassList(NO);
1944 for (i = 0; i < list->classesAllocated; i++) {
1945 if (cls == list->metaclasses[i]) return YES;
1949 // no list or not found in list
1954 /***********************************************************************
1955 * _setThisThreadIsInitializingClass
1956 * Record that this thread is currently initializing the given class.
1957 * This thread will be allowed to send messages to the class, but
1958 * other threads will have to wait.
1959 **********************************************************************/
1960 static void _setThisThreadIsInitializingClass(struct objc_class *cls)
1963 _objc_initializing_classes *list = _fetchInitializingClassList(YES);
1966 // paranoia: explicitly disallow duplicates
1967 for (i = 0; i < list->classesAllocated; i++) {
1968 if (cls == list->metaclasses[i]) {
1969 _objc_fatal("thread is already initializing this class!");
1970 return; // already the initializer
1974 for (i = 0; i < list->classesAllocated; i++) {
1975 if (0 == list->metaclasses[i]) {
1976 list->metaclasses[i] = cls;
1981 // class list is full - reallocate
1982 list->classesAllocated = list->classesAllocated * 2 + 1;
1983 list->metaclasses = realloc(list->metaclasses, list->classesAllocated * sizeof(struct objc_class *));
1984 // zero out the new entries
1985 list->metaclasses[i++] = cls;
1986 for ( ; i < list->classesAllocated; i++) {
1987 list->metaclasses[i] = NULL;
1992 /***********************************************************************
1993 * _setThisThreadIsNotInitializingClass
1994 * Record that this thread is no longer initializing the given class.
1995 **********************************************************************/
1996 static void _setThisThreadIsNotInitializingClass(struct objc_class *cls)
2000 _objc_initializing_classes *list = _fetchInitializingClassList(NO);
2003 for (i = 0; i < list->classesAllocated; i++) {
2004 if (cls == list->metaclasses[i]) {
2005 list->metaclasses[i] = NULL;
2011 // no list or not found in list
2012 _objc_fatal("thread is not initializing this class!");
2016 /***********************************************************************
2017 * class_initialize. Send the '+initialize' message on demand to any
2018 * uninitialized class. Force initialization of superclasses first.
2020 * Called only from _class_lookupMethodAndLoadCache (or itself).
2021 **********************************************************************/
2022 static void class_initialize(struct objc_class *cls)
2024 long *infoP = &GETMETA(cls)->info;
2025 BOOL reallyInitialize = NO;
2027 // Get the real class from the metaclass. The superclass chain
2028 // hangs off the real class only.
2030 if (strncmp(cls->name, "_%", 2) == 0) {
2031 // Posee's meta's name is smashed and isn't in the class_hash,
2032 // so objc_getClass doesn't work.
2033 char *baseName = strchr(cls->name, '%'); // get posee's real name
2034 cls = objc_getClass(baseName);
2036 cls = objc_getClass(cls->name);
2040 // Make sure super is done initializing BEFORE beginning to initialize cls.
2041 // See note about deadlock above.
2042 if (cls->super_class && !ISINITIALIZED(cls->super_class)) {
2043 class_initialize(cls->super_class);
2046 // Try to atomically set CLS_INITIALIZING.
2047 pthread_mutex_lock(&classInitLock);
2048 if (!ISINITIALIZED(cls) && !ISINITIALIZING(cls)) {
2049 *infoP |= CLS_INITIALIZING;
2050 reallyInitialize = YES;
2052 pthread_mutex_unlock(&classInitLock);
2054 if (reallyInitialize) {
2055 // We successfully set the CLS_INITIALIZING bit. Initialize the class.
2057 // Record that we're initializing this class so we can message it.
2058 _setThisThreadIsInitializingClass(cls);
2060 // bind the module in - if it came from a bundle or dynamic library
2061 _objc_bindClassIfNeeded(cls);
2063 // chain on the categories and bind them if necessary
2064 _objc_resolve_categories_for_class(cls);
2066 // Send the +initialize message.
2067 // Note that +initialize is sent to the superclass (again) if
2068 // this class doesn't implement +initialize. 2157218
2069 [(id)cls initialize];
2071 // Done initializing. Update the info bits and notify waiting threads.
2072 pthread_mutex_lock(&classInitLock);
2073 *infoP = (*infoP | CLS_INITIALIZED) & ~CLS_INITIALIZING;
2074 pthread_cond_broadcast(&classInitWaitCond);
2075 pthread_mutex_unlock(&classInitLock);
2076 _setThisThreadIsNotInitializingClass(cls);
2080 else if (ISINITIALIZING(cls)) {
2081 // We couldn't set INITIALIZING because INITIALIZING was already set.
2082 // If this thread set it earlier, continue normally.
2083 // If some other thread set it, block until initialize is done.
2084 // It's ok if INITIALIZING changes to INITIALIZED while we're here,
2085 // because we safely check for INITIALIZED inside the lock
2087 if (_thisThreadIsInitializingClass(cls)) {
2090 pthread_mutex_lock(&classInitLock);
2091 while (!ISINITIALIZED(cls)) {
2092 pthread_cond_wait(&classInitWaitCond, &classInitLock);
2094 pthread_mutex_unlock(&classInitLock);
2099 else if (ISINITIALIZED(cls)) {
2100 // Set CLS_INITIALIZING failed because someone else already
2101 // initialized the class. Continue normally.
2102 // NOTE this check must come AFTER the ISINITIALIZING case.
2103 // Otherwise: Another thread is initializing this class. ISINITIALIZED
2104 // is false. Skip this clause. Then the other thread finishes
2105 // initialization and sets INITIALIZING=no and INITIALIZED=yes.
2106 // Skip the ISINITIALIZING clause. Die horribly.
2111 // We shouldn't be here.
2112 _objc_fatal("thread-safe class init in objc runtime is buggy!");
2117 /***********************************************************************
2118 * _class_lookupMethodAndLoadCache.
2120 * Called only from objc_msgSend, objc_msgSendSuper and class_lookupMethod.
2121 **********************************************************************/
2122 IMP _class_lookupMethodAndLoadCache (Class cls,
2125 struct objc_class * curClass;
2127 IMP methodPC = NULL;
2129 trace(0xb300, 0, 0, 0);
2131 // Check for freed class
2132 if (cls == &freedObjectClass)
2133 return (IMP) _freedHandler;
2135 // Check for nonexistent class
2136 if (cls == &nonexistentObjectClass)
2137 return (IMP) _nonexistentHandler;
2139 trace(0xb301, 0, 0, 0);
2141 if (!ISINITIALIZED(cls)) {
2142 class_initialize ((struct objc_class *)cls);
2143 // If sel == initialize, class_initialize will send +initialize and
2144 // then the messenger will send +initialize again after this
2145 // procedure finishes. Of course, if this is not being called
2146 // from the messenger then it won't happen. 2778172
2149 trace(0xb302, 0, 0, 0);
2151 // Outer loop - search the caches and method lists of the
2152 // class and its super-classes
2153 for (curClass = cls; curClass; curClass = ((struct objc_class * )curClass)->super_class)
2155 #ifdef PRELOAD_SUPERCLASS_CACHES
2156 struct objc_class *curClass2;
2159 trace(0xb303, 0, 0, 0);
2161 // Beware of thread-unsafety and double-freeing of forward::
2162 // entries here! See note in "Method cache locking" above.
2163 // The upshot is that _cache_getMethod() will return NULL
2164 // instead of returning a forward:: entry.
2165 meth = _cache_getMethod(curClass, sel);
2167 // Found the method in this class or a superclass.
2168 // Cache the method in this class, unless we just found it in
2169 // this class's cache.
2170 if (curClass != cls) {
2171 #ifdef PRELOAD_SUPERCLASS_CACHES
2172 for (curClass2 = cls; curClass2 != curClass; curClass2 = curClass2->super_class)
2173 _cache_fill (curClass2, meth, sel);
2174 _cache_fill (curClass, meth, sel);
2176 _cache_fill (cls, meth, sel);
2180 methodPC = meth->method_imp;
2184 trace(0xb304, (int)methodPC, 0, 0);
2186 // Cache scan failed. Search method list.
2188 meth = _findMethodInClass(curClass, sel);
2190 // If logging is enabled, log the message send and let
2191 // the logger decide whether to encache the method.
2192 if ((objcMsgLogEnabled == 0) ||
2193 (objcMsgLogProc (CLS_GETINFO(((struct objc_class * )curClass),
2194 CLS_META) ? YES : NO,
2195 ((struct objc_class *)cls)->name,
2196 curClass->name, sel)))
2198 // Cache the method implementation
2199 #ifdef PRELOAD_SUPERCLASS_CACHES
2200 for (curClass2 = cls; curClass2 != curClass; curClass2 = curClass2->super_class)
2201 _cache_fill (curClass2, meth, sel);
2202 _cache_fill (curClass, meth, sel);
2204 _cache_fill (cls, meth, sel);
2208 methodPC = meth->method_imp;
2212 trace(0xb305, (int)methodPC, 0, 0);
2215 trace(0xb306, (int)methodPC, 0, 0);
2217 if (methodPC == NULL)
2219 // Class and superclasses do not respond -- use forwarding
2220 _cache_addForwardEntry(cls, sel);
2221 methodPC = &_objc_msgForward;
2224 trace(0xb30f, (int)methodPC, 0, 0);
2230 /***********************************************************************
2234 **********************************************************************/
2235 static int SubtypeUntil (const char * type,
2239 const char * head = type;
2244 if (!*type || (!level && (*type == end)))
2245 return (int)(type - head);
2249 case ']': case '}': case ')': level--; break;
2250 case '[': case '{': case '(': level += 1; break;
2256 _objc_fatal ("Object: SubtypeUntil: end of type encountered prematurely\n");
2260 /***********************************************************************
2262 **********************************************************************/
2263 static const char * SkipFirstType (const char * type)
2269 case 'O': /* bycopy */
2272 case 'N': /* inout */
2273 case 'r': /* const */
2274 case 'V': /* oneway */
2275 case '^': /* pointers */
2280 while ((*type >= '0') && (*type <= '9'))
2282 return type + SubtypeUntil (type, ']') + 1;
2286 return type + SubtypeUntil (type, '}') + 1;
2290 return type + SubtypeUntil (type, ')') + 1;
2299 /***********************************************************************
2300 * method_getNumberOfArguments.
2301 **********************************************************************/
2302 unsigned method_getNumberOfArguments (Method method)
2304 const char * typedesc;
2307 // First, skip the return type
2308 typedesc = method->method_types;
2309 typedesc = SkipFirstType (typedesc);
2311 // Next, skip stack size
2312 while ((*typedesc >= '0') && (*typedesc <= '9'))
2315 // Now, we have the arguments - count how many
2319 // Traverse argument type
2320 typedesc = SkipFirstType (typedesc);
2322 // Skip GNU runtime's register parameter hint
2323 if (*typedesc == '+') typedesc++;
2325 // Traverse (possibly negative) argument offset
2326 if (*typedesc == '-')
2328 while ((*typedesc >= '0') && (*typedesc <= '9'))
2331 // Made it past an argument
2338 /***********************************************************************
2339 * method_getSizeOfArguments.
2340 **********************************************************************/
2342 unsigned method_getSizeOfArguments (Method method)
2344 const char * typedesc;
2345 unsigned stack_size;
2346 #if defined(__ppc__) || defined(ppc)
2347 unsigned trueBaseOffset;
2348 unsigned foundBaseOffset;
2351 // Get our starting points
2353 typedesc = method->method_types;
2355 // Skip the return type
2356 #if defined (__ppc__) || defined(ppc)
2357 // Struct returns cause the parameters to be bumped
2358 // by a register, so the offset to the receiver is
2359 // 4 instead of the normal 0.
2360 trueBaseOffset = (*typedesc == '{') ? 4 : 0;
2362 typedesc = SkipFirstType (typedesc);
2364 // Convert ASCII number string to integer
2365 while ((*typedesc >= '0') && (*typedesc <= '9'))
2366 stack_size = (stack_size * 10) + (*typedesc++ - '0');
2367 #if defined (__ppc__) || defined(ppc)
2368 // NOTE: This is a temporary measure pending a compiler fix.
2369 // Work around PowerPC compiler bug wherein the method argument
2370 // string contains an incorrect value for the "stack size."
2371 // Generally, the size is reported 4 bytes too small, so we apply
2372 // that fudge factor. Unfortunately, there is at least one case
2373 // where the error is something other than -4: when the last
2374 // parameter is a double, the reported stack is much too high
2375 // (about 32 bytes). We do not attempt to detect that case.
2376 // The result of returning a too-high value is that objc_msgSendv
2377 // can bus error if the destination of the marg_list copying
2378 // butts up against excluded memory.
2379 // This fix disables itself when it sees a correctly built
2380 // type string (i.e. the offset for the Id is correct). This
2381 // keeps us out of lockstep with the compiler.
2383 // skip the '@' marking the Id field
2384 typedesc = SkipFirstType (typedesc);
2386 // Skip GNU runtime's register parameter hint
2387 if (*typedesc == '+') typedesc++;
2389 // pick up the offset for the Id field
2390 foundBaseOffset = 0;
2391 while ((*typedesc >= '0') && (*typedesc <= '9'))
2392 foundBaseOffset = (foundBaseOffset * 10) + (*typedesc++ - '0');
2394 // add fudge factor iff the Id field offset was wrong
2395 if (foundBaseOffset != trueBaseOffset)
2403 // XXX Getting the size of a type is done all over the place
2404 // (Here, Foundation, remote project)! - Should unify
2406 unsigned int getSizeOfType (const char * type, unsigned int * alignPtr);
2408 unsigned method_getSizeOfArguments (Method method)
2415 unsigned stack_size;
2418 nargs = method_getNumberOfArguments (method);
2419 stack_size = (*method->method_types == '{') ? sizeof(void *) : 0;
2421 for (index = 0; index < nargs; index += 1)
2423 (void) method_getArgumentInfo (method, index, &type, &offset);
2424 size = getSizeOfType (type, &align);
2425 stack_size += ((size + 7) & ~7);
2432 /***********************************************************************
2433 * method_getArgumentInfo.
2434 **********************************************************************/
2435 unsigned method_getArgumentInfo (Method method,
2440 const char * typedesc = method->method_types;
2442 unsigned self_offset = 0;
2443 BOOL offset_is_negative = NO;
2445 // First, skip the return type
2446 typedesc = SkipFirstType (typedesc);
2448 // Next, skip stack size
2449 while ((*typedesc >= '0') && (*typedesc <= '9'))
2452 // Now, we have the arguments - position typedesc to the appropriate argument
2453 while (*typedesc && nargs != arg)
2456 // Skip argument type
2457 typedesc = SkipFirstType (typedesc);
2461 // Skip GNU runtime's register parameter hint
2462 if (*typedesc == '+') typedesc++;
2464 // Skip negative sign in offset
2465 if (*typedesc == '-')
2467 offset_is_negative = YES;
2471 offset_is_negative = NO;
2473 while ((*typedesc >= '0') && (*typedesc <= '9'))
2474 self_offset = self_offset * 10 + (*typedesc++ - '0');
2475 if (offset_is_negative)
2476 self_offset = -(self_offset);
2482 // Skip GNU runtime's register parameter hint
2483 if (*typedesc == '+') typedesc++;
2485 // Skip (possibly negative) argument offset
2486 if (*typedesc == '-')
2488 while ((*typedesc >= '0') && (*typedesc <= '9'))
2497 unsigned arg_offset = 0;
2500 typedesc = SkipFirstType (typedesc);
2505 *offset = -sizeof(id);
2513 // Skip GNU register parameter hint
2514 if (*typedesc == '+') typedesc++;
2516 // Pick up (possibly negative) argument offset
2517 if (*typedesc == '-')
2519 offset_is_negative = YES;
2523 offset_is_negative = NO;
2525 while ((*typedesc >= '0') && (*typedesc <= '9'))
2526 arg_offset = arg_offset * 10 + (*typedesc++ - '0');
2527 if (offset_is_negative)
2528 arg_offset = - arg_offset;
2531 // For stacks which grow up, since margs points
2532 // to the top of the stack or the END of the args,
2533 // the first offset is at -sizeof(id) rather than 0.
2534 self_offset += sizeof(id);
2536 *offset = arg_offset - self_offset;
2550 /***********************************************************************
2551 * _objc_create_zone.
2552 **********************************************************************/
2554 void * _objc_create_zone (void)
2556 static void *_objc_z = (void *)0xffffffff;
2557 if ( _objc_z == (void *)0xffffffff ) {
2558 char *s = getenv("OBJC_USE_OBJC_ZONE");
2560 if ( (*s == '1') || (*s == 'y') || (*s == 'Y') ) {
2561 _objc_z = malloc_create_zone(vm_page_size, 0);
2562 malloc_set_zone_name(_objc_z, "ObjC");
2565 if ( _objc_z == (void *)0xffffffff ) {
2566 _objc_z = malloc_default_zone();
2572 /***********************************************************************
2574 **********************************************************************/
2576 static unsigned long _get_pc_for_thread (mach_port_t thread)
2579 struct hp_pa_frame_thread_state state;
2580 unsigned int count = HPPA_FRAME_THREAD_STATE_COUNT;
2581 thread_get_state (thread, HPPA_FRAME_THREAD_STATE, (thread_state_t)&state, &count);
2582 return state.ts_pcoq_front;
2584 #elif defined(sparc)
2586 struct sparc_thread_state_regs state;
2587 unsigned int count = SPARC_THREAD_STATE_REGS_COUNT;
2588 thread_get_state (thread, SPARC_THREAD_STATE_REGS, (thread_state_t)&state, &count);
2589 return state.regs.r_pc;
2591 #elif defined(__i386__) || defined(i386)
2593 i386_thread_state_t state;
2594 unsigned int count = i386_THREAD_STATE_COUNT;
2595 thread_get_state (thread, i386_THREAD_STATE, (thread_state_t)&state, &count);
2600 struct m68k_thread_state_regs state;
2601 unsigned int count = M68K_THREAD_STATE_REGS_COUNT;
2602 thread_get_state (thread, M68K_THREAD_STATE_REGS, (thread_state_t)&state, &count);
2605 #elif defined(__ppc__) || defined(ppc)
2607 struct ppc_thread_state state;
2608 unsigned int count = PPC_THREAD_STATE_COUNT;
2609 thread_get_state (thread, PPC_THREAD_STATE, (thread_state_t)&state, &count);
2614 #error _get_pc_for_thread () not implemented for this architecture
2618 /***********************************************************************
2619 * _collecting_in_critical.
2620 * Returns TRUE if some thread is currently executing a cache-reading
2621 * function. Collection of cache garbage is not allowed when a cache-
2622 * reading function is in progress because it might still be using
2623 * the garbage memory.
2624 **********************************************************************/
2625 OBJC_EXPORT unsigned long objc_entryPoints[];
2626 OBJC_EXPORT unsigned long objc_exitPoints[];
2628 static int _collecting_in_critical (void)
2630 thread_act_port_array_t threads;
2636 mach_port_t mythread = pthread_mach_thread_np(pthread_self());
2638 // Get a list of all the threads in the current task
2639 ret = task_threads (mach_task_self (), &threads, &number);
2640 if (ret != KERN_SUCCESS)
2642 _objc_inform ("task_thread failed (result %d)\n", ret);
2646 // Check whether any thread is in the cache lookup code
2648 for (count = 0; count < number; count++)
2653 // Don't bother checking ourselves
2654 if (threads[count] == mythread)
2657 // Find out where thread is executing
2658 pc = _get_pc_for_thread (threads[count]);
2660 // Check whether it is in the cache lookup code
2661 for (region = 0; objc_entryPoints[region] != 0; region++)
2663 if ((pc >= objc_entryPoints[region]) &&
2664 (pc <= objc_exitPoints[region]))
2673 // Deallocate the port rights for the threads
2674 for (count = 0; count < number; count++) {
2675 mach_port_deallocate(mach_task_self (), threads[count]);
2678 // Deallocate the thread list
2679 vm_deallocate (mach_task_self (), (vm_address_t) threads, sizeof(threads) * number);
2681 // Return our finding
2685 /***********************************************************************
2686 * _garbage_make_room. Ensure that there is enough room for at least
2687 * one more ref in the garbage.
2688 **********************************************************************/
2690 // amount of memory represented by all refs in the garbage
2691 static int garbage_byte_size = 0;
2693 // do not empty the garbage until garbage_byte_size gets at least this big
2694 static int garbage_threshold = 1024;
2696 // table of refs to free
2697 static void **garbage_refs = 0;
2699 // current number of refs in garbage_refs
2700 static int garbage_count = 0;
2702 // capacity of current garbage_refs
2703 static int garbage_max = 0;
2705 // capacity of initial garbage_refs
2707 INIT_GARBAGE_COUNT = 128
2710 static void _garbage_make_room (void)
2712 static int first = 1;
2713 volatile void * tempGarbage;
2715 // Create the collection table the first time it is needed
2719 garbage_refs = malloc_zone_malloc (_objc_create_zone(),
2720 INIT_GARBAGE_COUNT * sizeof(void *));
2721 garbage_max = INIT_GARBAGE_COUNT;
2724 // Double the table if it is full
2725 else if (garbage_count == garbage_max)
2727 tempGarbage = malloc_zone_realloc ((void *) _objc_create_zone(),
2728 (void *) garbage_refs,
2729 (size_t) garbage_max * 2 * sizeof(void *));
2730 garbage_refs = (void **) tempGarbage;
2735 /***********************************************************************
2736 * _cache_collect_free. Add the specified malloc'd memory to the list
2737 * of them to free at some later point.
2738 * Cache locks: cacheUpdateLock must be held by the caller.
2739 **********************************************************************/
2740 static void _cache_collect_free (void * data,
2743 static char *report_garbage = (char *)0xffffffff;
2745 if ((char *)0xffffffff == report_garbage) {
2746 // Check whether to log our activity
2747 report_garbage = getenv ("OBJC_REPORT_GARBAGE");
2750 // Insert new element in garbage list
2751 // Note that we do this even if we end up free'ing everything
2752 _garbage_make_room ();
2753 garbage_byte_size += malloc_size (data);
2754 garbage_refs[garbage_count++] = data;
2757 if (tryCollect && report_garbage)
2758 _objc_inform ("total of %d bytes of garbage ...", garbage_byte_size);
2760 // Done if caller says not to empty or the garbage is not full
2761 if (!tryCollect || (garbage_byte_size < garbage_threshold))
2763 if (tryCollect && report_garbage)
2764 _objc_inform ("couldn't collect cache garbage: below threshold\n");
2769 // tryCollect is guaranteed to be true after this point
2771 // Synchronize garbage collection with objc_msgSend and other cache readers
2772 if (!_collecting_in_critical ()) {
2773 // No cache readers in progress - garbage is now deletable
2777 _objc_inform ("collecting!\n");
2779 // Dispose all refs now in the garbage
2780 while (garbage_count)
2781 free (garbage_refs[--garbage_count]);
2783 // Clear the total size indicator
2784 garbage_byte_size = 0;
2787 // objc_msgSend (or other cache reader) is currently looking in the
2788 // cache and might still be using some garbage.
2789 if (report_garbage) {
2790 _objc_inform ("couldn't collect cache garbage: objc_msgSend in progress\n");
2796 /***********************************************************************
2798 **********************************************************************/
2799 static void _cache_print (Cache cache)
2804 count = cache->mask + 1;
2805 for (index = 0; index < count; index += 1)
2806 if (CACHE_BUCKET_VALID(cache->buckets[index]))
2808 if (CACHE_BUCKET_IMP(cache->buckets[index]) == &_objc_msgForward)
2809 printf ("does not recognize: \n");
2810 printf ("%s\n", (const char *) CACHE_BUCKET_NAME(cache->buckets[index]));
2814 /***********************************************************************
2815 * _class_printMethodCaches.
2816 **********************************************************************/
2817 void _class_printMethodCaches (Class cls)
2819 if (((struct objc_class *)cls)->cache == &emptyCache)
2820 printf ("no instance-method cache for class %s\n", ((struct objc_class *)cls)->name);
2824 printf ("instance-method cache for class %s:\n", ((struct objc_class *)cls)->name);
2825 _cache_print (((struct objc_class *)cls)->cache);
2828 if (((struct objc_class * )((struct objc_class * )cls)->isa)->cache == &emptyCache)
2829 printf ("no class-method cache for class %s\n", ((struct objc_class *)cls)->name);
2833 printf ("class-method cache for class %s:\n", ((struct objc_class *)cls)->name);
2834 _cache_print (((struct objc_class * )((struct objc_class * )cls)->isa)->cache);
2838 /***********************************************************************
2840 **********************************************************************/
2841 static unsigned int log2 (unsigned int x)
2852 /***********************************************************************
2853 * _class_printDuplicateCacheEntries.
2854 **********************************************************************/
2855 void _class_printDuplicateCacheEntries (BOOL detail)
2857 NXHashTable * class_hash;
2859 struct objc_class * cls;
2860 unsigned int duplicates;
2861 unsigned int index1;
2862 unsigned int index2;
2865 unsigned int isMeta;
2869 printf ("Checking for duplicate cache entries \n");
2871 // Outermost loop - iterate over all classes
2872 class_hash = objc_getClasses ();
2873 state = NXInitHashState (class_hash);
2875 while (NXNextHashState (class_hash, &state, (void **) &cls))
2877 // Control loop - do given class' cache, then its isa's cache
2878 for (isMeta = 0; isMeta <= 1; isMeta += 1)
2880 // Select cache of interest and make sure it exists
2881 cache = isMeta ? cls->isa->cache : ((struct objc_class *)cls)->cache;
2882 if (cache == &emptyCache)
2885 // Middle loop - check each entry in the given cache
2888 for (index1 = 0; index1 < count; index1 += 1)
2890 // Skip invalid entry
2891 if (!CACHE_BUCKET_VALID(cache->buckets[index1]))
2894 // Inner loop - check that given entry matches no later entry
2895 for (index2 = index1 + 1; index2 < count; index2 += 1)
2897 // Skip invalid entry
2898 if (!CACHE_BUCKET_VALID(cache->buckets[index2]))
2901 // Check for duplication by method name comparison
2902 if (strcmp ((char *) CACHE_BUCKET_NAME(cache->buckets[index1]),
2903 (char *) CACHE_BUCKET_NAME(cache->buckets[index2])) == 0)
2906 printf ("%s %s\n", ((struct objc_class *)cls)->name, (char *) CACHE_BUCKET_NAME(cache->buckets[index1]));
2916 printf ("duplicates = %d\n", duplicates);
2917 printf ("total cache fills = %d\n", totalCacheFills);
2920 /***********************************************************************
2922 **********************************************************************/
2923 static void PrintCacheHeader (void)
2925 #ifdef OBJC_INSTRUMENTED
2926 printf ("Cache Cache Slots Avg Max AvgS MaxS AvgS MaxS TotalD AvgD MaxD TotalD AvgD MaxD TotD AvgD MaxD\n");
2927 printf ("Size Count Used Used Used Hit Hit Miss Miss Hits Prbs Prbs Misses Prbs Prbs Flsh Flsh Flsh\n");
2928 printf ("----- ----- ----- ----- ---- ---- ---- ---- ---- ------- ---- ---- ------- ---- ---- ---- ---- ----\n");
2930 printf ("Cache Cache Slots Avg Max AvgS MaxS AvgS MaxS\n");
2931 printf ("Size Count Used Used Used Hit Hit Miss Miss\n");
2932 printf ("----- ----- ----- ----- ---- ---- ---- ---- ----\n");
2936 /***********************************************************************
2938 **********************************************************************/
2939 static void PrintCacheInfo (unsigned int cacheSize,
2940 unsigned int cacheCount,
2941 unsigned int slotsUsed,
2943 unsigned int maxUsed,
2945 unsigned int maxSHit,
2947 unsigned int maxSMiss
2948 #ifdef OBJC_INSTRUMENTED
2949 , unsigned int totDHits,
2951 unsigned int maxDHit,
2952 unsigned int totDMisses,
2954 unsigned int maxDMiss,
2955 unsigned int totDFlsh,
2957 unsigned int maxDFlsh
2961 #ifdef OBJC_INSTRUMENTED
2962 printf ("%5u %5u %5u %5.1f %4u %4.1f %4u %4.1f %4u %7u %4.1f %4u %7u %4.1f %4u %4u %4.1f %4u\n",
2964 printf ("%5u %5u %5u %5.1f %4u %4.1f %4u %4.1f %4u\n",
2966 cacheSize, cacheCount, slotsUsed, avgUsed, maxUsed, avgSHit, maxSHit, avgSMiss, maxSMiss
2967 #ifdef OBJC_INSTRUMENTED
2968 , totDHits, avgDHit, maxDHit, totDMisses, avgDMiss, maxDMiss, totDFlsh, avgDFlsh, maxDFlsh
2974 #ifdef OBJC_INSTRUMENTED
2975 /***********************************************************************
2976 * PrintCacheHistogram. Show the non-zero entries from the specified
2978 **********************************************************************/
2979 static void PrintCacheHistogram (char * title,
2980 unsigned int * firstEntry,
2981 unsigned int entryCount)
2984 unsigned int * thisEntry;
2986 printf ("%s\n", title);
2987 printf (" Probes Tally\n");
2988 printf (" ------ -----\n");
2989 for (index = 0, thisEntry = firstEntry;
2991 index += 1, thisEntry += 1)
2993 if (*thisEntry == 0)
2996 printf (" %6d %5d\n", index, *thisEntry);
3001 /***********************************************************************
3002 * _class_printMethodCacheStatistics.
3003 **********************************************************************/
3005 #define MAX_LOG2_SIZE 32
3006 #define MAX_CHAIN_SIZE 100
3008 void _class_printMethodCacheStatistics (void)
3010 unsigned int isMeta;
3012 NXHashTable * class_hash;
3014 struct objc_class * cls;
3015 unsigned int totalChain;
3016 unsigned int totalMissChain;
3017 unsigned int maxChain;
3018 unsigned int maxMissChain;
3019 unsigned int classCount;
3020 unsigned int negativeEntryCount;
3021 unsigned int cacheExpandCount;
3022 unsigned int cacheCountBySize[2][MAX_LOG2_SIZE] = {{0}};
3023 unsigned int totalEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};
3024 unsigned int maxEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};
3025 unsigned int totalChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3026 unsigned int totalMissChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3027 unsigned int totalMaxChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3028 unsigned int totalMaxMissChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3029 unsigned int maxChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3030 unsigned int maxMissChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3031 unsigned int chainCount[MAX_CHAIN_SIZE] = {0};
3032 unsigned int missChainCount[MAX_CHAIN_SIZE] = {0};
3033 #ifdef OBJC_INSTRUMENTED
3034 unsigned int hitCountBySize[2][MAX_LOG2_SIZE] = {{0}};
3035 unsigned int hitProbesBySize[2][MAX_LOG2_SIZE] = {{0}};
3036 unsigned int maxHitProbesBySize[2][MAX_LOG2_SIZE] = {{0}};
3037 unsigned int missCountBySize[2][MAX_LOG2_SIZE] = {{0}};
3038 unsigned int missProbesBySize[2][MAX_LOG2_SIZE] = {{0}};
3039 unsigned int maxMissProbesBySize[2][MAX_LOG2_SIZE] = {{0}};
3040 unsigned int flushCountBySize[2][MAX_LOG2_SIZE] = {{0}};
3041 unsigned int flushedEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};
3042 unsigned int maxFlushedEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};
3045 printf ("Printing cache statistics\n");
3047 // Outermost loop - iterate over all classes
3048 class_hash = objc_getClasses ();
3049 state = NXInitHashState (class_hash);
3051 negativeEntryCount = 0;
3052 cacheExpandCount = 0;
3053 while (NXNextHashState (class_hash, &state, (void **) &cls))
3058 // Control loop - do given class' cache, then its isa's cache
3059 for (isMeta = 0; isMeta <= 1; isMeta += 1)
3063 unsigned int log2Size;
3064 unsigned int entryCount;
3066 // Select cache of interest
3067 cache = isMeta ? cls->isa->cache : ((struct objc_class *)cls)->cache;
3069 // Ignore empty cache... should we?
3070 if (cache == &emptyCache)
3073 // Middle loop - do each entry in the given cache
3080 for (index = 0; index < mask + 1; index += 1)
3085 uarith_t methodChain;
3086 uarith_t methodMissChain;
3089 // If entry is invalid, the only item of
3090 // interest is that future insert hashes
3091 // to this entry can use it directly.
3092 buckets = cache->buckets;
3093 if (!CACHE_BUCKET_VALID(buckets[index]))
3095 missChainCount[0] += 1;
3099 method = buckets[index];
3101 // Tally valid entries
3104 // Tally "forward::" entries
3105 if (CACHE_BUCKET_IMP(method) == &_objc_msgForward)
3106 negativeEntryCount += 1;
3108 // Calculate search distance (chain length) for this method
3109 // The chain may wrap around to the beginning of the table.
3110 hash = CACHE_HASH(CACHE_BUCKET_NAME(method), mask);
3111 if (index >= hash) methodChain = index - hash;
3112 else methodChain = (mask+1) + index - hash;
3114 // Tally chains of this length
3115 if (methodChain < MAX_CHAIN_SIZE)
3116 chainCount[methodChain] += 1;
3118 // Keep sum of all chain lengths
3119 totalChain += methodChain;
3121 // Record greatest chain length
3122 if (methodChain > maxChain)
3123 maxChain = methodChain;
3125 // Calculate search distance for miss that hashes here
3127 while (CACHE_BUCKET_VALID(buckets[index2]))
3132 methodMissChain = ((index2 - index) & mask);
3134 // Tally miss chains of this length
3135 if (methodMissChain < MAX_CHAIN_SIZE)
3136 missChainCount[methodMissChain] += 1;
3138 // Keep sum of all miss chain lengths in this class
3139 totalMissChain += methodMissChain;
3141 // Record greatest miss chain length
3142 if (methodMissChain > maxMissChain)
3143 maxMissChain = methodMissChain;
3146 // Factor this cache into statistics about caches of the same
3147 // type and size (all caches are a power of two in size)
3148 log2Size = log2 (mask + 1);
3149 cacheCountBySize[isMeta][log2Size] += 1;
3150 totalEntriesBySize[isMeta][log2Size] += entryCount;
3151 if (entryCount > maxEntriesBySize[isMeta][log2Size])
3152 maxEntriesBySize[isMeta][log2Size] = entryCount;
3153 totalChainBySize[isMeta][log2Size] += totalChain;
3154 totalMissChainBySize[isMeta][log2Size] += totalMissChain;
3155 totalMaxChainBySize[isMeta][log2Size] += maxChain;
3156 totalMaxMissChainBySize[isMeta][log2Size] += maxMissChain;
3157 if (maxChain > maxChainBySize[isMeta][log2Size])
3158 maxChainBySize[isMeta][log2Size] = maxChain;
3159 if (maxMissChain > maxMissChainBySize[isMeta][log2Size])
3160 maxMissChainBySize[isMeta][log2Size] = maxMissChain;
3161 #ifdef OBJC_INSTRUMENTED
3163 CacheInstrumentation * cacheData;
3165 cacheData = CACHE_INSTRUMENTATION(cache);
3166 hitCountBySize[isMeta][log2Size] += cacheData->hitCount;
3167 hitProbesBySize[isMeta][log2Size] += cacheData->hitProbes;
3168 if (cacheData->maxHitProbes > maxHitProbesBySize[isMeta][log2Size])
3169 maxHitProbesBySize[isMeta][log2Size] = cacheData->maxHitProbes;
3170 missCountBySize[isMeta][log2Size] += cacheData->missCount;
3171 missProbesBySize[isMeta][log2Size] += cacheData->missProbes;
3172 if (cacheData->maxMissProbes > maxMissProbesBySize[isMeta][log2Size])
3173 maxMissProbesBySize[isMeta][log2Size] = cacheData->maxMissProbes;
3174 flushCountBySize[isMeta][log2Size] += cacheData->flushCount;
3175 flushedEntriesBySize[isMeta][log2Size] += cacheData->flushedEntries;
3176 if (cacheData->maxFlushedEntries > maxFlushedEntriesBySize[isMeta][log2Size])
3177 maxFlushedEntriesBySize[isMeta][log2Size] = cacheData->maxFlushedEntries;
3180 // Caches start with a power of two number of entries, and grow by doubling, so
3181 // we can calculate the number of times this cache has expanded
3183 cacheExpandCount += log2Size - INIT_META_CACHE_SIZE_LOG2;
3185 cacheExpandCount += log2Size - INIT_CACHE_SIZE_LOG2;
3191 unsigned int cacheCountByType[2] = {0};
3192 unsigned int totalCacheCount = 0;
3193 unsigned int totalEntries = 0;
3194 unsigned int maxEntries = 0;
3195 unsigned int totalSlots = 0;
3196 #ifdef OBJC_INSTRUMENTED
3197 unsigned int totalHitCount = 0;
3198 unsigned int totalHitProbes = 0;
3199 unsigned int maxHitProbes = 0;
3200 unsigned int totalMissCount = 0;
3201 unsigned int totalMissProbes = 0;
3202 unsigned int maxMissProbes = 0;
3203 unsigned int totalFlushCount = 0;
3204 unsigned int totalFlushedEntries = 0;
3205 unsigned int maxFlushedEntries = 0;
3213 // Sum information over all caches
3214 for (isMeta = 0; isMeta <= 1; isMeta += 1)
3216 for (index = 0; index < MAX_LOG2_SIZE; index += 1)
3218 cacheCountByType[isMeta] += cacheCountBySize[isMeta][index];
3219 totalEntries += totalEntriesBySize[isMeta][index];
3220 totalSlots += cacheCountBySize[isMeta][index] * (1 << index);
3221 totalChain += totalChainBySize[isMeta][index];
3222 if (maxEntriesBySize[isMeta][index] > maxEntries)
3223 maxEntries = maxEntriesBySize[isMeta][index];
3224 if (maxChainBySize[isMeta][index] > maxChain)
3225 maxChain = maxChainBySize[isMeta][index];
3226 totalMissChain += totalMissChainBySize[isMeta][index];
3227 if (maxMissChainBySize[isMeta][index] > maxMissChain)
3228 maxMissChain = maxMissChainBySize[isMeta][index];
3229 #ifdef OBJC_INSTRUMENTED
3230 totalHitCount += hitCountBySize[isMeta][index];
3231 totalHitProbes += hitProbesBySize[isMeta][index];
3232 if (maxHitProbesBySize[isMeta][index] > maxHitProbes)
3233 maxHitProbes = maxHitProbesBySize[isMeta][index];
3234 totalMissCount += missCountBySize[isMeta][index];
3235 totalMissProbes += missProbesBySize[isMeta][index];
3236 if (maxMissProbesBySize[isMeta][index] > maxMissProbes)
3237 maxMissProbes = maxMissProbesBySize[isMeta][index];
3238 totalFlushCount += flushCountBySize[isMeta][index];
3239 totalFlushedEntries += flushedEntriesBySize[isMeta][index];
3240 if (maxFlushedEntriesBySize[isMeta][index] > maxFlushedEntries)
3241 maxFlushedEntries = maxFlushedEntriesBySize[isMeta][index];
3245 totalCacheCount += cacheCountByType[isMeta];
3249 printf ("There are %u classes\n", classCount);
3251 for (isMeta = 0; isMeta <= 1; isMeta += 1)
3253 // Number of this type of class
3254 printf ("\nThere are %u %s-method caches, broken down by size (slot count):\n",
3255 cacheCountByType[isMeta],
3256 isMeta ? "class" : "instance");
3259 PrintCacheHeader ();
3261 // Keep format consistent even if there are caches of this kind
3262 if (cacheCountByType[isMeta] == 0)
3264 printf ("(none)\n");
3268 // Usage information by cache size
3269 for (index = 0; index < MAX_LOG2_SIZE; index += 1)
3271 unsigned int cacheCount;
3272 unsigned int cacheSlotCount;
3273 unsigned int cacheEntryCount;
3275 // Get number of caches of this type and size
3276 cacheCount = cacheCountBySize[isMeta][index];
3277 if (cacheCount == 0)
3280 // Get the cache slot count and the total number of valid entries
3281 cacheSlotCount = (1 << index);
3282 cacheEntryCount = totalEntriesBySize[isMeta][index];
3284 // Give the analysis
3285 PrintCacheInfo (cacheSlotCount,
3288 (float) cacheEntryCount / (float) cacheCount,
3289 maxEntriesBySize[isMeta][index],
3290 (float) totalChainBySize[isMeta][index] / (float) cacheEntryCount,
3291 maxChainBySize[isMeta][index],
3292 (float) totalMissChainBySize[isMeta][index] / (float) (cacheCount * cacheSlotCount),
3293 maxMissChainBySize[isMeta][index]
3294 #ifdef OBJC_INSTRUMENTED
3295 , hitCountBySize[isMeta][index],
3296 hitCountBySize[isMeta][index] ?
3297 (float) hitProbesBySize[isMeta][index] / (float) hitCountBySize[isMeta][index] : 0.0,
3298 maxHitProbesBySize[isMeta][index],
3299 missCountBySize[isMeta][index],
3300 missCountBySize[isMeta][index] ?
3301 (float) missProbesBySize[isMeta][index] / (float) missCountBySize[isMeta][index] : 0.0,
3302 maxMissProbesBySize[isMeta][index],
3303 flushCountBySize[isMeta][index],
3304 flushCountBySize[isMeta][index] ?
3305 (float) flushedEntriesBySize[isMeta][index] / (float) flushCountBySize[isMeta][index] : 0.0,
3306 maxFlushedEntriesBySize[isMeta][index]
3312 // Give overall numbers
3313 printf ("\nCumulative:\n");
3314 PrintCacheHeader ();
3315 PrintCacheInfo (totalSlots,
3318 (float) totalEntries / (float) totalCacheCount,
3320 (float) totalChain / (float) totalEntries,
3322 (float) totalMissChain / (float) totalSlots,
3324 #ifdef OBJC_INSTRUMENTED
3327 (float) totalHitProbes / (float) totalHitCount : 0.0,
3331 (float) totalMissProbes / (float) totalMissCount : 0.0,
3335 (float) totalFlushedEntries / (float) totalFlushCount : 0.0,
3340 printf ("\nNumber of \"forward::\" entries: %d\n", negativeEntryCount);
3341 printf ("Number of cache expansions: %d\n", cacheExpandCount);
3342 #ifdef OBJC_INSTRUMENTED
3343 printf ("flush_caches: total calls total visits average visits max visits total classes visits/class\n");
3344 printf (" ----------- ------------ -------------- ---------- ------------- -------------\n");
3345 printf (" linear %11u %12u %14.1f %10u %13u %12.2f\n",
3346 LinearFlushCachesCount,
3347 LinearFlushCachesVisitedCount,
3348 LinearFlushCachesCount ?
3349 (float) LinearFlushCachesVisitedCount / (float) LinearFlushCachesCount : 0.0,
3350 MaxLinearFlushCachesVisitedCount,
3351 LinearFlushCachesVisitedCount,
3353 printf (" nonlinear %11u %12u %14.1f %10u %13u %12.2f\n",
3354 NonlinearFlushCachesCount,
3355 NonlinearFlushCachesVisitedCount,
3356 NonlinearFlushCachesCount ?
3357 (float) NonlinearFlushCachesVisitedCount / (float) NonlinearFlushCachesCount : 0.0,
3358 MaxNonlinearFlushCachesVisitedCount,
3359 NonlinearFlushCachesClassCount,
3360 NonlinearFlushCachesClassCount ?
3361 (float) NonlinearFlushCachesVisitedCount / (float) NonlinearFlushCachesClassCount : 0.0);
3362 printf (" ideal %11u %12u %14.1f %10u %13u %12.2f\n",
3363 LinearFlushCachesCount + NonlinearFlushCachesCount,
3364 IdealFlushCachesCount,
3365 LinearFlushCachesCount + NonlinearFlushCachesCount ?
3366 (float) IdealFlushCachesCount / (float) (LinearFlushCachesCount + NonlinearFlushCachesCount) : 0.0,
3367 MaxIdealFlushCachesCount,
3368 LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount,
3369 LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount ?
3370 (float) IdealFlushCachesCount / (float) (LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount) : 0.0);
3372 PrintCacheHistogram ("\nCache hit histogram:", &CacheHitHistogram[0], CACHE_HISTOGRAM_SIZE);
3373 PrintCacheHistogram ("\nCache miss histogram:", &CacheMissHistogram[0], CACHE_HISTOGRAM_SIZE);
3377 printf ("\nLookup chains:");
3378 for (index = 0; index < MAX_CHAIN_SIZE; index += 1)
3380 if (chainCount[index] != 0)
3381 printf (" %u:%u", index, chainCount[index]);
3384 printf ("\nMiss chains:");
3385 for (index = 0; index < MAX_CHAIN_SIZE; index += 1)
3387 if (missChainCount[index] != 0)
3388 printf (" %u:%u", index, missChainCount[index]);
3391 printf ("\nTotal memory usage for cache data structures: %lu bytes\n",
3392 totalCacheCount * (sizeof(struct objc_cache) - sizeof(Method)) +
3393 totalSlots * sizeof(Method) +
3394 negativeEntryCount * sizeof(struct objc_method));
3399 /***********************************************************************
3401 **********************************************************************/
3402 void checkUniqueness (SEL s1,
3408 if (s1 && s2 && (strcmp ((const char *) s1, (const char *) s2) == 0))
3409 _objc_inform ("%p != %p but !strcmp (%s, %s)\n", s1, s2, (char *) s1, (char *) s2);