2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /***********************************************************************
27 * Copyright 1988-1997, Apple Computer, Inc.
29 **********************************************************************/
32 /***********************************************************************
33 * Method cache locking (GrP 2001-1-14)
35 * For speed, objc_msgSend does not acquire any locks when it reads
36 * method caches. Instead, all cache changes are performed so that any
37 * objc_msgSend running concurrently with the cache mutator will not
38 * crash or hang or get an incorrect result from the cache.
40 * When cache memory becomes unused (e.g. the old cache after cache
41 * expansion), it is not immediately freed, because a concurrent
42 * objc_msgSend could still be using it. Instead, the memory is
43 * disconnected from the data structures and placed on a garbage list.
44 * The memory is now only accessible to instances of objc_msgSend that
45 * were running when the memory was disconnected; any further calls to
46 * objc_msgSend will not see the garbage memory because the other data
47 * structures don't point to it anymore. The collecting_in_critical
48 * function checks the PC of all threads and returns FALSE when all threads
49 * are found to be outside objc_msgSend. This means any call to objc_msgSend
50 * that could have had access to the garbage has finished or moved past the
51 * cache lookup stage, so it is safe to free the memory.
53 * All functions that modify cache data or structures must acquire the
54 * cacheUpdateLock to prevent interference from concurrent modifications.
55 * The function that frees cache garbage must acquire the cacheUpdateLock
56 * and use collecting_in_critical() to flush out cache readers.
58 * Cache readers (PC-checked by collecting_in_critical())
63 * Cache writers (hold cacheUpdateLock while reading or writing; not PC-checked)
64 * _cache_fill (acquires lock)
65 * _cache_expand (only called from cache_fill)
66 * _cache_create (only called from cache_expand)
67 * bcopy (only called from instrumented cache_expand)
68 * flush_caches (acquires lock)
69 * _cache_flush (only called from cache_fill and flush_caches)
70 * _cache_collect_free (only called from cache_expand and cache_flush)
72 * UNPROTECTED cache readers (NOT thread-safe; used for debug info only)
74 * _class_printMethodCaches
75 * _class_printDuplicateCacheEntries
76 * _class_printMethodCacheStatistics
78 * _class_lookupMethodAndLoadCache is a special case. It may read a
79 * method triplet out of one cache and store it in another cache. This
80 * is unsafe if the method triplet is a forward:: entry, because the
81 * triplet itself could be freed unless _class_lookupMethodAndLoadCache
82 * were PC-checked or used a lock. Additionally, storing the method
83 * triplet in both caches would result in double-freeing if both caches
84 * were flushed or expanded. The solution is for _cache_getMethod to
85 * ignore all entries whose implementation is _objc_msgForward, so
86 * _class_lookupMethodAndLoadCache cannot look at a forward:: entry
87 * unsafely or place it in multiple caches.
88 ***********************************************************************/
90 /***********************************************************************
91 * Thread-safety during class initialization (GrP 2001-9-24)
93 * Initial state: CLS_INITIALIZING and CLS_INITIALIZED both clear.
94 * During initialization: CLS_INITIALIZING is set
95 * After initialization: CLS_INITIALIZING clear and CLS_INITIALIZED set.
96 * CLS_INITIALIZING and CLS_INITIALIZED are never set at the same time.
97 * CLS_INITIALIZED is never cleared once set.
99 * Only one thread is allowed to actually initialize a class and send
100 * +initialize. Enforced by allowing only one thread to set CLS_INITIALIZING.
102 * Additionally, threads trying to send messages to a class must wait for
103 * +initialize to finish. During initialization of a class, that class's
104 * method cache is kept empty. objc_msgSend will revert to
105 * class_lookupMethodAndLoadCache, which checks CLS_INITIALIZED before
106 * messaging. If CLS_INITIALIZED is clear but CLS_INITIALIZING is set,
107 * the thread must block, unless it is the thread that started
108 * initializing the class in the first place.
110 * Each thread keeps a list of classes it's initializing.
111 * The global classInitLock is used to synchronize changes to CLS_INITIALIZED
112 * and CLS_INITIALIZING: the transition to CLS_INITIALIZING must be
113 * an atomic test-and-set with respect to itself and the transition
114 * to CLS_INITIALIZED.
115 * The global classInitWaitCond is used to block threads waiting for an
116 * initialization to complete. The classInitLock synchronizes
117 * condition checking and the condition variable.
118 **********************************************************************/
120 /***********************************************************************
121 * +initialize deadlock case when a class is marked initializing while
122 * its superclass is initialized. Solved by completely initializing
123 * superclasses before beginning to initialize a class.
125 * OmniWeb class hierarchy:
130 * OWAddressEntry OWController
132 * OWConsoleController
134 * Thread 1 (evil testing thread):
135 * initialize OWAddressEntry
136 * super init OFObject
137 * super init OBObject
138 * [OBObject initialize] runs OBPostLoader, which inits lots of classes...
139 * initialize OWConsoleController
140 * super init OWController - wait for Thread 2 to finish OWController init
142 * Thread 2 (normal OmniWeb thread):
143 * initialize OWController
144 * super init OFObject - wait for Thread 1 to finish OFObject init
148 * Solution: fully initialize super classes before beginning to initialize
149 * a subclass. Then the initializing+initialized part of the class hierarchy
150 * will be a contiguous subtree starting at the root, so other threads
151 * can't jump into the middle between two initializing classes, and we won't
152 * get stuck while a superclass waits for its subclass which waits for the
154 **********************************************************************/
158 /***********************************************************************
160 **********************************************************************/
162 #import <mach/mach_interface.h>
163 #include <mach-o/ldsyms.h>
164 #include <mach-o/dyld.h>
166 #include <sys/types.h>
170 #include <sys/fcntl.h>
172 #import "objc-class.h"
174 #import <objc/Object.h>
175 #import <objc/objc-runtime.h>
176 #import "objc-private.h"
177 #import "hashtable2.h"
180 #include <sys/types.h>
182 #include <CoreFoundation/CFDictionary.h>
184 // Needed functions not in any header file
185 size_t malloc_size (const void * ptr);
187 // Needed kernel interface
188 #import <mach/mach.h>
189 #import <mach/thread_status.h>
192 /***********************************************************************
194 **********************************************************************/
196 // Define PRELOAD_SUPERCLASS_CACHES to cause method lookups to add the
197 // method the appropriate superclass caches, in addition to the normal
198 // encaching in the subclass where the method was messaged. Doing so
199 // will speed up messaging the same method from instances of the
200 // superclasses, but also uses up valuable cache space for a speculative
202 // See radar 2364264 about incorrectly propogating _objc_forward entries
203 // and double freeing them, first, before turning this on!
204 // (Radar 2364264 is now "inactive".)
205 // Double-freeing is also a potential problem when this is off. See
206 // note about _class_lookupMethodAndLoadCache in "Method cache locking".
207 //#define PRELOAD_SUPERCLASS_CACHES
209 /***********************************************************************
211 **********************************************************************/
213 #ifdef OBJC_INSTRUMENTED
215 CACHE_HISTOGRAM_SIZE = 512
218 unsigned int CacheHitHistogram [CACHE_HISTOGRAM_SIZE];
219 unsigned int CacheMissHistogram [CACHE_HISTOGRAM_SIZE];
222 /***********************************************************************
223 * Constants and macros internal to this module.
224 **********************************************************************/
226 // INIT_CACHE_SIZE and INIT_META_CACHE_SIZE must be a power of two
228 INIT_CACHE_SIZE_LOG2 = 2,
229 INIT_META_CACHE_SIZE_LOG2 = 2,
230 INIT_CACHE_SIZE = (1 << INIT_CACHE_SIZE_LOG2),
231 INIT_META_CACHE_SIZE = (1 << INIT_META_CACHE_SIZE_LOG2)
234 // Amount of space required for count hash table buckets, knowing that
235 // one entry is embedded in the cache structure itself
236 #define TABLE_SIZE(count) ((count - 1) * sizeof(Method))
238 // A sentinal (magic value) to report bad thread_get_state status
239 #define PC_SENTINAL 0
242 /***********************************************************************
243 * Types internal to this module.
244 **********************************************************************/
246 #ifdef OBJC_INSTRUMENTED
247 struct CacheInstrumentation
249 unsigned int hitCount; // cache lookup success tally
250 unsigned int hitProbes; // sum entries checked to hit
251 unsigned int maxHitProbes; // max entries checked to hit
252 unsigned int missCount; // cache lookup no-find tally
253 unsigned int missProbes; // sum entries checked to miss
254 unsigned int maxMissProbes; // max entries checked to miss
255 unsigned int flushCount; // cache flush tally
256 unsigned int flushedEntries; // sum cache entries flushed
257 unsigned int maxFlushedEntries; // max cache entries flushed
259 typedef struct CacheInstrumentation CacheInstrumentation;
261 // Cache instrumentation data follows table, so it is most compatible
262 #define CACHE_INSTRUMENTATION(cache) (CacheInstrumentation *) &cache->buckets[cache->mask + 1];
265 /***********************************************************************
266 * Function prototypes internal to this module.
267 **********************************************************************/
269 static Ivar class_getVariable (Class cls, const char * name);
270 static void flush_caches (Class cls, BOOL flush_meta);
271 static void addClassToOriginalClass (Class posingClass, Class originalClass);
272 static void _objc_addOrigClass (Class origClass);
273 static void _freedHandler (id self, SEL sel);
274 static void _nonexistentHandler (id self, SEL sel);
275 static void class_initialize (Class cls);
276 static Cache _cache_expand (Class cls);
277 static int LogObjCMessageSend (BOOL isClassMethod, const char * objectsClass, const char * implementingClass, SEL selector);
278 static BOOL _cache_fill (Class cls, Method smt, SEL sel);
279 static void _cache_addForwardEntry(Class cls, SEL sel);
280 static void _cache_flush (Class cls);
281 static int SubtypeUntil (const char * type, char end);
282 static const char * SkipFirstType (const char * type);
284 static unsigned long _get_pc_for_thread (mach_port_t thread);
285 static int _collecting_in_critical (void);
286 static void _garbage_make_room (void);
287 static void _cache_collect_free (void * data, BOOL tryCollect);
289 static void _cache_print (Cache cache);
290 static unsigned int log2 (unsigned int x);
291 static void PrintCacheHeader (void);
292 #ifdef OBJC_INSTRUMENTED
293 static void PrintCacheHistogram (char * title, unsigned int * firstEntry, unsigned int entryCount);
296 /***********************************************************************
297 * Static data internal to this module.
298 **********************************************************************/
300 // When _class_uncache is non-zero, cache growth copies the existing
301 // entries into the new (larger) cache. When this flag is zero, new
302 // (larger) caches start out empty.
303 static int _class_uncache = 1;
305 // When _class_slow_grow is non-zero, any given cache is actually grown
306 // only on the odd-numbered times it becomes full; on the even-numbered
307 // times, it is simply emptied and re-used. When this flag is zero,
308 // caches are grown every time.
309 static int _class_slow_grow = 1;
311 // Lock for cache access.
312 // Held when modifying a cache in place.
313 // Held when installing a new cache on a class.
314 // Held when adding to the cache garbage list.
315 // Held when disposing cache garbage.
316 // See "Method cache locking" above for notes about cache locking.
317 static OBJC_DECLARE_LOCK(cacheUpdateLock);
319 // classInitLock protects classInitWaitCond and examination and modification
320 // of CLS_INITIALIZED and CLS_INITIALIZING.
321 OBJC_DECLARE_LOCK(classInitLock);
322 // classInitWaitCond is signalled when any class is done initializing.
323 // Threads that are waiting for a class to finish initializing wait on this.
324 pthread_cond_t classInitWaitCond = PTHREAD_COND_INITIALIZER;
326 CFMutableDictionaryRef _classIMPTables = NULL;
328 // When traceDuplicates is non-zero, _cacheFill checks whether the method
329 // being encached is already there. The number of times it finds a match
330 // is tallied in cacheFillDuplicates. When traceDuplicatesVerbose is
331 // non-zero, each duplication is logged when found in this way.
332 static int traceDuplicates = 0;
333 static int traceDuplicatesVerbose = 0;
334 static int cacheFillDuplicates = 0;
336 #ifdef OBJC_INSTRUMENTED
338 static unsigned int LinearFlushCachesCount = 0;
339 static unsigned int LinearFlushCachesVisitedCount = 0;
340 static unsigned int MaxLinearFlushCachesVisitedCount = 0;
341 static unsigned int NonlinearFlushCachesCount = 0;
342 static unsigned int NonlinearFlushCachesClassCount = 0;
343 static unsigned int NonlinearFlushCachesVisitedCount = 0;
344 static unsigned int MaxNonlinearFlushCachesVisitedCount = 0;
345 static unsigned int IdealFlushCachesCount = 0;
346 static unsigned int MaxIdealFlushCachesCount = 0;
349 // Method call logging
350 typedef int (*ObjCLogProc)(BOOL, const char *, const char *, SEL);
352 static int totalCacheFills = 0;
353 static int objcMsgLogFD = (-1);
354 static ObjCLogProc objcMsgLogProc = &LogObjCMessageSend;
355 static int objcMsgLogEnabled = 0;
359 _errNoMem[] = "failed -- out of memory(%s, %u)",
360 _errAllocNil[] = "allocating nil object",
361 _errFreedObject[] = "message %s sent to freed object=0x%lx",
362 _errNonExistentObject[] = "message %s sent to non-existent object=0x%lx",
363 _errBadSel[] = "invalid selector %s",
364 _errNotSuper[] = "[%s poseAs:%s]: target not immediate superclass",
365 _errNewVars[] = "[%s poseAs:%s]: %s defines new instance variables";
367 /***********************************************************************
368 * Information about multi-thread support:
370 * Since we do not lock many operations which walk the superclass, method
371 * and ivar chains, these chains must remain intact once a class is published
372 * by inserting it into the class hashtable. All modifications must be
373 * atomic so that someone walking these chains will always geta valid
375 ***********************************************************************/
376 /***********************************************************************
377 * A static empty cache. All classes initially point at this cache.
378 * When the first message is sent it misses in the cache, and when
379 * the cache is grown it checks for this case and uses malloc rather
380 * than realloc. This avoids the need to check for NULL caches in the
382 ***********************************************************************/
384 const struct objc_cache emptyCache =
391 // Freed objects have their isa set to point to this dummy class.
392 // This avoids the need to check for Nil classes in the messenger.
393 static const struct objc_class freedObjectClass =
403 (Cache) &emptyCache, // cache
407 static const struct objc_class nonexistentObjectClass =
411 "NONEXISTENT(id)", // name
417 (Cache) &emptyCache, // cache
421 /***********************************************************************
422 * object_getClassName.
423 **********************************************************************/
424 const char * object_getClassName (id obj)
426 // Even nil objects have a class name, sort of
430 // Retrieve name from object's class
431 return ((struct objc_class *) obj->isa)->name;
434 /***********************************************************************
435 * object_getIndexedIvars.
436 **********************************************************************/
437 void * object_getIndexedIvars (id obj)
439 // ivars are tacked onto the end of the object
440 return ((char *) obj) + ((struct objc_class *) obj->isa)->instance_size;
444 /***********************************************************************
445 * _internal_class_createInstanceFromZone. Allocate an instance of the
446 * specified class with the specified number of bytes for indexed
447 * variables, in the specified zone. The isa field is set to the
448 * class, all other fields are zeroed.
449 **********************************************************************/
450 static id _internal_class_createInstanceFromZone (Class aClass,
455 register unsigned byteCount;
457 // Can't create something for nothing
460 __objc_error ((id) aClass, _errAllocNil, 0);
464 // Allocate and initialize
465 byteCount = ((struct objc_class *) aClass)->instance_size + nIvarBytes;
466 obj = (id) malloc_zone_calloc (z, 1, byteCount);
469 __objc_error ((id) aClass, _errNoMem, ((struct objc_class *) aClass)->name, nIvarBytes);
473 // Set the isa pointer
478 /***********************************************************************
479 * _internal_class_createInstance. Allocate an instance of the specified
480 * class with the specified number of bytes for indexed variables, in
481 * the default zone, using _internal_class_createInstanceFromZone.
482 **********************************************************************/
483 static id _internal_class_createInstance (Class aClass,
486 return _internal_class_createInstanceFromZone (aClass,
488 malloc_default_zone ());
491 id (*_poseAs)() = (id (*)())class_poseAs;
492 id (*_alloc)(Class, unsigned) = _internal_class_createInstance;
493 id (*_zoneAlloc)(Class, unsigned, void *) = _internal_class_createInstanceFromZone;
495 /***********************************************************************
496 * class_createInstanceFromZone. Allocate an instance of the specified
497 * class with the specified number of bytes for indexed variables, in
498 * the specified zone, using _zoneAlloc.
499 **********************************************************************/
500 id class_createInstanceFromZone (Class aClass,
504 // _zoneAlloc can be overridden, but is initially set to
505 // _internal_class_createInstanceFromZone
506 return (*_zoneAlloc) (aClass, nIvarBytes, z);
509 /***********************************************************************
510 * class_createInstance. Allocate an instance of the specified class with
511 * the specified number of bytes for indexed variables, using _alloc.
512 **********************************************************************/
513 id class_createInstance (Class aClass,
516 // _alloc can be overridden, but is initially set to
517 // _internal_class_createInstance
518 return (*_alloc) (aClass, nIvarBytes);
521 /***********************************************************************
522 * class_setVersion. Record the specified version with the class.
523 **********************************************************************/
524 void class_setVersion (Class aClass,
527 ((struct objc_class *) aClass)->version = version;
530 /***********************************************************************
531 * class_getVersion. Return the version recorded with the class.
532 **********************************************************************/
533 int class_getVersion (Class aClass)
535 return ((struct objc_class *) aClass)->version;
538 static void _addListIMPsToTable(CFMutableDictionaryRef table, struct objc_method_list *mlist, Class cls, void **iterator) {
540 struct objc_method_list *new_mlist;
542 /* Work from end of list so that categories override */
543 new_mlist = _class_inlinedNextMethodList(cls, iterator);
544 _addListIMPsToTable(table, new_mlist, cls, iterator);
545 for (i = 0; i < mlist->method_count; i++) {
546 CFDictionarySetValue(table, mlist->method_list[i].method_name, mlist->method_list[i].method_imp);
550 static void _addClassIMPsToTable(CFMutableDictionaryRef table, Class cls) {
551 struct objc_method_list *mlist;
553 #ifdef INCLUDE_SUPER_IMPS_IN_IMP_TABLE
554 if (cls->super_class) { /* Do superclass first so subclass overrides */
555 CFMutableDictionaryRef super_table = CFDictionaryGetValue(_classIMPTables, cls->super_class);
558 const void **keys, **values, *buffer1[128], *buffer2[128];
559 cnt = CFDictionaryGetCount(super_table);
560 keys = (cnt <= 128) ? buffer1 : CFAllocatorAllocate(NULL, cnt * sizeof(void *), 0);
561 values = (cnt <= 128) ? buffer2 : CFAllocatorAllocate(NULL, cnt * sizeof(void *), 0);
562 CFDictionaryGetKeysAndValues(super_table, keys, values);
564 CFDictionarySetValue(table, keys[cnt], values[cnt]);
566 if (keys != buffer1) CFAllocatorDeallocate(NULL, keys);
567 if (values != buffer2) CFAllocatorDeallocate(NULL, values);
569 _addClassIMPsToTable(table, cls->super_class);
573 mlist = _class_inlinedNextMethodList(cls, &iterator);
574 _addListIMPsToTable(table, mlist, cls, &iterator);
577 CFMutableDictionaryRef _getClassIMPTable(Class cls) {
578 CFMutableDictionaryRef table;
579 if (NULL == _classIMPTables) {
580 // maps Classes to mutable dictionaries
581 _classIMPTables = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
583 table = (CFMutableDictionaryRef)CFDictionaryGetValue(_classIMPTables, cls);
584 // IMP table maps SELs to IMPS
586 table = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
587 _addClassIMPsToTable(table, cls);
588 CFDictionaryAddValue(_classIMPTables, cls, table);
593 static inline Method _findNamedMethodInList(struct objc_method_list * mlist, const char *meth_name) {
595 if (!mlist) return NULL;
596 for (i = 0; i < mlist->method_count; i++) {
597 Method m = &mlist->method_list[i];
598 if (*((const char *)m->method_name) == *meth_name && 0 == strcmp((const char *)(m->method_name), meth_name)) {
605 /* These next three functions are the heart of ObjC method lookup. */
606 static inline Method _findMethodInList(struct objc_method_list * mlist, SEL sel) {
608 if (!mlist) return NULL;
609 for (i = 0; i < mlist->method_count; i++) {
610 Method m = &mlist->method_list[i];
611 if (m->method_name == sel) {
618 static inline Method _findMethodInClass(Class cls, SEL sel) {
619 struct objc_method_list *mlist;
621 while ((mlist = _class_inlinedNextMethodList(cls, &iterator))) {
622 Method m = _findMethodInList(mlist, sel);
628 static inline Method _getMethod(Class cls, SEL sel) {
629 for (; cls; cls = cls->super_class) {
630 Method m = _findMethodInClass(cls, sel);
637 /***********************************************************************
638 * class_getInstanceMethod. Return the instance method for the
639 * specified class and selector.
640 **********************************************************************/
641 Method class_getInstanceMethod (Class aClass,
644 // Need both a class and a selector
645 if (!aClass || !aSelector)
649 return _getMethod (aClass, aSelector);
652 /***********************************************************************
653 * class_getClassMethod. Return the class method for the specified
654 * class and selector.
655 **********************************************************************/
656 Method class_getClassMethod (Class aClass,
659 // Need both a class and a selector
660 if (!aClass || !aSelector)
663 // Go to the class or isa
664 return _getMethod (GETMETA(aClass), aSelector);
667 /***********************************************************************
668 * class_getVariable. Return the named instance variable.
669 **********************************************************************/
670 static Ivar class_getVariable (Class cls,
673 struct objc_class * thisCls;
675 // Outer loop - search the class and its superclasses
676 for (thisCls = cls; thisCls != Nil; thisCls = ((struct objc_class *) thisCls)->super_class)
681 // Skip class having no ivars
685 // Inner loop - search the given class
686 thisIvar = &thisCls->ivars->ivar_list[0];
687 for (index = 0; index < thisCls->ivars->ivar_count; index += 1)
689 // Check this ivar's name. Be careful because the
690 // compiler generates ivar entries with NULL ivar_name
691 // (e.g. for anonymous bit fields).
692 if ((thisIvar->ivar_name) &&
693 (strcmp (name, thisIvar->ivar_name) == 0))
705 /***********************************************************************
706 * class_getInstanceVariable. Return the named instance variable.
708 * Someday add class_getClassVariable ().
709 **********************************************************************/
710 Ivar class_getInstanceVariable (Class aClass,
713 // Must have a class and a name
714 if (!aClass || !name)
718 return class_getVariable (aClass, name);
721 /***********************************************************************
722 * flush_caches. Flush the instance and optionally class method caches
723 * of cls and all its subclasses.
725 * Specifying Nil for the class "all classes."
726 **********************************************************************/
727 static void flush_caches(Class cls, BOOL flush_meta)
729 int numClasses = 0, newNumClasses;
730 struct objc_class * * classes = NULL;
732 struct objc_class * clsObject;
733 #ifdef OBJC_INSTRUMENTED
734 unsigned int classesVisited;
735 unsigned int subclassCount;
738 // Do nothing if class has no cache
739 // This check is safe to do without any cache locks.
740 if (cls && !((struct objc_class *) cls)->cache)
743 newNumClasses = objc_getClassList((Class *)NULL, 0);
744 while (numClasses < newNumClasses) {
745 numClasses = newNumClasses;
746 classes = realloc(classes, sizeof(Class) * numClasses);
747 newNumClasses = objc_getClassList((Class *)classes, numClasses);
749 numClasses = newNumClasses;
751 OBJC_LOCK(&cacheUpdateLock);
753 // Handle nil and root instance class specially: flush all
754 // instance and class method caches. Nice that this
755 // loop is linear vs the N-squared loop just below.
756 if (!cls || !((struct objc_class *) cls)->super_class)
758 #ifdef OBJC_INSTRUMENTED
759 LinearFlushCachesCount += 1;
763 // Traverse all classes in the hash table
764 for (i = 0; i < numClasses; i++)
766 struct objc_class * metaClsObject;
767 #ifdef OBJC_INSTRUMENTED
770 clsObject = classes[i];
772 // Skip class that is known not to be a subclass of this root
773 // (the isa pointer of any meta class points to the meta class
775 // NOTE: When is an isa pointer of a hash tabled class ever nil?
776 metaClsObject = clsObject->isa;
777 if (cls && metaClsObject && cls->isa != metaClsObject->isa)
782 #ifdef OBJC_INSTRUMENTED
786 _cache_flush (clsObject);
787 if (flush_meta && metaClsObject != NULL) {
788 _cache_flush (metaClsObject);
791 #ifdef OBJC_INSTRUMENTED
792 LinearFlushCachesVisitedCount += classesVisited;
793 if (classesVisited > MaxLinearFlushCachesVisitedCount)
794 MaxLinearFlushCachesVisitedCount = classesVisited;
795 IdealFlushCachesCount += subclassCount;
796 if (subclassCount > MaxIdealFlushCachesCount)
797 MaxIdealFlushCachesCount = subclassCount;
800 OBJC_UNLOCK(&cacheUpdateLock);
805 // Outer loop - flush any cache that could now get a method from
806 // cls (i.e. the cache associated with cls and any of its subclasses).
807 #ifdef OBJC_INSTRUMENTED
808 NonlinearFlushCachesCount += 1;
812 for (i = 0; i < numClasses; i++)
814 struct objc_class * clsIter;
816 #ifdef OBJC_INSTRUMENTED
817 NonlinearFlushCachesClassCount += 1;
819 clsObject = classes[i];
821 // Inner loop - Process a given class
826 #ifdef OBJC_INSTRUMENTED
829 // Flush clsObject instance method cache if
830 // clsObject is a subclass of cls, or is cls itself
831 // Flush the class method cache if that was asked for
834 #ifdef OBJC_INSTRUMENTED
837 _cache_flush (clsObject);
839 _cache_flush (clsObject->isa);
845 // Flush clsObject class method cache if cls is
846 // the meta class of clsObject or of one
847 // of clsObject's superclasses
848 else if (clsIter->isa == cls)
850 #ifdef OBJC_INSTRUMENTED
853 _cache_flush (clsObject->isa);
857 // Move up superclass chain
858 else if (ISINITIALIZED(clsIter))
859 clsIter = clsIter->super_class;
861 // clsIter is not initialized, so its cache
862 // must be empty. This happens only when
863 // clsIter == clsObject, because
864 // superclasses are initialized before
865 // subclasses, and this loop traverses
866 // from sub- to super- classes.
871 #ifdef OBJC_INSTRUMENTED
872 NonlinearFlushCachesVisitedCount += classesVisited;
873 if (classesVisited > MaxNonlinearFlushCachesVisitedCount)
874 MaxNonlinearFlushCachesVisitedCount = classesVisited;
875 IdealFlushCachesCount += subclassCount;
876 if (subclassCount > MaxIdealFlushCachesCount)
877 MaxIdealFlushCachesCount = subclassCount;
880 OBJC_UNLOCK(&cacheUpdateLock);
884 /***********************************************************************
885 * _objc_flush_caches. Flush the caches of the specified class and any
886 * of its subclasses. If cls is a meta-class, only meta-class (i.e.
887 * class method) caches are flushed. If cls is an instance-class, both
888 * instance-class and meta-class caches are flushed.
889 **********************************************************************/
890 void _objc_flush_caches (Class cls)
892 flush_caches (cls, YES);
895 /***********************************************************************
896 * do_not_remove_this_dummy_function.
897 **********************************************************************/
898 void do_not_remove_this_dummy_function (void)
900 (void) class_nextMethodList (NULL, NULL);
903 /***********************************************************************
904 * class_nextMethodList.
907 * void * iterator = 0;
908 * while (class_nextMethodList (cls, &iterator)) {...}
909 **********************************************************************/
910 OBJC_EXPORT struct objc_method_list * class_nextMethodList (Class cls,
913 return _class_inlinedNextMethodList(cls, it);
916 /***********************************************************************
918 **********************************************************************/
921 (void) class_nextMethodList (Nil, NULL);
924 /***********************************************************************
927 * Formerly class_addInstanceMethods ()
928 **********************************************************************/
929 void class_addMethods (Class cls,
930 struct objc_method_list * meths)
932 // Insert atomically.
933 _objc_insertMethods (meths, &((struct objc_class *) cls)->methodLists);
935 // Must flush when dynamically adding methods. No need to flush
936 // all the class method caches. If cls is a meta class, though,
937 // this will still flush it and any of its sub-meta classes.
938 flush_caches (cls, NO);
941 /***********************************************************************
942 * class_addClassMethods.
944 * Obsolete (for binary compatibility only).
945 **********************************************************************/
946 void class_addClassMethods (Class cls,
947 struct objc_method_list * meths)
949 class_addMethods (((struct objc_class *) cls)->isa, meths);
952 /***********************************************************************
953 * class_removeMethods.
954 **********************************************************************/
955 void class_removeMethods (Class cls,
956 struct objc_method_list * meths)
958 // Remove atomically.
959 _objc_removeMethods (meths, &((struct objc_class *) cls)->methodLists);
961 // Must flush when dynamically removing methods. No need to flush
962 // all the class method caches. If cls is a meta class, though,
963 // this will still flush it and any of its sub-meta classes.
964 flush_caches (cls, NO);
967 /***********************************************************************
968 * addClassToOriginalClass. Add to a hash table of classes involved in
969 * a posing situation. We use this when we need to get to the "original"
970 * class for some particular name through the function objc_getOrigClass.
971 * For instance, the implementation of [super ...] will use this to be
972 * sure that it gets hold of the correct super class, so that no infinite
973 * loops will occur if the class it appears in is involved in posing.
975 * We use the classLock to guard the hash table.
977 * See tracker bug #51856.
978 **********************************************************************/
980 static NXMapTable * posed_class_hash = NULL;
981 static NXMapTable * posed_class_to_original_class_hash = NULL;
983 static void addClassToOriginalClass (Class posingClass,
986 // Install hash table when it is first needed
987 if (!posed_class_to_original_class_hash)
989 posed_class_to_original_class_hash =
990 NXCreateMapTableFromZone (NXPtrValueMapPrototype,
992 _objc_create_zone ());
995 // Add pose to hash table
996 NXMapInsert (posed_class_to_original_class_hash,
1001 /***********************************************************************
1002 * getOriginalClassForPosingClass.
1003 **********************************************************************/
1004 Class getOriginalClassForPosingClass (Class posingClass)
1006 return NXMapGet (posed_class_to_original_class_hash, posingClass);
1009 /***********************************************************************
1010 * objc_getOrigClass.
1011 **********************************************************************/
1012 Class objc_getOrigClass (const char * name)
1014 struct objc_class * ret;
1016 // Look for class among the posers
1018 OBJC_LOCK(&classLock);
1019 if (posed_class_hash)
1020 ret = (Class) NXMapGet (posed_class_hash, name);
1021 OBJC_UNLOCK(&classLock);
1025 // Not a poser. Do a normal lookup.
1026 ret = objc_getClass (name);
1028 _objc_inform ("class `%s' not linked into application", name);
1033 /***********************************************************************
1034 * _objc_addOrigClass. This function is only used from class_poseAs.
1035 * Registers the original class names, before they get obscured by
1036 * posing, so that [super ..] will work correctly from categories
1037 * in posing classes and in categories in classes being posed for.
1038 **********************************************************************/
1039 static void _objc_addOrigClass (Class origClass)
1041 OBJC_LOCK(&classLock);
1043 // Create the poser's hash table on first use
1044 if (!posed_class_hash)
1046 posed_class_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype,
1048 _objc_create_zone ());
1051 // Add the named class iff it is not already there (or collides?)
1052 if (NXMapGet (posed_class_hash, ((struct objc_class *)origClass)->name) == 0)
1053 NXMapInsert (posed_class_hash, ((struct objc_class *)origClass)->name, origClass);
1055 OBJC_UNLOCK(&classLock);
1058 /***********************************************************************
1061 * !!! class_poseAs () does not currently flush any caches.
1062 **********************************************************************/
1063 Class class_poseAs (Class imposter,
1066 struct objc_class * clsObject;
1067 char * imposterNamePtr;
1068 NXHashTable * class_hash;
1070 struct objc_class * copy;
1071 #ifdef OBJC_CLASS_REFS
1072 header_info * hInfo;
1075 // Trivial case is easy
1076 if (imposter == original)
1079 // Imposter must be an immediate subclass of the original
1080 if (((struct objc_class *)imposter)->super_class != original) {
1081 __objc_error(imposter, _errNotSuper, ((struct objc_class *)imposter)->name, ((struct objc_class *)original)->name);
1084 // Can't pose when you have instance variables (how could it work?)
1085 if (((struct objc_class *)imposter)->ivars) {
1086 __objc_error(imposter, _errNewVars, ((struct objc_class *)imposter)->name, ((struct objc_class *)original)->name, ((struct objc_class *)imposter)->name);
1089 // Build a string to use to replace the name of the original class.
1090 #define imposterNamePrefix "_%"
1091 imposterNamePtr = malloc_zone_malloc(_objc_create_zone(), strlen(((struct objc_class *)original)->name) + strlen(imposterNamePrefix) + 1);
1092 strcpy(imposterNamePtr, imposterNamePrefix);
1093 strcat(imposterNamePtr, ((struct objc_class *)original)->name);
1094 #undef imposterNamePrefix
1096 // We lock the class hashtable, so we are thread safe with respect to
1097 // calls to objc_getClass (). However, the class names are not
1098 // changed atomically, nor are all of the subclasses updated
1099 // atomically. I have ordered the operations so that you will
1100 // never crash, but you may get inconsistent results....
1102 // Register the original class so that [super ..] knows
1103 // exactly which classes are the "original" classes.
1104 _objc_addOrigClass (original);
1105 _objc_addOrigClass (imposter);
1107 OBJC_LOCK(&classLock);
1109 class_hash = objc_getClasses ();
1111 // Remove both the imposter and the original class.
1112 NXHashRemove (class_hash, imposter);
1113 NXHashRemove (class_hash, original);
1115 // Copy the imposter, so that the imposter can continue
1116 // its normal life in addition to changing the behavior of
1117 // the original. As a hack we don't bother to copy the metaclass.
1118 // For some reason we modify the original rather than the copy.
1119 copy = (*_zoneAlloc)(imposter->isa, sizeof(struct objc_class), _objc_create_zone());
1120 memmove(copy, imposter, sizeof(struct objc_class));
1122 NXHashInsert (class_hash, copy);
1123 addClassToOriginalClass (imposter, copy);
1125 // Mark the imposter as such
1126 CLS_SETINFO(((struct objc_class *)imposter), CLS_POSING);
1127 CLS_SETINFO(((struct objc_class *)imposter)->isa, CLS_POSING);
1129 // Change the name of the imposter to that of the original class.
1130 ((struct objc_class *)imposter)->name = ((struct objc_class *)original)->name;
1131 ((struct objc_class *)imposter)->isa->name = ((struct objc_class *)original)->isa->name;
1133 // Also copy the version field to avoid archiving problems.
1134 ((struct objc_class *)imposter)->version = ((struct objc_class *)original)->version;
1136 // Change all subclasses of the original to point to the imposter.
1137 state = NXInitHashState (class_hash);
1138 while (NXNextHashState (class_hash, &state, (void **) &clsObject))
1140 while ((clsObject) && (clsObject != imposter) &&
1141 (clsObject != copy))
1143 if (clsObject->super_class == original)
1145 clsObject->super_class = imposter;
1146 clsObject->isa->super_class = ((struct objc_class *)imposter)->isa;
1147 // We must flush caches here!
1151 clsObject = clsObject->super_class;
1155 #ifdef OBJC_CLASS_REFS
1156 // Replace the original with the imposter in all class refs
1157 // Major loop - process all headers
1158 for (hInfo = _objc_headerStart(); hInfo != NULL; hInfo = hInfo->next)
1161 unsigned int refCount;
1164 // Get refs associated with this header
1165 cls_refs = (Class *) _getObjcClassRefs ((headerType *) hInfo->mhdr, &refCount);
1166 if (!cls_refs || !refCount)
1169 // Minor loop - process this header's refs
1170 cls_refs = (Class *) ((unsigned long) cls_refs + hInfo->image_slide);
1171 for (index = 0; index < refCount; index += 1)
1173 if (cls_refs[index] == original)
1174 cls_refs[index] = imposter;
1177 #endif // OBJC_CLASS_REFS
1179 // Change the name of the original class.
1180 ((struct objc_class *)original)->name = imposterNamePtr + 1;
1181 ((struct objc_class *)original)->isa->name = imposterNamePtr;
1183 // Restore the imposter and the original class with their new names.
1184 NXHashInsert (class_hash, imposter);
1185 NXHashInsert (class_hash, original);
1187 OBJC_UNLOCK(&classLock);
1192 /***********************************************************************
1194 **********************************************************************/
1195 static void _freedHandler (id self,
1198 __objc_error (self, _errFreedObject, SELNAME(sel), self);
1201 /***********************************************************************
1202 * _nonexistentHandler.
1203 **********************************************************************/
1204 static void _nonexistentHandler (id self,
1207 __objc_error (self, _errNonExistentObject, SELNAME(sel), self);
1210 /***********************************************************************
1211 * _class_install_relationships. Fill in the class pointers of a class
1212 * that was loaded before some or all of the classes it needs to point to.
1213 * The deal here is that the class pointer fields have been usurped to
1214 * hold the string name of the pertinent class. Our job is to look up
1215 * the real thing based on those stored names.
1216 **********************************************************************/
1217 void _class_install_relationships (Class cls,
1220 struct objc_class * meta;
1221 struct objc_class * clstmp;
1223 // Get easy access to meta class structure
1224 meta = ((struct objc_class *)cls)->isa;
1226 // Set version in meta class strucure
1227 meta->version = version;
1229 // Install superclass based on stored name. No name iff
1230 // cls is a root class.
1231 if (((struct objc_class *)cls)->super_class)
1233 clstmp = objc_getClass ((const char *) ((struct objc_class *)cls)->super_class);
1236 _objc_inform("failed objc_getClass(%s) for %s->super_class", (const char *)((struct objc_class *)cls)->super_class, ((struct objc_class *)cls)->name);
1240 ((struct objc_class *)cls)->super_class = clstmp;
1243 // Install meta's isa based on stored name. Meta class isa
1244 // pointers always point to the meta class of the root class
1245 // (root meta class, too, it points to itself!).
1246 clstmp = objc_getClass ((const char *) meta->isa);
1249 _objc_inform("failed objc_getClass(%s) for %s->isa->isa", (const char *) meta->isa, ((struct objc_class *)cls)->name);
1253 meta->isa = clstmp->isa;
1255 // Install meta's superclass based on stored name. No name iff
1256 // cls is a root class.
1257 if (meta->super_class)
1259 // Locate instance class of super class
1260 clstmp = objc_getClass ((const char *) meta->super_class);
1263 _objc_inform("failed objc_getClass(%s) for %s->isa->super_class", (const char *)meta->super_class, ((struct objc_class *)cls)->name);
1267 // Store meta class of super class
1268 meta->super_class = clstmp->isa;
1271 // cls is root, so `tie' the (root) meta class down to its
1272 // instance class. This way, class methods can come from
1273 // the root instance class.
1275 ((struct objc_class *)meta)->super_class = cls;
1277 // Use common static empty cache instead of NULL
1278 if (((struct objc_class *)cls)->cache == NULL)
1279 ((struct objc_class *)cls)->cache = (Cache) &emptyCache;
1280 if (((struct objc_class *)meta)->cache == NULL)
1281 ((struct objc_class *)meta)->cache = (Cache) &emptyCache;
1286 _objc_fatal ("please link appropriate classes in your program");
1289 /***********************************************************************
1290 * class_respondsToMethod.
1292 * Called from -[Object respondsTo:] and +[Object instancesRespondTo:]
1293 **********************************************************************/
1294 BOOL class_respondsToMethod (Class cls,
1300 // No one responds to zero!
1304 imp = _cache_getImp(cls, sel);
1306 // Found method in cache.
1307 // If the cache entry is forward::, the class does not respond to sel.
1308 return (imp != &_objc_msgForward);
1311 // Handle cache miss
1312 meth = _getMethod(cls, sel);
1314 _cache_fill(cls, meth, sel);
1318 // Not implemented. Use _objc_msgForward.
1319 _cache_addForwardEntry(cls, sel);
1325 /***********************************************************************
1326 * class_lookupMethod.
1328 * Called from -[Object methodFor:] and +[Object instanceMethodFor:]
1329 **********************************************************************/
1330 // GrP is this used anymore?
1331 IMP class_lookupMethod (Class cls,
1336 // No one responds to zero!
1338 __objc_error(cls, _errBadSel, sel);
1341 imp = _cache_getImp(cls, sel);
1342 if (imp) return imp;
1344 // Handle cache miss
1345 return _class_lookupMethodAndLoadCache (cls, sel);
1348 /***********************************************************************
1349 * class_lookupMethodInMethodList.
1351 * Called from objc-load.m and _objc_callLoads ()
1352 **********************************************************************/
1353 IMP class_lookupMethodInMethodList (struct objc_method_list * mlist,
1356 Method m = _findMethodInList(mlist, sel);
1357 return (m ? m->method_imp : NULL);
1360 IMP class_lookupNamedMethodInMethodList(struct objc_method_list *mlist,
1361 const char *meth_name)
1363 Method m = meth_name ? _findNamedMethodInList(mlist, meth_name) : NULL;
1364 return (m ? m->method_imp : NULL);
1368 /***********************************************************************
1371 * Called from _cache_create() and cache_expand()
1372 **********************************************************************/
1373 static Cache _cache_malloc(int slotCount)
1378 // Allocate table (why not check for failure?)
1379 size = sizeof(struct objc_cache) + TABLE_SIZE(slotCount);
1380 #ifdef OBJC_INSTRUMENTED
1381 size += sizeof(CacheInstrumentation);
1383 new_cache = malloc_zone_calloc (_objc_create_zone(), size, 1);
1385 // [c|v]allocated memory is zeroed, so all buckets are invalidated
1386 // and occupied == 0 and all instrumentation is zero.
1388 new_cache->mask = slotCount - 1;
1394 /***********************************************************************
1397 * Called from _cache_expand().
1398 * Cache locks: cacheUpdateLock must be held by the caller.
1399 **********************************************************************/
1400 Cache _cache_create (Class cls)
1405 // Select appropriate size
1406 slotCount = (ISMETA(cls)) ? INIT_META_CACHE_SIZE : INIT_CACHE_SIZE;
1408 new_cache = _cache_malloc(slotCount);
1410 // Install the cache
1411 ((struct objc_class *)cls)->cache = new_cache;
1413 // Clear the cache flush flag so that we will not flush this cache
1414 // before expanding it for the first time.
1415 ((struct objc_class * )cls)->info &= ~(CLS_FLUSH_CACHE);
1417 // Clear the grow flag so that we will re-use the current storage,
1418 // rather than actually grow the cache, when expanding the cache
1419 // for the first time
1420 if (_class_slow_grow)
1421 ((struct objc_class * )cls)->info &= ~(CLS_GROW_CACHE);
1423 // Return our creation
1427 /***********************************************************************
1430 * Called from _cache_fill ()
1431 * Cache locks: cacheUpdateLock must be held by the caller.
1432 **********************************************************************/
1433 static Cache _cache_expand (Class cls)
1437 unsigned int slotCount;
1440 // First growth goes from emptyCache to a real one
1441 old_cache = ((struct objc_class *)cls)->cache;
1442 if (old_cache == &emptyCache)
1443 return _cache_create (cls);
1445 // iff _class_slow_grow, trade off actual cache growth with re-using
1446 // the current one, so that growth only happens every odd time
1447 if (_class_slow_grow)
1449 // CLS_GROW_CACHE controls every-other-time behavior. If it
1450 // is non-zero, let the cache grow this time, but clear the
1451 // flag so the cache is reused next time
1452 if ((((struct objc_class * )cls)->info & CLS_GROW_CACHE) != 0)
1453 ((struct objc_class * )cls)->info &= ~CLS_GROW_CACHE;
1455 // Reuse the current cache storage this time
1458 // Clear the valid-entry counter
1459 old_cache->occupied = 0;
1461 // Invalidate all the cache entries
1462 for (index = 0; index < old_cache->mask + 1; index += 1)
1464 // Remember what this entry was, so we can possibly
1465 // deallocate it after the bucket has been invalidated
1466 Method oldEntry = old_cache->buckets[index];
1467 // Skip invalid entry
1468 if (!CACHE_BUCKET_VALID(old_cache->buckets[index]))
1471 // Invalidate this entry
1472 CACHE_BUCKET_VALID(old_cache->buckets[index]) = NULL;
1474 // Deallocate "forward::" entry
1475 if (CACHE_BUCKET_IMP(oldEntry) == &_objc_msgForward)
1477 _cache_collect_free (oldEntry, NO);
1481 // Set the slow growth flag so the cache is next grown
1482 ((struct objc_class * )cls)->info |= CLS_GROW_CACHE;
1484 // Return the same old cache, freshly emptied
1490 // Double the cache size
1491 slotCount = (old_cache->mask + 1) << 1;
1493 new_cache = _cache_malloc(slotCount);
1495 #ifdef OBJC_INSTRUMENTED
1496 // Propagate the instrumentation data
1498 CacheInstrumentation * oldCacheData;
1499 CacheInstrumentation * newCacheData;
1501 oldCacheData = CACHE_INSTRUMENTATION(old_cache);
1502 newCacheData = CACHE_INSTRUMENTATION(new_cache);
1503 bcopy ((const char *)oldCacheData, (char *)newCacheData, sizeof(CacheInstrumentation));
1507 // iff _class_uncache, copy old cache entries into the new cache
1508 if (_class_uncache == 0)
1512 newMask = new_cache->mask;
1514 // Look at all entries in the old cache
1515 for (index = 0; index < old_cache->mask + 1; index += 1)
1519 // Skip invalid entry
1520 if (!CACHE_BUCKET_VALID(old_cache->buckets[index]))
1523 // Hash the old entry into the new table
1524 index2 = CACHE_HASH(CACHE_BUCKET_NAME(old_cache->buckets[index]),
1527 // Find an available spot, at or following the hashed spot;
1528 // Guaranteed to not infinite loop, because table has grown
1531 if (!CACHE_BUCKET_VALID(new_cache->buckets[index2]))
1533 new_cache->buckets[index2] = old_cache->buckets[index];
1541 // Account for the addition
1542 new_cache->occupied += 1;
1545 // Set the cache flush flag so that we will flush this cache
1546 // before expanding it again.
1547 ((struct objc_class * )cls)->info |= CLS_FLUSH_CACHE;
1550 // Deallocate "forward::" entries from the old cache
1553 for (index = 0; index < old_cache->mask + 1; index += 1)
1555 if (CACHE_BUCKET_VALID(old_cache->buckets[index]) &&
1556 CACHE_BUCKET_IMP(old_cache->buckets[index]) == &_objc_msgForward)
1558 _cache_collect_free (old_cache->buckets[index], NO);
1563 // Install new cache
1564 ((struct objc_class *)cls)->cache = new_cache;
1566 // Deallocate old cache, try freeing all the garbage
1567 _cache_collect_free (old_cache, YES);
1571 /***********************************************************************
1572 * instrumentObjcMessageSends/logObjcMessageSends.
1573 **********************************************************************/
1574 static int LogObjCMessageSend (BOOL isClassMethod,
1575 const char * objectsClass,
1576 const char * implementingClass,
1581 // Create/open the log file
1582 if (objcMsgLogFD == (-1))
1584 snprintf (buf, sizeof(buf), "/tmp/msgSends-%d", (int) getpid ());
1585 objcMsgLogFD = open (buf, O_WRONLY | O_CREAT, 0666);
1588 // Make the log entry
1589 snprintf(buf, sizeof(buf), "%c %s %s %s\n",
1590 isClassMethod ? '+' : '-',
1595 write (objcMsgLogFD, buf, strlen(buf));
1597 // Tell caller to not cache the method
1601 void instrumentObjcMessageSends (BOOL flag)
1603 int enabledValue = (flag) ? 1 : 0;
1606 if (objcMsgLogEnabled == enabledValue)
1609 // If enabling, flush all method caches so we get some traces
1611 flush_caches (Nil, YES);
1613 // Sync our log file
1614 if (objcMsgLogFD != (-1))
1615 fsync (objcMsgLogFD);
1617 objcMsgLogEnabled = enabledValue;
1620 void logObjcMessageSends (ObjCLogProc logProc)
1624 objcMsgLogProc = logProc;
1625 objcMsgLogEnabled = 1;
1629 objcMsgLogProc = logProc;
1630 objcMsgLogEnabled = 0;
1633 if (objcMsgLogFD != (-1))
1634 fsync (objcMsgLogFD);
1638 /***********************************************************************
1639 * _cache_fill. Add the specified method to the specified class' cache.
1640 * Returns NO if the cache entry wasn't added: cache was busy,
1641 * class is still being initialized, new entry is a duplicate.
1643 * Called only from _class_lookupMethodAndLoadCache and
1644 * class_respondsToMethod and _cache_addForwardEntry.
1646 * Cache locks: cacheUpdateLock must not be held.
1647 **********************************************************************/
1648 static BOOL _cache_fill(Class cls, Method smt, SEL sel)
1650 unsigned int newOccupied;
1655 // Never cache before +initialize is done
1656 if (!ISINITIALIZED(cls)) {
1660 // Keep tally of cache additions
1661 totalCacheFills += 1;
1663 OBJC_LOCK(&cacheUpdateLock);
1665 cache = ((struct objc_class *)cls)->cache;
1667 // Check for duplicate entries, if we're in the mode
1668 if (traceDuplicates)
1671 arith_t mask = cache->mask;
1672 buckets = cache->buckets;
1675 for (index2 = 0; index2 < mask + 1; index2 += 1)
1677 // Skip invalid or non-duplicate entry
1678 if ((!CACHE_BUCKET_VALID(buckets[index2])) ||
1679 (strcmp ((char *) CACHE_BUCKET_NAME(buckets[index2]), (char *) smt->method_name) != 0))
1682 // Tally duplication, but report iff wanted
1683 cacheFillDuplicates += 1;
1684 if (traceDuplicatesVerbose)
1686 _objc_inform ("Cache fill duplicate #%d: found %x adding %x: %s\n",
1687 cacheFillDuplicates,
1688 (unsigned int) CACHE_BUCKET_NAME(buckets[index2]),
1689 (unsigned int) smt->method_name,
1690 (char *) smt->method_name);
1695 // Make sure the entry wasn't added to the cache by some other thread
1696 // before we grabbed the cacheUpdateLock.
1697 // Don't use _cache_getMethod() because _cache_getMethod() doesn't
1698 // return forward:: entries.
1699 if (_cache_getImp(cls, sel)) {
1700 OBJC_UNLOCK(&cacheUpdateLock);
1701 return NO; // entry is already cached, didn't add new one
1704 // Use the cache as-is if it is less than 3/4 full
1705 newOccupied = cache->occupied + 1;
1706 if ((newOccupied * 4) <= (cache->mask + 1) * 3) {
1707 // Cache is less than 3/4 full.
1708 cache->occupied = newOccupied;
1710 // Cache is too full. Flush it or expand it.
1711 if ((((struct objc_class * )cls)->info & CLS_FLUSH_CACHE) != 0) {
1714 cache = _cache_expand (cls);
1717 // Account for the addition
1718 cache->occupied += 1;
1721 // Insert the new entry. This can be done by either:
1722 // (a) Scanning for the first unused spot. Easy!
1723 // (b) Opening up an unused spot by sliding existing
1724 // entries down by one. The benefit of this
1725 // extra work is that it puts the most recently
1726 // loaded entries closest to where the selector
1727 // hash starts the search.
1729 // The loop is a little more complicated because there
1730 // are two kinds of entries, so there have to be two ways
1732 buckets = cache->buckets;
1733 index = CACHE_HASH(sel, cache->mask);
1736 // Slide existing entries down by one
1739 // Copy current entry to a local
1740 saveMethod = buckets[index];
1742 // Copy previous entry (or new entry) to current slot
1743 buckets[index] = smt;
1745 // Done if current slot had been invalid
1746 if (saveMethod == NULL)
1749 // Prepare to copy saved value into next slot
1752 // Move on to next slot
1754 index &= cache->mask;
1757 OBJC_UNLOCK(&cacheUpdateLock);
1759 return YES; // successfully added new cache entry
1763 /***********************************************************************
1764 * _cache_addForwardEntry
1765 * Add a forward:: entry for the given selector to cls's method cache.
1766 * Does nothing if the cache addition fails for any reason.
1767 * Called from class_respondsToMethod and _class_lookupMethodAndLoadCache.
1768 * Cache locks: cacheUpdateLock must not be held.
1769 **********************************************************************/
1770 static void _cache_addForwardEntry(Class cls, SEL sel)
1774 smt = malloc_zone_malloc(_objc_create_zone(), sizeof(struct objc_method));
1775 smt->method_name = sel;
1776 smt->method_types = "";
1777 smt->method_imp = &_objc_msgForward;
1778 if (! _cache_fill(cls, smt, sel)) {
1779 // Entry not added to cache. Don't leak the method struct.
1780 malloc_zone_free(_objc_create_zone(), smt);
1785 /***********************************************************************
1786 * _cache_flush. Invalidate all valid entries in the given class' cache,
1787 * and clear the CLS_FLUSH_CACHE in the cls->info.
1789 * Called from flush_caches() and _cache_fill()
1790 * Cache locks: cacheUpdateLock must be held by the caller.
1791 **********************************************************************/
1792 static void _cache_flush (Class cls)
1797 // Locate cache. Ignore unused cache.
1798 cache = ((struct objc_class *)cls)->cache;
1799 if (cache == NULL || cache == &emptyCache)
1802 #ifdef OBJC_INSTRUMENTED
1804 CacheInstrumentation * cacheData;
1807 cacheData = CACHE_INSTRUMENTATION(cache);
1808 cacheData->flushCount += 1;
1809 cacheData->flushedEntries += cache->occupied;
1810 if (cache->occupied > cacheData->maxFlushedEntries)
1811 cacheData->maxFlushedEntries = cache->occupied;
1815 // Traverse the cache
1816 for (index = 0; index <= cache->mask; index += 1)
1818 // Remember what this entry was, so we can possibly
1819 // deallocate it after the bucket has been invalidated
1820 Method oldEntry = cache->buckets[index];
1822 // Invalidate this entry
1823 CACHE_BUCKET_VALID(cache->buckets[index]) = NULL;
1825 // Deallocate "forward::" entry
1826 if (oldEntry && oldEntry->method_imp == &_objc_msgForward)
1827 _cache_collect_free (oldEntry, NO);
1830 // Clear the valid-entry counter
1831 cache->occupied = 0;
1833 // Clear the cache flush flag so that we will not flush this cache
1834 // before expanding it again.
1835 ((struct objc_class * )cls)->info &= ~CLS_FLUSH_CACHE;
1838 /***********************************************************************
1839 * _objc_getFreedObjectClass. Return a pointer to the dummy freed
1840 * object class. Freed objects get their isa pointers replaced with
1841 * a pointer to the freedObjectClass, so that we can catch usages of
1843 **********************************************************************/
1844 Class _objc_getFreedObjectClass (void)
1846 return (Class) &freedObjectClass;
1849 /***********************************************************************
1850 * _objc_getNonexistentClass. Return a pointer to the dummy nonexistent
1851 * object class. This is used when, for example, mapping the class
1852 * refs for an image, and the class can not be found, so that we can
1853 * catch later uses of the non-existent class.
1854 **********************************************************************/
1855 Class _objc_getNonexistentClass (void)
1857 return (Class) &nonexistentObjectClass;
1861 /***********************************************************************
1862 * struct _objc_initializing_classes
1863 * Per-thread list of classes currently being initialized by that thread.
1864 * During initialization, that thread is allowed to send messages to that
1865 * class, but other threads have to wait.
1866 * The list is a simple array of metaclasses (the metaclass stores
1867 * the initialization state).
1868 **********************************************************************/
1869 typedef struct _objc_initializing_classes {
1870 int classesAllocated;
1871 struct objc_class** metaclasses;
1872 } _objc_initializing_classes;
1875 /***********************************************************************
1876 * _fetchInitializingClassList
1877 * Return the list of classes being initialized by this thread.
1878 * If create == YES, create the list when no classes are being initialized by this thread.
1879 * If create == NO, return NULL when no classes are being initialized by this thread.
1880 **********************************************************************/
1881 static _objc_initializing_classes *_fetchInitializingClassList(BOOL create)
1883 _objc_pthread_data *data;
1884 _objc_initializing_classes *list;
1885 struct objc_class **classes;
1887 data = pthread_getspecific(_objc_pthread_key);
1892 data = calloc(1, sizeof(_objc_pthread_data));
1893 pthread_setspecific(_objc_pthread_key, data);
1897 list = data->initializingClasses;
1902 list = calloc(1, sizeof(_objc_initializing_classes));
1903 data->initializingClasses = list;
1907 classes = list->metaclasses;
1908 if (classes == NULL) {
1909 // If _objc_initializing_classes exists, allocate metaclass array,
1910 // even if create == NO.
1911 // Allow 4 simultaneous class inits on this thread before realloc.
1912 list->classesAllocated = 4;
1913 classes = calloc(list->classesAllocated, sizeof(struct objc_class *));
1914 list->metaclasses = classes;
1920 /***********************************************************************
1921 * _destroyInitializingClassList
1922 * Deallocate memory used by the given initialization list.
1923 * Any part of the list may be NULL.
1924 * Called from _objc_pthread_destroyspecific().
1925 **********************************************************************/
1926 void _destroyInitializingClassList(_objc_initializing_classes *list)
1929 if (list->metaclasses != NULL) {
1930 free(list->metaclasses);
1937 /***********************************************************************
1938 * _thisThreadIsInitializingClass
1939 * Return TRUE if this thread is currently initializing the given class.
1940 **********************************************************************/
1941 static BOOL _thisThreadIsInitializingClass(struct objc_class *cls)
1945 _objc_initializing_classes *list = _fetchInitializingClassList(NO);
1948 for (i = 0; i < list->classesAllocated; i++) {
1949 if (cls == list->metaclasses[i]) return YES;
1953 // no list or not found in list
1958 /***********************************************************************
1959 * _setThisThreadIsInitializingClass
1960 * Record that this thread is currently initializing the given class.
1961 * This thread will be allowed to send messages to the class, but
1962 * other threads will have to wait.
1963 **********************************************************************/
1964 static void _setThisThreadIsInitializingClass(struct objc_class *cls)
1967 _objc_initializing_classes *list = _fetchInitializingClassList(YES);
1970 // paranoia: explicitly disallow duplicates
1971 for (i = 0; i < list->classesAllocated; i++) {
1972 if (cls == list->metaclasses[i]) {
1973 _objc_fatal("thread is already initializing this class!");
1974 return; // already the initializer
1978 for (i = 0; i < list->classesAllocated; i++) {
1979 if (0 == list->metaclasses[i]) {
1980 list->metaclasses[i] = cls;
1985 // class list is full - reallocate
1986 list->classesAllocated = list->classesAllocated * 2 + 1;
1987 list->metaclasses = realloc(list->metaclasses, list->classesAllocated * sizeof(struct objc_class *));
1988 // zero out the new entries
1989 list->metaclasses[i++] = cls;
1990 for ( ; i < list->classesAllocated; i++) {
1991 list->metaclasses[i] = NULL;
1996 /***********************************************************************
1997 * _setThisThreadIsNotInitializingClass
1998 * Record that this thread is no longer initializing the given class.
1999 **********************************************************************/
2000 static void _setThisThreadIsNotInitializingClass(struct objc_class *cls)
2004 _objc_initializing_classes *list = _fetchInitializingClassList(NO);
2007 for (i = 0; i < list->classesAllocated; i++) {
2008 if (cls == list->metaclasses[i]) {
2009 list->metaclasses[i] = NULL;
2015 // no list or not found in list
2016 _objc_fatal("thread is not initializing this class!");
2020 /***********************************************************************
2021 * class_initialize. Send the '+initialize' message on demand to any
2022 * uninitialized class. Force initialization of superclasses first.
2024 * Called only from _class_lookupMethodAndLoadCache (or itself).
2025 **********************************************************************/
2026 static void class_initialize(struct objc_class *cls)
2028 long *infoP = &GETMETA(cls)->info;
2029 BOOL reallyInitialize = NO;
2031 // Get the real class from the metaclass. The superclass chain
2032 // hangs off the real class only.
2034 if (strncmp(cls->name, "_%", 2) == 0) {
2035 // Posee's meta's name is smashed and isn't in the class_hash,
2036 // so objc_getClass doesn't work.
2037 char *baseName = strchr(cls->name, '%'); // get posee's real name
2038 cls = objc_getClass(baseName);
2040 cls = objc_getClass(cls->name);
2044 // Make sure super is done initializing BEFORE beginning to initialize cls.
2045 // See note about deadlock above.
2046 if (cls->super_class && !ISINITIALIZED(cls->super_class)) {
2047 class_initialize(cls->super_class);
2050 // Try to atomically set CLS_INITIALIZING.
2051 pthread_mutex_lock(&classInitLock);
2052 if (!ISINITIALIZED(cls) && !ISINITIALIZING(cls)) {
2053 *infoP |= CLS_INITIALIZING;
2054 reallyInitialize = YES;
2056 pthread_mutex_unlock(&classInitLock);
2058 if (reallyInitialize) {
2059 // We successfully set the CLS_INITIALIZING bit. Initialize the class.
2061 // Record that we're initializing this class so we can message it.
2062 _setThisThreadIsInitializingClass(cls);
2064 // bind the module in - if it came from a bundle or dynamic library
2065 _objc_bindClassIfNeeded(cls);
2067 // chain on the categories and bind them if necessary
2068 _objc_resolve_categories_for_class(cls);
2070 // Send the +initialize message.
2071 // Note that +initialize is sent to the superclass (again) if
2072 // this class doesn't implement +initialize. 2157218
2073 [(id)cls initialize];
2075 // Done initializing. Update the info bits and notify waiting threads.
2076 pthread_mutex_lock(&classInitLock);
2077 *infoP = (*infoP | CLS_INITIALIZED) & ~CLS_INITIALIZING;
2078 pthread_cond_broadcast(&classInitWaitCond);
2079 pthread_mutex_unlock(&classInitLock);
2080 _setThisThreadIsNotInitializingClass(cls);
2084 else if (ISINITIALIZING(cls)) {
2085 // We couldn't set INITIALIZING because INITIALIZING was already set.
2086 // If this thread set it earlier, continue normally.
2087 // If some other thread set it, block until initialize is done.
2088 // It's ok if INITIALIZING changes to INITIALIZED while we're here,
2089 // because we safely check for INITIALIZED inside the lock
2091 if (_thisThreadIsInitializingClass(cls)) {
2094 pthread_mutex_lock(&classInitLock);
2095 while (!ISINITIALIZED(cls)) {
2096 pthread_cond_wait(&classInitWaitCond, &classInitLock);
2098 pthread_mutex_unlock(&classInitLock);
2103 else if (ISINITIALIZED(cls)) {
2104 // Set CLS_INITIALIZING failed because someone else already
2105 // initialized the class. Continue normally.
2106 // NOTE this check must come AFTER the ISINITIALIZING case.
2107 // Otherwise: Another thread is initializing this class. ISINITIALIZED
2108 // is false. Skip this clause. Then the other thread finishes
2109 // initialization and sets INITIALIZING=no and INITIALIZED=yes.
2110 // Skip the ISINITIALIZING clause. Die horribly.
2115 // We shouldn't be here.
2116 _objc_fatal("thread-safe class init in objc runtime is buggy!");
2121 /***********************************************************************
2122 * _class_lookupMethodAndLoadCache.
2124 * Called only from objc_msgSend, objc_msgSendSuper and class_lookupMethod.
2125 **********************************************************************/
2126 IMP _class_lookupMethodAndLoadCache (Class cls,
2129 struct objc_class * curClass;
2131 IMP methodPC = NULL;
2133 trace(0xb300, 0, 0, 0);
2135 // Check for freed class
2136 if (cls == &freedObjectClass)
2137 return (IMP) _freedHandler;
2139 // Check for nonexistent class
2140 if (cls == &nonexistentObjectClass)
2141 return (IMP) _nonexistentHandler;
2143 trace(0xb301, 0, 0, 0);
2145 if (!ISINITIALIZED(cls)) {
2146 class_initialize ((struct objc_class *)cls);
2147 // If sel == initialize, class_initialize will send +initialize and
2148 // then the messenger will send +initialize again after this
2149 // procedure finishes. Of course, if this is not being called
2150 // from the messenger then it won't happen. 2778172
2153 trace(0xb302, 0, 0, 0);
2155 // Outer loop - search the caches and method lists of the
2156 // class and its super-classes
2157 for (curClass = cls; curClass; curClass = ((struct objc_class * )curClass)->super_class)
2159 #ifdef PRELOAD_SUPERCLASS_CACHES
2160 struct objc_class *curClass2;
2163 trace(0xb303, 0, 0, 0);
2165 // Beware of thread-unsafety and double-freeing of forward::
2166 // entries here! See note in "Method cache locking" above.
2167 // The upshot is that _cache_getMethod() will return NULL
2168 // instead of returning a forward:: entry.
2169 meth = _cache_getMethod(curClass, sel, &_objc_msgForward);
2171 // Found the method in this class or a superclass.
2172 // Cache the method in this class, unless we just found it in
2173 // this class's cache.
2174 if (curClass != cls) {
2175 #ifdef PRELOAD_SUPERCLASS_CACHES
2176 for (curClass2 = cls; curClass2 != curClass; curClass2 = curClass2->super_class)
2177 _cache_fill (curClass2, meth, sel);
2178 _cache_fill (curClass, meth, sel);
2180 _cache_fill (cls, meth, sel);
2184 methodPC = meth->method_imp;
2188 trace(0xb304, (int)methodPC, 0, 0);
2190 // Cache scan failed. Search method list.
2192 meth = _findMethodInClass(curClass, sel);
2194 // If logging is enabled, log the message send and let
2195 // the logger decide whether to encache the method.
2196 if ((objcMsgLogEnabled == 0) ||
2197 (objcMsgLogProc (CLS_GETINFO(((struct objc_class * )curClass),
2198 CLS_META) ? YES : NO,
2199 ((struct objc_class *)cls)->name,
2200 curClass->name, sel)))
2202 // Cache the method implementation
2203 #ifdef PRELOAD_SUPERCLASS_CACHES
2204 for (curClass2 = cls; curClass2 != curClass; curClass2 = curClass2->super_class)
2205 _cache_fill (curClass2, meth, sel);
2206 _cache_fill (curClass, meth, sel);
2208 _cache_fill (cls, meth, sel);
2212 methodPC = meth->method_imp;
2216 trace(0xb305, (int)methodPC, 0, 0);
2219 trace(0xb306, (int)methodPC, 0, 0);
2221 if (methodPC == NULL)
2223 // Class and superclasses do not respond -- use forwarding
2224 _cache_addForwardEntry(cls, sel);
2225 methodPC = &_objc_msgForward;
2228 trace(0xb30f, (int)methodPC, 0, 0);
2234 /***********************************************************************
2238 **********************************************************************/
2239 static int SubtypeUntil (const char * type,
2243 const char * head = type;
2248 if (!*type || (!level && (*type == end)))
2249 return (int)(type - head);
2253 case ']': case '}': case ')': level--; break;
2254 case '[': case '{': case '(': level += 1; break;
2260 _objc_fatal ("Object: SubtypeUntil: end of type encountered prematurely\n");
2264 /***********************************************************************
2266 **********************************************************************/
2267 static const char * SkipFirstType (const char * type)
2273 case 'O': /* bycopy */
2276 case 'N': /* inout */
2277 case 'r': /* const */
2278 case 'V': /* oneway */
2279 case '^': /* pointers */
2284 while ((*type >= '0') && (*type <= '9'))
2286 return type + SubtypeUntil (type, ']') + 1;
2290 return type + SubtypeUntil (type, '}') + 1;
2294 return type + SubtypeUntil (type, ')') + 1;
2303 /***********************************************************************
2304 * method_getNumberOfArguments.
2305 **********************************************************************/
2306 unsigned method_getNumberOfArguments (Method method)
2308 const char * typedesc;
2311 // First, skip the return type
2312 typedesc = method->method_types;
2313 typedesc = SkipFirstType (typedesc);
2315 // Next, skip stack size
2316 while ((*typedesc >= '0') && (*typedesc <= '9'))
2319 // Now, we have the arguments - count how many
2323 // Traverse argument type
2324 typedesc = SkipFirstType (typedesc);
2326 // Skip GNU runtime's register parameter hint
2327 if (*typedesc == '+') typedesc++;
2329 // Traverse (possibly negative) argument offset
2330 if (*typedesc == '-')
2332 while ((*typedesc >= '0') && (*typedesc <= '9'))
2335 // Made it past an argument
2342 /***********************************************************************
2343 * method_getSizeOfArguments.
2344 **********************************************************************/
2346 unsigned method_getSizeOfArguments (Method method)
2348 const char * typedesc;
2349 unsigned stack_size;
2350 #if defined(__ppc__) || defined(ppc)
2351 unsigned trueBaseOffset;
2352 unsigned foundBaseOffset;
2355 // Get our starting points
2357 typedesc = method->method_types;
2359 // Skip the return type
2360 #if defined (__ppc__) || defined(ppc)
2361 // Struct returns cause the parameters to be bumped
2362 // by a register, so the offset to the receiver is
2363 // 4 instead of the normal 0.
2364 trueBaseOffset = (*typedesc == '{') ? 4 : 0;
2366 typedesc = SkipFirstType (typedesc);
2368 // Convert ASCII number string to integer
2369 while ((*typedesc >= '0') && (*typedesc <= '9'))
2370 stack_size = (stack_size * 10) + (*typedesc++ - '0');
2371 #if defined (__ppc__) || defined(ppc)
2372 // NOTE: This is a temporary measure pending a compiler fix.
2373 // Work around PowerPC compiler bug wherein the method argument
2374 // string contains an incorrect value for the "stack size."
2375 // Generally, the size is reported 4 bytes too small, so we apply
2376 // that fudge factor. Unfortunately, there is at least one case
2377 // where the error is something other than -4: when the last
2378 // parameter is a double, the reported stack is much too high
2379 // (about 32 bytes). We do not attempt to detect that case.
2380 // The result of returning a too-high value is that objc_msgSendv
2381 // can bus error if the destination of the marg_list copying
2382 // butts up against excluded memory.
2383 // This fix disables itself when it sees a correctly built
2384 // type string (i.e. the offset for the Id is correct). This
2385 // keeps us out of lockstep with the compiler.
2387 // skip the '@' marking the Id field
2388 typedesc = SkipFirstType (typedesc);
2390 // Skip GNU runtime's register parameter hint
2391 if (*typedesc == '+') typedesc++;
2393 // pick up the offset for the Id field
2394 foundBaseOffset = 0;
2395 while ((*typedesc >= '0') && (*typedesc <= '9'))
2396 foundBaseOffset = (foundBaseOffset * 10) + (*typedesc++ - '0');
2398 // add fudge factor iff the Id field offset was wrong
2399 if (foundBaseOffset != trueBaseOffset)
2407 // XXX Getting the size of a type is done all over the place
2408 // (Here, Foundation, remote project)! - Should unify
2410 unsigned int getSizeOfType (const char * type, unsigned int * alignPtr);
2412 unsigned method_getSizeOfArguments (Method method)
2419 unsigned stack_size;
2422 nargs = method_getNumberOfArguments (method);
2423 stack_size = (*method->method_types == '{') ? sizeof(void *) : 0;
2425 for (index = 0; index < nargs; index += 1)
2427 (void) method_getArgumentInfo (method, index, &type, &offset);
2428 size = getSizeOfType (type, &align);
2429 stack_size += ((size + 7) & ~7);
2436 /***********************************************************************
2437 * method_getArgumentInfo.
2438 **********************************************************************/
2439 unsigned method_getArgumentInfo (Method method,
2444 const char * typedesc = method->method_types;
2446 unsigned self_offset = 0;
2447 BOOL offset_is_negative = NO;
2449 // First, skip the return type
2450 typedesc = SkipFirstType (typedesc);
2452 // Next, skip stack size
2453 while ((*typedesc >= '0') && (*typedesc <= '9'))
2456 // Now, we have the arguments - position typedesc to the appropriate argument
2457 while (*typedesc && nargs != arg)
2460 // Skip argument type
2461 typedesc = SkipFirstType (typedesc);
2465 // Skip GNU runtime's register parameter hint
2466 if (*typedesc == '+') typedesc++;
2468 // Skip negative sign in offset
2469 if (*typedesc == '-')
2471 offset_is_negative = YES;
2475 offset_is_negative = NO;
2477 while ((*typedesc >= '0') && (*typedesc <= '9'))
2478 self_offset = self_offset * 10 + (*typedesc++ - '0');
2479 if (offset_is_negative)
2480 self_offset = -(self_offset);
2486 // Skip GNU runtime's register parameter hint
2487 if (*typedesc == '+') typedesc++;
2489 // Skip (possibly negative) argument offset
2490 if (*typedesc == '-')
2492 while ((*typedesc >= '0') && (*typedesc <= '9'))
2501 unsigned arg_offset = 0;
2504 typedesc = SkipFirstType (typedesc);
2509 *offset = -sizeof(id);
2517 // Skip GNU register parameter hint
2518 if (*typedesc == '+') typedesc++;
2520 // Pick up (possibly negative) argument offset
2521 if (*typedesc == '-')
2523 offset_is_negative = YES;
2527 offset_is_negative = NO;
2529 while ((*typedesc >= '0') && (*typedesc <= '9'))
2530 arg_offset = arg_offset * 10 + (*typedesc++ - '0');
2531 if (offset_is_negative)
2532 arg_offset = - arg_offset;
2535 // For stacks which grow up, since margs points
2536 // to the top of the stack or the END of the args,
2537 // the first offset is at -sizeof(id) rather than 0.
2538 self_offset += sizeof(id);
2540 *offset = arg_offset - self_offset;
2554 /***********************************************************************
2555 * _objc_create_zone.
2556 **********************************************************************/
2558 void * _objc_create_zone (void)
2560 static void *_objc_z = (void *)0xffffffff;
2561 if ( _objc_z == (void *)0xffffffff ) {
2562 char *s = getenv("OBJC_USE_OBJC_ZONE");
2564 if ( (*s == '1') || (*s == 'y') || (*s == 'Y') ) {
2565 _objc_z = malloc_create_zone(vm_page_size, 0);
2566 malloc_set_zone_name(_objc_z, "ObjC");
2569 if ( _objc_z == (void *)0xffffffff ) {
2570 _objc_z = malloc_default_zone();
2576 /***********************************************************************
2578 **********************************************************************/
2580 static unsigned long _get_pc_for_thread (mach_port_t thread)
2583 struct hp_pa_frame_thread_state state;
2584 unsigned int count = HPPA_FRAME_THREAD_STATE_COUNT;
2585 kern_return_t okay = thread_get_state (thread, HPPA_FRAME_THREAD_STATE, (thread_state_t)&state, &count);
2586 return (okay == KERN_SUCCESS) ? state.ts_pcoq_front : PC_SENTINAL;
2588 #elif defined(sparc)
2590 struct sparc_thread_state_regs state;
2591 unsigned int count = SPARC_THREAD_STATE_REGS_COUNT;
2592 kern_return_t okay = thread_get_state (thread, SPARC_THREAD_STATE_REGS, (thread_state_t)&state, &count);
2593 return (okay == KERN_SUCCESS) ? state.regs.r_pc : PC_SENTINAL;
2595 #elif defined(__i386__) || defined(i386)
2597 i386_thread_state_t state;
2598 unsigned int count = i386_THREAD_STATE_COUNT;
2599 kern_return_t okay = thread_get_state (thread, i386_THREAD_STATE, (thread_state_t)&state, &count);
2600 return (okay == KERN_SUCCESS) ? state.eip : PC_SENTINAL;
2604 struct m68k_thread_state_regs state;
2605 unsigned int count = M68K_THREAD_STATE_REGS_COUNT;
2606 kern_return_t okay = thread_get_state (thread, M68K_THREAD_STATE_REGS, (thread_state_t)&state, &count);
2607 return (okay == KERN_SUCCESS) ? state.pc : PC_SENTINAL;
2609 #elif defined(__ppc__) || defined(ppc)
2611 struct ppc_thread_state state;
2612 unsigned int count = PPC_THREAD_STATE_COUNT;
2613 kern_return_t okay = thread_get_state (thread, PPC_THREAD_STATE, (thread_state_t)&state, &count);
2614 return (okay == KERN_SUCCESS) ? state.srr0 : PC_SENTINAL;
2618 #error _get_pc_for_thread () not implemented for this architecture
2622 /***********************************************************************
2623 * _collecting_in_critical.
2624 * Returns TRUE if some thread is currently executing a cache-reading
2625 * function. Collection of cache garbage is not allowed when a cache-
2626 * reading function is in progress because it might still be using
2627 * the garbage memory.
2628 **********************************************************************/
2629 OBJC_EXPORT unsigned long objc_entryPoints[];
2630 OBJC_EXPORT unsigned long objc_exitPoints[];
2632 static int _collecting_in_critical (void)
2634 thread_act_port_array_t threads;
2640 mach_port_t mythread = pthread_mach_thread_np(pthread_self());
2642 // Get a list of all the threads in the current task
2643 ret = task_threads (mach_task_self (), &threads, &number);
2644 if (ret != KERN_SUCCESS)
2646 _objc_fatal("task_thread failed (result %d)\n", ret);
2649 // Check whether any thread is in the cache lookup code
2651 for (count = 0; count < number; count++)
2656 // Don't bother checking ourselves
2657 if (threads[count] == mythread)
2660 // Find out where thread is executing
2661 pc = _get_pc_for_thread (threads[count]);
2663 // Check for bad status, and if so, assume the worse (can't collect)
2664 if (pc == PC_SENTINAL)
2670 // Check whether it is in the cache lookup code
2671 for (region = 0; objc_entryPoints[region] != 0; region++)
2673 if ((pc >= objc_entryPoints[region]) &&
2674 (pc <= objc_exitPoints[region]))
2683 // Deallocate the port rights for the threads
2684 for (count = 0; count < number; count++) {
2685 mach_port_deallocate(mach_task_self (), threads[count]);
2688 // Deallocate the thread list
2689 vm_deallocate (mach_task_self (), (vm_address_t) threads, sizeof(threads) * number);
2691 // Return our finding
2695 /***********************************************************************
2696 * _garbage_make_room. Ensure that there is enough room for at least
2697 * one more ref in the garbage.
2698 **********************************************************************/
2700 // amount of memory represented by all refs in the garbage
2701 static int garbage_byte_size = 0;
2703 // do not empty the garbage until garbage_byte_size gets at least this big
2704 static int garbage_threshold = 1024;
2706 // table of refs to free
2707 static void **garbage_refs = 0;
2709 // current number of refs in garbage_refs
2710 static int garbage_count = 0;
2712 // capacity of current garbage_refs
2713 static int garbage_max = 0;
2715 // capacity of initial garbage_refs
2717 INIT_GARBAGE_COUNT = 128
2720 static void _garbage_make_room (void)
2722 static int first = 1;
2723 volatile void * tempGarbage;
2725 // Create the collection table the first time it is needed
2729 garbage_refs = malloc_zone_malloc (_objc_create_zone(),
2730 INIT_GARBAGE_COUNT * sizeof(void *));
2731 garbage_max = INIT_GARBAGE_COUNT;
2734 // Double the table if it is full
2735 else if (garbage_count == garbage_max)
2737 tempGarbage = malloc_zone_realloc ((void *) _objc_create_zone(),
2738 (void *) garbage_refs,
2739 (size_t) garbage_max * 2 * sizeof(void *));
2740 garbage_refs = (void **) tempGarbage;
2745 /***********************************************************************
2746 * _cache_collect_free. Add the specified malloc'd memory to the list
2747 * of them to free at some later point.
2748 * Cache locks: cacheUpdateLock must be held by the caller.
2749 **********************************************************************/
2750 static void _cache_collect_free (void * data,
2753 static char *report_garbage = (char *)0xffffffff;
2755 if ((char *)0xffffffff == report_garbage) {
2756 // Check whether to log our activity
2757 report_garbage = getenv ("OBJC_REPORT_GARBAGE");
2760 // Insert new element in garbage list
2761 // Note that we do this even if we end up free'ing everything
2762 _garbage_make_room ();
2763 garbage_byte_size += malloc_size (data);
2764 garbage_refs[garbage_count++] = data;
2767 if (tryCollect && report_garbage)
2768 _objc_inform ("total of %d bytes of garbage ...", garbage_byte_size);
2770 // Done if caller says not to empty or the garbage is not full
2771 if (!tryCollect || (garbage_byte_size < garbage_threshold))
2773 if (tryCollect && report_garbage)
2774 _objc_inform ("couldn't collect cache garbage: below threshold\n");
2779 // tryCollect is guaranteed to be true after this point
2781 // Synchronize garbage collection with objc_msgSend and other cache readers
2782 if (!_collecting_in_critical ()) {
2783 // No cache readers in progress - garbage is now deletable
2787 _objc_inform ("collecting!\n");
2789 // Dispose all refs now in the garbage
2790 while (garbage_count)
2791 free (garbage_refs[--garbage_count]);
2793 // Clear the total size indicator
2794 garbage_byte_size = 0;
2797 // objc_msgSend (or other cache reader) is currently looking in the
2798 // cache and might still be using some garbage.
2799 if (report_garbage) {
2800 _objc_inform ("couldn't collect cache garbage: objc_msgSend in progress\n");
2806 /***********************************************************************
2808 **********************************************************************/
2809 static void _cache_print (Cache cache)
2814 count = cache->mask + 1;
2815 for (index = 0; index < count; index += 1)
2816 if (CACHE_BUCKET_VALID(cache->buckets[index]))
2818 if (CACHE_BUCKET_IMP(cache->buckets[index]) == &_objc_msgForward)
2819 printf ("does not recognize: \n");
2820 printf ("%s\n", (const char *) CACHE_BUCKET_NAME(cache->buckets[index]));
2824 /***********************************************************************
2825 * _class_printMethodCaches.
2826 **********************************************************************/
2827 void _class_printMethodCaches (Class cls)
2829 if (((struct objc_class *)cls)->cache == &emptyCache)
2830 printf ("no instance-method cache for class %s\n", ((struct objc_class *)cls)->name);
2834 printf ("instance-method cache for class %s:\n", ((struct objc_class *)cls)->name);
2835 _cache_print (((struct objc_class *)cls)->cache);
2838 if (((struct objc_class * )((struct objc_class * )cls)->isa)->cache == &emptyCache)
2839 printf ("no class-method cache for class %s\n", ((struct objc_class *)cls)->name);
2843 printf ("class-method cache for class %s:\n", ((struct objc_class *)cls)->name);
2844 _cache_print (((struct objc_class * )((struct objc_class * )cls)->isa)->cache);
2848 /***********************************************************************
2850 **********************************************************************/
2851 static unsigned int log2 (unsigned int x)
2862 /***********************************************************************
2863 * _class_printDuplicateCacheEntries.
2864 **********************************************************************/
2865 void _class_printDuplicateCacheEntries (BOOL detail)
2867 NXHashTable * class_hash;
2869 struct objc_class * cls;
2870 unsigned int duplicates;
2871 unsigned int index1;
2872 unsigned int index2;
2875 unsigned int isMeta;
2879 printf ("Checking for duplicate cache entries \n");
2881 // Outermost loop - iterate over all classes
2882 class_hash = objc_getClasses ();
2883 state = NXInitHashState (class_hash);
2885 while (NXNextHashState (class_hash, &state, (void **) &cls))
2887 // Control loop - do given class' cache, then its isa's cache
2888 for (isMeta = 0; isMeta <= 1; isMeta += 1)
2890 // Select cache of interest and make sure it exists
2891 cache = isMeta ? cls->isa->cache : ((struct objc_class *)cls)->cache;
2892 if (cache == &emptyCache)
2895 // Middle loop - check each entry in the given cache
2898 for (index1 = 0; index1 < count; index1 += 1)
2900 // Skip invalid entry
2901 if (!CACHE_BUCKET_VALID(cache->buckets[index1]))
2904 // Inner loop - check that given entry matches no later entry
2905 for (index2 = index1 + 1; index2 < count; index2 += 1)
2907 // Skip invalid entry
2908 if (!CACHE_BUCKET_VALID(cache->buckets[index2]))
2911 // Check for duplication by method name comparison
2912 if (strcmp ((char *) CACHE_BUCKET_NAME(cache->buckets[index1]),
2913 (char *) CACHE_BUCKET_NAME(cache->buckets[index2])) == 0)
2916 printf ("%s %s\n", ((struct objc_class *)cls)->name, (char *) CACHE_BUCKET_NAME(cache->buckets[index1]));
2926 printf ("duplicates = %d\n", duplicates);
2927 printf ("total cache fills = %d\n", totalCacheFills);
2930 /***********************************************************************
2932 **********************************************************************/
2933 static void PrintCacheHeader (void)
2935 #ifdef OBJC_INSTRUMENTED
2936 printf ("Cache Cache Slots Avg Max AvgS MaxS AvgS MaxS TotalD AvgD MaxD TotalD AvgD MaxD TotD AvgD MaxD\n");
2937 printf ("Size Count Used Used Used Hit Hit Miss Miss Hits Prbs Prbs Misses Prbs Prbs Flsh Flsh Flsh\n");
2938 printf ("----- ----- ----- ----- ---- ---- ---- ---- ---- ------- ---- ---- ------- ---- ---- ---- ---- ----\n");
2940 printf ("Cache Cache Slots Avg Max AvgS MaxS AvgS MaxS\n");
2941 printf ("Size Count Used Used Used Hit Hit Miss Miss\n");
2942 printf ("----- ----- ----- ----- ---- ---- ---- ---- ----\n");
2946 /***********************************************************************
2948 **********************************************************************/
2949 static void PrintCacheInfo (unsigned int cacheSize,
2950 unsigned int cacheCount,
2951 unsigned int slotsUsed,
2953 unsigned int maxUsed,
2955 unsigned int maxSHit,
2957 unsigned int maxSMiss
2958 #ifdef OBJC_INSTRUMENTED
2959 , unsigned int totDHits,
2961 unsigned int maxDHit,
2962 unsigned int totDMisses,
2964 unsigned int maxDMiss,
2965 unsigned int totDFlsh,
2967 unsigned int maxDFlsh
2971 #ifdef OBJC_INSTRUMENTED
2972 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",
2974 printf ("%5u %5u %5u %5.1f %4u %4.1f %4u %4.1f %4u\n",
2976 cacheSize, cacheCount, slotsUsed, avgUsed, maxUsed, avgSHit, maxSHit, avgSMiss, maxSMiss
2977 #ifdef OBJC_INSTRUMENTED
2978 , totDHits, avgDHit, maxDHit, totDMisses, avgDMiss, maxDMiss, totDFlsh, avgDFlsh, maxDFlsh
2984 #ifdef OBJC_INSTRUMENTED
2985 /***********************************************************************
2986 * PrintCacheHistogram. Show the non-zero entries from the specified
2988 **********************************************************************/
2989 static void PrintCacheHistogram (char * title,
2990 unsigned int * firstEntry,
2991 unsigned int entryCount)
2994 unsigned int * thisEntry;
2996 printf ("%s\n", title);
2997 printf (" Probes Tally\n");
2998 printf (" ------ -----\n");
2999 for (index = 0, thisEntry = firstEntry;
3001 index += 1, thisEntry += 1)
3003 if (*thisEntry == 0)
3006 printf (" %6d %5d\n", index, *thisEntry);
3011 /***********************************************************************
3012 * _class_printMethodCacheStatistics.
3013 **********************************************************************/
3015 #define MAX_LOG2_SIZE 32
3016 #define MAX_CHAIN_SIZE 100
3018 void _class_printMethodCacheStatistics (void)
3020 unsigned int isMeta;
3022 NXHashTable * class_hash;
3024 struct objc_class * cls;
3025 unsigned int totalChain;
3026 unsigned int totalMissChain;
3027 unsigned int maxChain;
3028 unsigned int maxMissChain;
3029 unsigned int classCount;
3030 unsigned int negativeEntryCount;
3031 unsigned int cacheExpandCount;
3032 unsigned int cacheCountBySize[2][MAX_LOG2_SIZE] = {{0}};
3033 unsigned int totalEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};
3034 unsigned int maxEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};
3035 unsigned int totalChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3036 unsigned int totalMissChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3037 unsigned int totalMaxChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3038 unsigned int totalMaxMissChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3039 unsigned int maxChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3040 unsigned int maxMissChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3041 unsigned int chainCount[MAX_CHAIN_SIZE] = {0};
3042 unsigned int missChainCount[MAX_CHAIN_SIZE] = {0};
3043 #ifdef OBJC_INSTRUMENTED
3044 unsigned int hitCountBySize[2][MAX_LOG2_SIZE] = {{0}};
3045 unsigned int hitProbesBySize[2][MAX_LOG2_SIZE] = {{0}};
3046 unsigned int maxHitProbesBySize[2][MAX_LOG2_SIZE] = {{0}};
3047 unsigned int missCountBySize[2][MAX_LOG2_SIZE] = {{0}};
3048 unsigned int missProbesBySize[2][MAX_LOG2_SIZE] = {{0}};
3049 unsigned int maxMissProbesBySize[2][MAX_LOG2_SIZE] = {{0}};
3050 unsigned int flushCountBySize[2][MAX_LOG2_SIZE] = {{0}};
3051 unsigned int flushedEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};
3052 unsigned int maxFlushedEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};
3055 printf ("Printing cache statistics\n");
3057 // Outermost loop - iterate over all classes
3058 class_hash = objc_getClasses ();
3059 state = NXInitHashState (class_hash);
3061 negativeEntryCount = 0;
3062 cacheExpandCount = 0;
3063 while (NXNextHashState (class_hash, &state, (void **) &cls))
3068 // Control loop - do given class' cache, then its isa's cache
3069 for (isMeta = 0; isMeta <= 1; isMeta += 1)
3073 unsigned int log2Size;
3074 unsigned int entryCount;
3076 // Select cache of interest
3077 cache = isMeta ? cls->isa->cache : ((struct objc_class *)cls)->cache;
3079 // Ignore empty cache... should we?
3080 if (cache == &emptyCache)
3083 // Middle loop - do each entry in the given cache
3090 for (index = 0; index < mask + 1; index += 1)
3095 uarith_t methodChain;
3096 uarith_t methodMissChain;
3099 // If entry is invalid, the only item of
3100 // interest is that future insert hashes
3101 // to this entry can use it directly.
3102 buckets = cache->buckets;
3103 if (!CACHE_BUCKET_VALID(buckets[index]))
3105 missChainCount[0] += 1;
3109 method = buckets[index];
3111 // Tally valid entries
3114 // Tally "forward::" entries
3115 if (CACHE_BUCKET_IMP(method) == &_objc_msgForward)
3116 negativeEntryCount += 1;
3118 // Calculate search distance (chain length) for this method
3119 // The chain may wrap around to the beginning of the table.
3120 hash = CACHE_HASH(CACHE_BUCKET_NAME(method), mask);
3121 if (index >= hash) methodChain = index - hash;
3122 else methodChain = (mask+1) + index - hash;
3124 // Tally chains of this length
3125 if (methodChain < MAX_CHAIN_SIZE)
3126 chainCount[methodChain] += 1;
3128 // Keep sum of all chain lengths
3129 totalChain += methodChain;
3131 // Record greatest chain length
3132 if (methodChain > maxChain)
3133 maxChain = methodChain;
3135 // Calculate search distance for miss that hashes here
3137 while (CACHE_BUCKET_VALID(buckets[index2]))
3142 methodMissChain = ((index2 - index) & mask);
3144 // Tally miss chains of this length
3145 if (methodMissChain < MAX_CHAIN_SIZE)
3146 missChainCount[methodMissChain] += 1;
3148 // Keep sum of all miss chain lengths in this class
3149 totalMissChain += methodMissChain;
3151 // Record greatest miss chain length
3152 if (methodMissChain > maxMissChain)
3153 maxMissChain = methodMissChain;
3156 // Factor this cache into statistics about caches of the same
3157 // type and size (all caches are a power of two in size)
3158 log2Size = log2 (mask + 1);
3159 cacheCountBySize[isMeta][log2Size] += 1;
3160 totalEntriesBySize[isMeta][log2Size] += entryCount;
3161 if (entryCount > maxEntriesBySize[isMeta][log2Size])
3162 maxEntriesBySize[isMeta][log2Size] = entryCount;
3163 totalChainBySize[isMeta][log2Size] += totalChain;
3164 totalMissChainBySize[isMeta][log2Size] += totalMissChain;
3165 totalMaxChainBySize[isMeta][log2Size] += maxChain;
3166 totalMaxMissChainBySize[isMeta][log2Size] += maxMissChain;
3167 if (maxChain > maxChainBySize[isMeta][log2Size])
3168 maxChainBySize[isMeta][log2Size] = maxChain;
3169 if (maxMissChain > maxMissChainBySize[isMeta][log2Size])
3170 maxMissChainBySize[isMeta][log2Size] = maxMissChain;
3171 #ifdef OBJC_INSTRUMENTED
3173 CacheInstrumentation * cacheData;
3175 cacheData = CACHE_INSTRUMENTATION(cache);
3176 hitCountBySize[isMeta][log2Size] += cacheData->hitCount;
3177 hitProbesBySize[isMeta][log2Size] += cacheData->hitProbes;
3178 if (cacheData->maxHitProbes > maxHitProbesBySize[isMeta][log2Size])
3179 maxHitProbesBySize[isMeta][log2Size] = cacheData->maxHitProbes;
3180 missCountBySize[isMeta][log2Size] += cacheData->missCount;
3181 missProbesBySize[isMeta][log2Size] += cacheData->missProbes;
3182 if (cacheData->maxMissProbes > maxMissProbesBySize[isMeta][log2Size])
3183 maxMissProbesBySize[isMeta][log2Size] = cacheData->maxMissProbes;
3184 flushCountBySize[isMeta][log2Size] += cacheData->flushCount;
3185 flushedEntriesBySize[isMeta][log2Size] += cacheData->flushedEntries;
3186 if (cacheData->maxFlushedEntries > maxFlushedEntriesBySize[isMeta][log2Size])
3187 maxFlushedEntriesBySize[isMeta][log2Size] = cacheData->maxFlushedEntries;
3190 // Caches start with a power of two number of entries, and grow by doubling, so
3191 // we can calculate the number of times this cache has expanded
3193 cacheExpandCount += log2Size - INIT_META_CACHE_SIZE_LOG2;
3195 cacheExpandCount += log2Size - INIT_CACHE_SIZE_LOG2;
3201 unsigned int cacheCountByType[2] = {0};
3202 unsigned int totalCacheCount = 0;
3203 unsigned int totalEntries = 0;
3204 unsigned int maxEntries = 0;
3205 unsigned int totalSlots = 0;
3206 #ifdef OBJC_INSTRUMENTED
3207 unsigned int totalHitCount = 0;
3208 unsigned int totalHitProbes = 0;
3209 unsigned int maxHitProbes = 0;
3210 unsigned int totalMissCount = 0;
3211 unsigned int totalMissProbes = 0;
3212 unsigned int maxMissProbes = 0;
3213 unsigned int totalFlushCount = 0;
3214 unsigned int totalFlushedEntries = 0;
3215 unsigned int maxFlushedEntries = 0;
3223 // Sum information over all caches
3224 for (isMeta = 0; isMeta <= 1; isMeta += 1)
3226 for (index = 0; index < MAX_LOG2_SIZE; index += 1)
3228 cacheCountByType[isMeta] += cacheCountBySize[isMeta][index];
3229 totalEntries += totalEntriesBySize[isMeta][index];
3230 totalSlots += cacheCountBySize[isMeta][index] * (1 << index);
3231 totalChain += totalChainBySize[isMeta][index];
3232 if (maxEntriesBySize[isMeta][index] > maxEntries)
3233 maxEntries = maxEntriesBySize[isMeta][index];
3234 if (maxChainBySize[isMeta][index] > maxChain)
3235 maxChain = maxChainBySize[isMeta][index];
3236 totalMissChain += totalMissChainBySize[isMeta][index];
3237 if (maxMissChainBySize[isMeta][index] > maxMissChain)
3238 maxMissChain = maxMissChainBySize[isMeta][index];
3239 #ifdef OBJC_INSTRUMENTED
3240 totalHitCount += hitCountBySize[isMeta][index];
3241 totalHitProbes += hitProbesBySize[isMeta][index];
3242 if (maxHitProbesBySize[isMeta][index] > maxHitProbes)
3243 maxHitProbes = maxHitProbesBySize[isMeta][index];
3244 totalMissCount += missCountBySize[isMeta][index];
3245 totalMissProbes += missProbesBySize[isMeta][index];
3246 if (maxMissProbesBySize[isMeta][index] > maxMissProbes)
3247 maxMissProbes = maxMissProbesBySize[isMeta][index];
3248 totalFlushCount += flushCountBySize[isMeta][index];
3249 totalFlushedEntries += flushedEntriesBySize[isMeta][index];
3250 if (maxFlushedEntriesBySize[isMeta][index] > maxFlushedEntries)
3251 maxFlushedEntries = maxFlushedEntriesBySize[isMeta][index];
3255 totalCacheCount += cacheCountByType[isMeta];
3259 printf ("There are %u classes\n", classCount);
3261 for (isMeta = 0; isMeta <= 1; isMeta += 1)
3263 // Number of this type of class
3264 printf ("\nThere are %u %s-method caches, broken down by size (slot count):\n",
3265 cacheCountByType[isMeta],
3266 isMeta ? "class" : "instance");
3269 PrintCacheHeader ();
3271 // Keep format consistent even if there are caches of this kind
3272 if (cacheCountByType[isMeta] == 0)
3274 printf ("(none)\n");
3278 // Usage information by cache size
3279 for (index = 0; index < MAX_LOG2_SIZE; index += 1)
3281 unsigned int cacheCount;
3282 unsigned int cacheSlotCount;
3283 unsigned int cacheEntryCount;
3285 // Get number of caches of this type and size
3286 cacheCount = cacheCountBySize[isMeta][index];
3287 if (cacheCount == 0)
3290 // Get the cache slot count and the total number of valid entries
3291 cacheSlotCount = (1 << index);
3292 cacheEntryCount = totalEntriesBySize[isMeta][index];
3294 // Give the analysis
3295 PrintCacheInfo (cacheSlotCount,
3298 (float) cacheEntryCount / (float) cacheCount,
3299 maxEntriesBySize[isMeta][index],
3300 (float) totalChainBySize[isMeta][index] / (float) cacheEntryCount,
3301 maxChainBySize[isMeta][index],
3302 (float) totalMissChainBySize[isMeta][index] / (float) (cacheCount * cacheSlotCount),
3303 maxMissChainBySize[isMeta][index]
3304 #ifdef OBJC_INSTRUMENTED
3305 , hitCountBySize[isMeta][index],
3306 hitCountBySize[isMeta][index] ?
3307 (float) hitProbesBySize[isMeta][index] / (float) hitCountBySize[isMeta][index] : 0.0,
3308 maxHitProbesBySize[isMeta][index],
3309 missCountBySize[isMeta][index],
3310 missCountBySize[isMeta][index] ?
3311 (float) missProbesBySize[isMeta][index] / (float) missCountBySize[isMeta][index] : 0.0,
3312 maxMissProbesBySize[isMeta][index],
3313 flushCountBySize[isMeta][index],
3314 flushCountBySize[isMeta][index] ?
3315 (float) flushedEntriesBySize[isMeta][index] / (float) flushCountBySize[isMeta][index] : 0.0,
3316 maxFlushedEntriesBySize[isMeta][index]
3322 // Give overall numbers
3323 printf ("\nCumulative:\n");
3324 PrintCacheHeader ();
3325 PrintCacheInfo (totalSlots,
3328 (float) totalEntries / (float) totalCacheCount,
3330 (float) totalChain / (float) totalEntries,
3332 (float) totalMissChain / (float) totalSlots,
3334 #ifdef OBJC_INSTRUMENTED
3337 (float) totalHitProbes / (float) totalHitCount : 0.0,
3341 (float) totalMissProbes / (float) totalMissCount : 0.0,
3345 (float) totalFlushedEntries / (float) totalFlushCount : 0.0,
3350 printf ("\nNumber of \"forward::\" entries: %d\n", negativeEntryCount);
3351 printf ("Number of cache expansions: %d\n", cacheExpandCount);
3352 #ifdef OBJC_INSTRUMENTED
3353 printf ("flush_caches: total calls total visits average visits max visits total classes visits/class\n");
3354 printf (" ----------- ------------ -------------- ---------- ------------- -------------\n");
3355 printf (" linear %11u %12u %14.1f %10u %13u %12.2f\n",
3356 LinearFlushCachesCount,
3357 LinearFlushCachesVisitedCount,
3358 LinearFlushCachesCount ?
3359 (float) LinearFlushCachesVisitedCount / (float) LinearFlushCachesCount : 0.0,
3360 MaxLinearFlushCachesVisitedCount,
3361 LinearFlushCachesVisitedCount,
3363 printf (" nonlinear %11u %12u %14.1f %10u %13u %12.2f\n",
3364 NonlinearFlushCachesCount,
3365 NonlinearFlushCachesVisitedCount,
3366 NonlinearFlushCachesCount ?
3367 (float) NonlinearFlushCachesVisitedCount / (float) NonlinearFlushCachesCount : 0.0,
3368 MaxNonlinearFlushCachesVisitedCount,
3369 NonlinearFlushCachesClassCount,
3370 NonlinearFlushCachesClassCount ?
3371 (float) NonlinearFlushCachesVisitedCount / (float) NonlinearFlushCachesClassCount : 0.0);
3372 printf (" ideal %11u %12u %14.1f %10u %13u %12.2f\n",
3373 LinearFlushCachesCount + NonlinearFlushCachesCount,
3374 IdealFlushCachesCount,
3375 LinearFlushCachesCount + NonlinearFlushCachesCount ?
3376 (float) IdealFlushCachesCount / (float) (LinearFlushCachesCount + NonlinearFlushCachesCount) : 0.0,
3377 MaxIdealFlushCachesCount,
3378 LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount,
3379 LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount ?
3380 (float) IdealFlushCachesCount / (float) (LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount) : 0.0);
3382 PrintCacheHistogram ("\nCache hit histogram:", &CacheHitHistogram[0], CACHE_HISTOGRAM_SIZE);
3383 PrintCacheHistogram ("\nCache miss histogram:", &CacheMissHistogram[0], CACHE_HISTOGRAM_SIZE);
3387 printf ("\nLookup chains:");
3388 for (index = 0; index < MAX_CHAIN_SIZE; index += 1)
3390 if (chainCount[index] != 0)
3391 printf (" %u:%u", index, chainCount[index]);
3394 printf ("\nMiss chains:");
3395 for (index = 0; index < MAX_CHAIN_SIZE; index += 1)
3397 if (missChainCount[index] != 0)
3398 printf (" %u:%u", index, missChainCount[index]);
3401 printf ("\nTotal memory usage for cache data structures: %lu bytes\n",
3402 totalCacheCount * (sizeof(struct objc_cache) - sizeof(Method)) +
3403 totalSlots * sizeof(Method) +
3404 negativeEntryCount * sizeof(struct objc_method));
3409 /***********************************************************************
3411 **********************************************************************/
3412 void checkUniqueness (SEL s1,
3418 if (s1 && s2 && (strcmp ((const char *) s1, (const char *) s2) == 0))
3419 _objc_inform ("%p != %p but !strcmp (%s, %s)\n", s1, s2, (char *) s1, (char *) s2);