2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
24 /***********************************************************************
26 * Copyright 1988-1997, Apple Computer, Inc.
28 **********************************************************************/
30 /***********************************************************************
32 **********************************************************************/
35 #import <mach/mach_interface.h>
36 #include <mach-o/ldsyms.h>
37 #include <mach-o/dyld.h>
43 #include <winnt-pdo.h>
45 #include <sys/types.h>
52 #include <sys/fcntl.h>
56 #if defined(__svr4__) || defined(__hpux__) || defined(hpux)
60 #import <objc/Object.h>
61 #import <objc/objc-runtime.h>
62 #import "objc-private.h"
63 #import "hashtable2.h"
66 #include <sys/types.h>
68 #include <CoreFoundation/CFDictionary.h>
70 // Needed functions not in any header file
71 size_t malloc_size (const void * ptr);
73 // Needed kernel interface
76 #import <mach/thread_status.h>
79 // This is currently disabled in this file, because it is called a LOT here; turn it on when needed.
80 #if 0 && defined(__MACH__)
81 extern int ptrace(int, int, int, int);
82 // ObjC is assigned the range 0xb000 - 0xbfff for first parameter; this file 0xb300-0xb3ff
84 #define ptrace(a, b, c, d) do {} while (0)
87 /***********************************************************************
89 **********************************************************************/
91 // Define PRELOAD_SUPERCLASS_CACHES to cause method lookups to add the
92 // method the appropriate superclass caches, in addition to the normal
93 // encaching in the subclass where the method was messaged. Doing so
94 // will speed up messaging the same method from instances of the
95 // superclasses, but also uses up valuable cache space for a speculative
97 //#define PRELOAD_SUPERCLASS_CACHES
99 /***********************************************************************
101 **********************************************************************/
103 #ifdef OBJC_INSTRUMENTED
105 CACHE_HISTOGRAM_SIZE = 512
108 unsigned int CacheHitHistogram [CACHE_HISTOGRAM_SIZE];
109 unsigned int CacheMissHistogram [CACHE_HISTOGRAM_SIZE];
112 /***********************************************************************
113 * Constants and macros internal to this module.
114 **********************************************************************/
116 // INIT_CACHE_SIZE and INIT_META_CACHE_SIZE must be a power of two
118 INIT_CACHE_SIZE_LOG2 = 2,
119 INIT_META_CACHE_SIZE_LOG2 = 2,
120 INIT_CACHE_SIZE = (1 << INIT_CACHE_SIZE_LOG2),
121 INIT_META_CACHE_SIZE = (1 << INIT_META_CACHE_SIZE_LOG2)
124 // Amount of space required for count hash table buckets, knowing that
125 // one entry is embedded in the cache structure itself
126 #define TABLE_SIZE(count) ((count - 1) * sizeof(Method))
129 #define ISCLASS(cls) ((((struct objc_class *) cls)->info & CLS_CLASS) != 0)
130 #define ISMETA(cls) ((((struct objc_class *) cls)->info & CLS_META) != 0)
131 #define GETMETA(cls) (ISMETA(cls) ? ((struct objc_class *) cls) : ((struct objc_class *) cls)->isa)
132 #define ISINITIALIZED(cls) ((GETMETA(cls)->info & CLS_INITIALIZED) != 0)
133 #define MARKINITIALIZED(cls) (GETMETA(cls)->info |= CLS_INITIALIZED)
135 /***********************************************************************
136 * Types internal to this module.
137 **********************************************************************/
139 #ifdef OBJC_INSTRUMENTED
140 struct CacheInstrumentation
142 unsigned int hitCount; // cache lookup success tally
143 unsigned int hitProbes; // sum entries checked to hit
144 unsigned int maxHitProbes; // max entries checked to hit
145 unsigned int missCount; // cache lookup no-find tally
146 unsigned int missProbes; // sum entries checked to miss
147 unsigned int maxMissProbes; // max entries checked to miss
148 unsigned int flushCount; // cache flush tally
149 unsigned int flushedEntries; // sum cache entries flushed
150 unsigned int maxFlushedEntries; // max cache entries flushed
152 typedef struct CacheInstrumentation CacheInstrumentation;
154 // Cache instrumentation data follows table, so it is most compatible
155 #define CACHE_INSTRUMENTATION(cache) (CacheInstrumentation *) &cache->buckets[cache->mask + 1];
158 /***********************************************************************
159 * Function prototypes internal to this module.
160 **********************************************************************/
162 static Ivar class_getVariable (Class cls, const char * name);
163 static void flush_caches (Class cls, BOOL flush_meta);
164 static void addClassToOriginalClass (Class posingClass, Class originalClass);
165 static void _objc_addOrigClass (Class origClass);
166 static void _freedHandler (id self, SEL sel);
167 static void _nonexistentHandler (id self, SEL sel);
168 static void class_initialize (Class clsDesc);
169 static void * objc_malloc (int byteCount);
170 static Cache _cache_expand (Class cls);
171 static int LogObjCMessageSend (BOOL isClassMethod, const char * objectsClass, const char * implementingClass, SEL selector);
172 static void _cache_fill (Class cls, Method smt, SEL sel);
173 static void _cache_flush (Class cls);
174 static Method _class_lookupMethod (Class cls, SEL sel);
175 static int SubtypeUntil (const char * type, char end);
176 static const char * SkipFirstType (const char * type);
178 #ifdef OBJC_COLLECTING_CACHE
179 static unsigned long _get_pc_for_thread (mach_port_t thread);
180 static int _collecting_in_critical (void);
181 static void _garbage_make_room (void);
182 static void _cache_collect_free (void * data, BOOL tryCollect);
185 static void _cache_print (Cache cache);
186 static unsigned int log2 (unsigned int x);
187 static void PrintCacheHeader (void);
188 #ifdef OBJC_INSTRUMENTED
189 static void PrintCacheHistogram (char * title, unsigned int * firstEntry, unsigned int entryCount);
192 /***********************************************************************
193 * Static data internal to this module.
194 **********************************************************************/
196 // When _class_uncache is non-zero, cache growth copies the existing
197 // entries into the new (larger) cache. When this flag is zero, new
198 // (larger) caches start out empty.
199 static int _class_uncache = 1;
201 // When _class_slow_grow is non-zero, any given cache is actually grown
202 // only on the odd-numbered times it becomes full; on the even-numbered
203 // times, it is simply emptied and re-used. When this flag is zero,
204 // caches are grown every time.
205 static int _class_slow_grow = 1;
207 // Locks for cache access
208 #ifdef OBJC_COLLECTING_CACHE
209 // Held when adding an entry to the cache
210 static OBJC_DECLARE_LOCK(cacheUpdateLock);
212 // Held when freeing memory from garbage
213 static OBJC_DECLARE_LOCK(cacheCollectionLock);
216 // Held when looking in, adding to, or freeing the cache.
217 #ifdef OBJC_COLLECTING_CACHE
218 // For speed, messageLock is not held by the method dispatch code.
219 // Instead the cache freeing code checks thread PCs to ensure no
220 // one is dispatching. messageLock is held, though, during less
221 // time critical operations.
223 OBJC_DECLARE_LOCK(messageLock);
225 CFMutableDictionaryRef _classIMPTables = NULL;
227 // When traceDuplicates is non-zero, _cacheFill checks whether the method
228 // being encached is already there. The number of times it finds a match
229 // is tallied in cacheFillDuplicates. When traceDuplicatesVerbose is
230 // non-zero, each duplication is logged when found in this way.
231 #ifdef OBJC_COLLECTING_CACHE
232 static int traceDuplicates = 0;
233 static int traceDuplicatesVerbose = 0;
234 static int cacheFillDuplicates = 0;
237 #ifdef OBJC_INSTRUMENTED
239 static unsigned int LinearFlushCachesCount = 0;
240 static unsigned int LinearFlushCachesVisitedCount = 0;
241 static unsigned int MaxLinearFlushCachesVisitedCount = 0;
242 static unsigned int NonlinearFlushCachesCount = 0;
243 static unsigned int NonlinearFlushCachesClassCount = 0;
244 static unsigned int NonlinearFlushCachesVisitedCount = 0;
245 static unsigned int MaxNonlinearFlushCachesVisitedCount = 0;
246 static unsigned int IdealFlushCachesCount = 0;
247 static unsigned int MaxIdealFlushCachesCount = 0;
250 // Method call logging
251 typedef int (*ObjCLogProc)(BOOL, const char *, const char *, SEL);
253 static int totalCacheFills = 0;
254 static int objcMsgLogFD = (-1);
255 static ObjCLogProc objcMsgLogProc = &LogObjCMessageSend;
256 static int objcMsgLogEnabled = 0;
260 _errNoMem[] = "failed -- out of memory(%s, %u)",
261 _errAllocNil[] = "allocating nil object",
262 _errFreedObject[] = "message %s sent to freed object=0x%lx",
263 _errNonExistentObject[] = "message %s sent to non-existent object=0x%lx",
264 _errBadSel[] = "invalid selector %s",
265 _errNotSuper[] = "[%s poseAs:%s]: target not immediate superclass",
266 _errNewVars[] = "[%s poseAs:%s]: %s defines new instance variables";
268 /***********************************************************************
269 * Information about multi-thread support:
271 * Since we do not lock many operations which walk the superclass, method
272 * and ivar chains, these chains must remain intact once a class is published
273 * by inserting it into the class hashtable. All modifications must be
274 * atomic so that someone walking these chains will always geta valid
276 ***********************************************************************/
277 /***********************************************************************
278 * A static empty cache. All classes initially point at this cache.
279 * When the first message is sent it misses in the cache, and when
280 * the cache is grown it checks for this case and uses malloc rather
281 * than realloc. This avoids the need to check for NULL caches in the
283 ***********************************************************************/
285 const struct objc_cache emptyCache =
292 // Freed objects have their isa set to point to this dummy class.
293 // This avoids the need to check for Nil classes in the messenger.
294 static const struct objc_class freedObjectClass =
304 (Cache) &emptyCache, // cache
308 static const struct objc_class nonexistentObjectClass =
312 "NONEXISTENT(id)", // name
318 (Cache) &emptyCache, // cache
322 /***********************************************************************
323 * object_getClassName.
324 **********************************************************************/
325 const char * object_getClassName (id obj)
327 // Even nil objects have a class name, sort of
331 // Retrieve name from object's class
332 return ((struct objc_class *) obj->isa)->name;
335 /***********************************************************************
336 * object_getIndexedIvars.
337 **********************************************************************/
338 void * object_getIndexedIvars (id obj)
340 // ivars are tacked onto the end of the object
341 return ((char *) obj) + ((struct objc_class *) obj->isa)->instance_size;
345 /***********************************************************************
346 * _internal_class_createInstanceFromZone. Allocate an instance of the
347 * specified class with the specified number of bytes for indexed
348 * variables, in the specified zone. The isa field is set to the
349 * class, all other fields are zeroed.
350 **********************************************************************/
351 static id _internal_class_createInstanceFromZone (Class aClass,
356 register unsigned byteCount;
358 // Can't create something for nothing
361 __objc_error ((id) aClass, _errAllocNil, 0);
365 // Allocate and initialize
366 byteCount = ((struct objc_class *) aClass)->instance_size + nIvarBytes;
367 obj = (id) malloc_zone_calloc (z, 1, byteCount);
370 __objc_error ((id) aClass, _errNoMem, ((struct objc_class *) aClass)->name, nIvarBytes);
374 // Set the isa pointer
379 /***********************************************************************
380 * _internal_class_createInstance. Allocate an instance of the specified
381 * class with the specified number of bytes for indexed variables, in
382 * the default zone, using _internal_class_createInstanceFromZone.
383 **********************************************************************/
384 static id _internal_class_createInstance (Class aClass,
387 return _internal_class_createInstanceFromZone (aClass,
389 malloc_default_zone ());
392 id (*_poseAs)() = (id (*)())class_poseAs;
393 id (*_alloc)(Class, unsigned) = _internal_class_createInstance;
394 id (*_zoneAlloc)(Class, unsigned, void *) = _internal_class_createInstanceFromZone;
396 /***********************************************************************
397 * class_createInstanceFromZone. Allocate an instance of the specified
398 * class with the specified number of bytes for indexed variables, in
399 * the specified zone, using _zoneAlloc.
400 **********************************************************************/
401 id class_createInstanceFromZone (Class aClass,
405 // _zoneAlloc can be overridden, but is initially set to
406 // _internal_class_createInstanceFromZone
407 return (*_zoneAlloc) (aClass, nIvarBytes, z);
410 /***********************************************************************
411 * class_createInstance. Allocate an instance of the specified class with
412 * the specified number of bytes for indexed variables, using _alloc.
413 **********************************************************************/
414 id class_createInstance (Class aClass,
417 // _alloc can be overridden, but is initially set to
418 // _internal_class_createInstance
419 return (*_alloc) (aClass, nIvarBytes);
422 /***********************************************************************
423 * class_setVersion. Record the specified version with the class.
424 **********************************************************************/
425 void class_setVersion (Class aClass,
428 ((struct objc_class *) aClass)->version = version;
431 /***********************************************************************
432 * class_getVersion. Return the version recorded with the class.
433 **********************************************************************/
434 int class_getVersion (Class aClass)
436 return ((struct objc_class *) aClass)->version;
439 static void _addListIMPsToTable(CFMutableDictionaryRef table, struct objc_method_list *mlist, Class cls, void **iterator) {
441 struct objc_method_list *new_mlist;
443 /* Work from end of list so that categories override */
444 new_mlist = _class_inlinedNextMethodList(cls, iterator);
445 _addListIMPsToTable(table, new_mlist, cls, iterator);
446 for (i = 0; i < mlist->method_count; i++) {
447 CFDictionarySetValue(table, mlist->method_list[i].method_name, mlist->method_list[i].method_imp);
451 static void _addClassIMPsToTable(CFMutableDictionaryRef table, Class cls) {
452 struct objc_method_list *mlist;
454 #ifdef INCLUDE_SUPER_IMPS_IN_IMP_TABLE
455 if (cls->super_class) { /* Do superclass first so subclass overrides */
456 CFMutableDictionaryRef super_table = CFDictionaryGetValue(_classIMPTables, cls->super_class);
459 const void **keys, **values, *buffer1[128], *buffer2[128];
460 cnt = CFDictionaryGetCount(super_table);
461 keys = (cnt <= 128) ? buffer1 : CFAllocatorAllocate(NULL, cnt * sizeof(void *), 0);
462 values = (cnt <= 128) ? buffer2 : CFAllocatorAllocate(NULL, cnt * sizeof(void *), 0);
463 CFDictionaryGetKeysAndValues(super_table, keys, values);
465 CFDictionarySetValue(table, keys[cnt], values[cnt]);
467 if (keys != buffer1) CFAllocatorDeallocate(NULL, keys);
468 if (values != buffer2) CFAllocatorDeallocate(NULL, values);
470 _addClassIMPsToTable(table, cls->super_class);
474 mlist = _class_inlinedNextMethodList(cls, &iterator);
475 _addListIMPsToTable(table, mlist, cls, &iterator);
478 CFMutableDictionaryRef _getClassIMPTable(Class cls) {
479 CFMutableDictionaryRef table;
480 if (NULL == _classIMPTables) {
481 // maps Classes to mutable dictionaries
482 _classIMPTables = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
484 table = (CFMutableDictionaryRef)CFDictionaryGetValue(_classIMPTables, cls);
485 // IMP table maps SELs to IMPS
487 table = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
488 _addClassIMPsToTable(table, cls);
489 CFDictionaryAddValue(_classIMPTables, cls, table);
494 static inline Method _findNamedMethodInList(struct objc_method_list * mlist, const char *meth_name) {
496 if (!mlist) return NULL;
497 for (i = 0; i < mlist->method_count; i++) {
498 Method m = &mlist->method_list[i];
499 if (*((const char *)m->method_name) == *meth_name && 0 == strcmp((const char *)(m->method_name), meth_name)) {
506 /* These next three functions are the heart of ObjC method lookup. */
507 static inline Method _findMethodInList(struct objc_method_list * mlist, SEL sel) {
509 if (!mlist) return NULL;
510 for (i = 0; i < mlist->method_count; i++) {
511 Method m = &mlist->method_list[i];
512 if (m->method_name == sel) {
519 static inline Method _findMethodInClass(Class cls, SEL sel) {
520 struct objc_method_list *mlist;
522 while ((mlist = _class_inlinedNextMethodList(cls, &iterator))) {
523 Method m = _findMethodInList(mlist, sel);
529 static inline Method _getMethod(Class cls, SEL sel) {
530 for (; cls; cls = cls->super_class) {
531 Method m = _findMethodInClass(cls, sel);
538 /***********************************************************************
539 * class_getInstanceMethod. Return the instance method for the
540 * specified class and selector.
541 **********************************************************************/
542 Method class_getInstanceMethod (Class aClass,
545 // Need both a class and a selector
546 if (!aClass || !aSelector)
550 return _getMethod (aClass, aSelector);
553 /***********************************************************************
554 * class_getClassMethod. Return the class method for the specified
555 * class and selector.
556 **********************************************************************/
557 Method class_getClassMethod (Class aClass,
560 // Need both a class and a selector
561 if (!aClass || !aSelector)
564 // Go to the class or isa
565 return _getMethod (GETMETA(aClass), aSelector);
568 /***********************************************************************
569 * class_getVariable. Return the named instance variable.
570 **********************************************************************/
571 static Ivar class_getVariable (Class cls,
574 struct objc_class * thisCls;
576 // Outer loop - search the class and its superclasses
577 for (thisCls = cls; thisCls != Nil; thisCls = ((struct objc_class *) thisCls)->super_class)
582 // Skip class having no ivars
586 // Inner loop - search the given class
587 thisIvar = &thisCls->ivars->ivar_list[0];
588 for (index = 0; index < thisCls->ivars->ivar_count; index += 1)
590 // Check this ivar's name. Be careful because the
591 // compiler generates ivar entries with NULL ivar_name
592 // (e.g. for anonymous bit fields).
593 if ((thisIvar->ivar_name) &&
594 (strcmp (name, thisIvar->ivar_name) == 0))
606 /***********************************************************************
607 * class_getInstanceVariable. Return the named instance variable.
609 * Someday add class_getClassVariable ().
610 **********************************************************************/
611 Ivar class_getInstanceVariable (Class aClass,
614 // Must have a class and a name
615 if (!aClass || !name)
619 return class_getVariable (aClass, name);
622 /***********************************************************************
623 * flush_caches. Flush the instance and optionally class method caches
624 * of cls and all its subclasses.
626 * Specifying Nil for the class "all classes."
627 **********************************************************************/
628 static void flush_caches (Class cls,
631 int numClasses = 0, newNumClasses;
632 struct objc_class * * classes = NULL;
634 struct objc_class * clsObject;
635 #ifdef OBJC_INSTRUMENTED
636 unsigned int classesVisited;
637 unsigned int subclassCount;
640 // Do nothing if class has no cache
641 if (cls && !((struct objc_class *) cls)->cache)
644 newNumClasses = objc_getClassList((Class *)NULL, 0);
645 while (numClasses < newNumClasses) {
646 numClasses = newNumClasses;
647 classes = realloc(classes, sizeof(Class) * numClasses);
648 newNumClasses = objc_getClassList((Class *)classes, numClasses);
650 numClasses = newNumClasses;
652 // Handle nil and root instance class specially: flush all
653 // instance and class method caches. Nice that this
654 // loop is linear vs the N-squared loop just below.
655 if (!cls || !((struct objc_class *) cls)->super_class)
657 #ifdef OBJC_INSTRUMENTED
658 LinearFlushCachesCount += 1;
662 // Traverse all classes in the hash table
663 for (i = 0; i < numClasses; i++)
665 struct objc_class * metaClsObject;
666 #ifdef OBJC_INSTRUMENTED
669 clsObject = classes[i];
671 // Skip class that is known not to be a subclass of this root
672 // (the isa pointer of any meta class points to the meta class
674 // NOTE: When is an isa pointer of a hash tabled class ever nil?
675 metaClsObject = ((struct objc_class *) clsObject)->isa;
676 if (cls && metaClsObject && (((struct objc_class *) metaClsObject)->isa != ((struct objc_class *) metaClsObject)->isa))
679 #ifdef OBJC_INSTRUMENTED
683 // Be careful of classes that do not yet have caches
684 if (((struct objc_class *) clsObject)->cache)
685 _cache_flush (clsObject);
686 if (flush_meta && metaClsObject && ((struct objc_class *) metaClsObject)->cache)
687 _cache_flush (((struct objc_class *) clsObject)->isa);
689 #ifdef OBJC_INSTRUMENTED
690 LinearFlushCachesVisitedCount += classesVisited;
691 if (classesVisited > MaxLinearFlushCachesVisitedCount)
692 MaxLinearFlushCachesVisitedCount = classesVisited;
693 IdealFlushCachesCount += subclassCount;
694 if (subclassCount > MaxIdealFlushCachesCount)
695 MaxIdealFlushCachesCount = subclassCount;
702 // Outer loop - flush any cache that could now get a method from
703 // cls (i.e. the cache associated with cls and any of its subclasses).
704 #ifdef OBJC_INSTRUMENTED
705 NonlinearFlushCachesCount += 1;
709 for (i = 0; i < numClasses; i++)
711 struct objc_class * clsIter;
713 #ifdef OBJC_INSTRUMENTED
714 NonlinearFlushCachesClassCount += 1;
716 clsObject = classes[i];
718 // Inner loop - Process a given class
723 #ifdef OBJC_INSTRUMENTED
726 // Flush clsObject instance method cache if
727 // clsObject is a subclass of cls, or is cls itself
728 // Flush the class method cache if that was asked for
731 #ifdef OBJC_INSTRUMENTED
734 _cache_flush (clsObject);
736 _cache_flush (clsObject->isa);
742 // Flush clsObject class method cache if cls is
743 // the meta class of clsObject or of one
744 // of clsObject's superclasses
745 else if (clsIter->isa == cls)
747 #ifdef OBJC_INSTRUMENTED
750 _cache_flush (clsObject->isa);
754 // Move up superclass chain
755 else if (ISINITIALIZED(clsIter))
756 clsIter = clsIter->super_class;
758 // clsIter is not initialized, so its cache
759 // must be empty. This happens only when
760 // clsIter == clsObject, because
761 // superclasses are initialized before
762 // subclasses, and this loop traverses
763 // from sub- to super- classes.
768 #ifdef OBJC_INSTRUMENTED
769 NonlinearFlushCachesVisitedCount += classesVisited;
770 if (classesVisited > MaxNonlinearFlushCachesVisitedCount)
771 MaxNonlinearFlushCachesVisitedCount = classesVisited;
772 IdealFlushCachesCount += subclassCount;
773 if (subclassCount > MaxIdealFlushCachesCount)
774 MaxIdealFlushCachesCount = subclassCount;
777 // Relinquish access to class hash table
781 /***********************************************************************
782 * _objc_flush_caches. Flush the caches of the specified class and any
783 * of its subclasses. If cls is a meta-class, only meta-class (i.e.
784 * class method) caches are flushed. If cls is an instance-class, both
785 * instance-class and meta-class caches are flushed.
786 **********************************************************************/
787 void _objc_flush_caches (Class cls)
789 flush_caches (cls, YES);
792 /***********************************************************************
793 * do_not_remove_this_dummy_function.
794 **********************************************************************/
795 void do_not_remove_this_dummy_function (void)
797 (void) class_nextMethodList (NULL, NULL);
800 /***********************************************************************
801 * class_nextMethodList.
804 * void * iterator = 0;
805 * while (class_nextMethodList (cls, &iterator)) {...}
806 **********************************************************************/
807 OBJC_EXPORT struct objc_method_list * class_nextMethodList (Class cls,
810 return _class_inlinedNextMethodList(cls, it);
813 /***********************************************************************
815 **********************************************************************/
818 (void) class_nextMethodList (Nil, NULL);
821 /***********************************************************************
824 * Formerly class_addInstanceMethods ()
825 **********************************************************************/
826 void class_addMethods (Class cls,
827 struct objc_method_list * meths)
829 // Insert atomically.
830 _objc_insertMethods (meths, &((struct objc_class *) cls)->methodLists);
832 // Must flush when dynamically adding methods. No need to flush
833 // all the class method caches. If cls is a meta class, though,
834 // this will still flush it and any of its sub-meta classes.
835 flush_caches (cls, NO);
838 /***********************************************************************
839 * class_addClassMethods.
841 * Obsolete (for binary compatibility only).
842 **********************************************************************/
843 void class_addClassMethods (Class cls,
844 struct objc_method_list * meths)
846 class_addMethods (((struct objc_class *) cls)->isa, meths);
849 /***********************************************************************
850 * class_removeMethods.
851 **********************************************************************/
852 void class_removeMethods (Class cls,
853 struct objc_method_list * meths)
855 // Remove atomically.
856 _objc_removeMethods (meths, &((struct objc_class *) cls)->methodLists);
858 // Must flush when dynamically removing methods. No need to flush
859 // all the class method caches. If cls is a meta class, though,
860 // this will still flush it and any of its sub-meta classes.
861 flush_caches (cls, NO);
864 /***********************************************************************
865 * addClassToOriginalClass. Add to a hash table of classes involved in
866 * a posing situation. We use this when we need to get to the "original"
867 * class for some particular name through the function objc_getOrigClass.
868 * For instance, the implementation of [super ...] will use this to be
869 * sure that it gets hold of the correct super class, so that no infinite
870 * loops will occur if the class it appears in is involved in posing.
872 * We use the classLock to guard the hash table.
874 * See tracker bug #51856.
875 **********************************************************************/
877 static NXMapTable * posed_class_hash = NULL;
878 static NXMapTable * posed_class_to_original_class_hash = NULL;
880 static void addClassToOriginalClass (Class posingClass,
883 // Install hash table when it is first needed
884 if (!posed_class_to_original_class_hash)
886 posed_class_to_original_class_hash =
887 NXCreateMapTableFromZone (NXPtrValueMapPrototype,
889 _objc_create_zone ());
892 // Add pose to hash table
893 NXMapInsert (posed_class_to_original_class_hash,
898 /***********************************************************************
899 * getOriginalClassForPosingClass.
900 **********************************************************************/
901 Class getOriginalClassForPosingClass (Class posingClass)
903 return NXMapGet (posed_class_to_original_class_hash, posingClass);
906 /***********************************************************************
908 **********************************************************************/
909 Class objc_getOrigClass (const char * name)
911 struct objc_class * ret;
913 // Look for class among the posers
915 OBJC_LOCK(&classLock);
916 if (posed_class_hash)
917 ret = (Class) NXMapGet (posed_class_hash, name);
918 OBJC_UNLOCK(&classLock);
922 // Not a poser. Do a normal lookup.
923 ret = objc_getClass (name);
925 _objc_inform ("class `%s' not linked into application", name);
930 /***********************************************************************
931 * _objc_addOrigClass. This function is only used from class_poseAs.
932 * Registers the original class names, before they get obscured by
933 * posing, so that [super ..] will work correctly from categories
934 * in posing classes and in categories in classes being posed for.
935 **********************************************************************/
936 static void _objc_addOrigClass (Class origClass)
938 OBJC_LOCK(&classLock);
940 // Create the poser's hash table on first use
941 if (!posed_class_hash)
943 posed_class_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype,
945 _objc_create_zone ());
948 // Add the named class iff it is not already there (or collides?)
949 if (NXMapGet (posed_class_hash, ((struct objc_class *)origClass)->name) == 0)
950 NXMapInsert (posed_class_hash, ((struct objc_class *)origClass)->name, origClass);
952 OBJC_UNLOCK(&classLock);
955 /***********************************************************************
958 * !!! class_poseAs () does not currently flush any caches.
959 **********************************************************************/
960 Class class_poseAs (Class imposter,
963 struct objc_class * clsObject;
964 char imposterName[256];
965 char * imposterNamePtr;
966 NXHashTable * class_hash;
968 struct objc_class * copy;
969 #ifdef OBJC_CLASS_REFS
971 unsigned int hdrCount;
972 header_info * hdrVector;
974 // Get these now before locking, to minimize impact
975 hdrCount = _objc_headerCount ();
976 hdrVector = _objc_headerVector (NULL);
979 // Trivial case is easy
980 if (imposter == original)
983 // Imposter must be an immediate subclass of the original
984 if (((struct objc_class *)imposter)->super_class != original)
985 return (Class) [(id) imposter error:_errNotSuper,
986 ((struct objc_class *)imposter)->name, ((struct objc_class *)original)->name];
988 // Can't pose when you have instance variables (how could it work?)
989 if (((struct objc_class *)imposter)->ivars)
990 return (Class) [(id) imposter error:_errNewVars, ((struct objc_class *)imposter)->name,
991 ((struct objc_class *)original)->name, ((struct objc_class *)imposter)->name];
993 // Build a string to use to replace the name of the original class.
994 strcpy (imposterName, "_%");
995 strcat (imposterName, ((struct objc_class *)original)->name);
996 imposterNamePtr = objc_malloc (strlen (imposterName)+1);
997 strcpy (imposterNamePtr, imposterName);
999 // We lock the class hashtable, so we are thread safe with respect to
1000 // calls to objc_getClass (). However, the class names are not
1001 // changed atomically, nor are all of the subclasses updated
1002 // atomically. I have ordered the operations so that you will
1003 // never crash, but you may get inconsistent results....
1005 // Register the original class so that [super ..] knows
1006 // exactly which classes are the "original" classes.
1007 _objc_addOrigClass (original);
1008 _objc_addOrigClass (imposter);
1010 OBJC_LOCK(&classLock);
1012 class_hash = objc_getClasses ();
1014 // Remove both the imposter and the original class.
1015 NXHashRemove (class_hash, imposter);
1016 NXHashRemove (class_hash, original);
1018 // Copy the imposter, so that the imposter can continue
1019 // its normal life in addition to changing the behavior of
1020 // the original. As a hack we don't bother to copy the metaclass.
1021 // For some reason we modify the original rather than the copy.
1022 copy = (*_zoneAlloc)(imposter->isa, sizeof(struct objc_class), _objc_create_zone());
1023 memmove(copy, imposter, sizeof(struct objc_class));
1025 NXHashInsert (class_hash, copy);
1026 addClassToOriginalClass (imposter, copy);
1028 // Mark the imposter as such
1029 CLS_SETINFO(((struct objc_class *)imposter), CLS_POSING);
1030 CLS_SETINFO(((struct objc_class *)imposter)->isa, CLS_POSING);
1032 // Change the name of the imposter to that of the original class.
1033 ((struct objc_class *)imposter)->name = ((struct objc_class *)original)->name;
1034 ((struct objc_class *)imposter)->isa->name = ((struct objc_class *)original)->isa->name;
1036 // Also copy the version field to avoid archiving problems.
1037 ((struct objc_class *)imposter)->version = ((struct objc_class *)original)->version;
1039 // Change all subclasses of the original to point to the imposter.
1040 state = NXInitHashState (class_hash);
1041 while (NXNextHashState (class_hash, &state, (void **) &clsObject))
1043 while ((clsObject) && (clsObject != imposter) &&
1044 (clsObject != copy))
1046 if (clsObject->super_class == original)
1048 clsObject->super_class = imposter;
1049 clsObject->isa->super_class = ((struct objc_class *)imposter)->isa;
1050 // We must flush caches here!
1054 clsObject = clsObject->super_class;
1058 #ifdef OBJC_CLASS_REFS
1059 // Replace the original with the imposter in all class refs
1060 // Major loop - process all headers
1061 for (hidx = 0; hidx < hdrCount; hidx += 1)
1064 unsigned int refCount;
1067 // Get refs associated with this header
1068 cls_refs = (Class *) _getObjcClassRefs ((headerType *) hdrVector[hidx].mhdr, &refCount);
1069 if (!cls_refs || !refCount)
1072 // Minor loop - process this header's refs
1073 cls_refs = (Class *) ((unsigned long) cls_refs + hdrVector[hidx].image_slide);
1074 for (index = 0; index < refCount; index += 1)
1076 if (cls_refs[index] == original)
1077 cls_refs[index] = imposter;
1080 #endif // OBJC_CLASS_REFS
1082 // Change the name of the original class.
1083 ((struct objc_class *)original)->name = imposterNamePtr + 1;
1084 ((struct objc_class *)original)->isa->name = imposterNamePtr;
1086 // Restore the imposter and the original class with their new names.
1087 NXHashInsert (class_hash, imposter);
1088 NXHashInsert (class_hash, original);
1090 OBJC_UNLOCK(&classLock);
1095 /***********************************************************************
1097 **********************************************************************/
1098 static void _freedHandler (id self,
1101 __objc_error (self, _errFreedObject, SELNAME(sel), self);
1104 /***********************************************************************
1105 * _nonexistentHandler.
1106 **********************************************************************/
1107 static void _nonexistentHandler (id self,
1110 __objc_error (self, _errNonExistentObject, SELNAME(sel), self);
1113 /***********************************************************************
1114 * class_initialize. Send the 'initialize' message on demand to any
1115 * uninitialized class. Force initialization of superclasses first.
1117 * Called only from _class_lookupMethodAndLoadCache (or itself).
1119 * #ifdef OBJC_COLLECTING_CACHE
1120 * The messageLock can be in either state.
1122 * The messageLock is already assumed to be taken out.
1123 * It is temporarily released while the initialize method is sent.
1125 **********************************************************************/
1126 static void class_initialize (Class clsDesc)
1128 struct objc_class * super;
1130 // Skip if someone else beat us to it
1131 if (ISINITIALIZED(((struct objc_class *)clsDesc)))
1134 // Force initialization of superclasses first
1135 super = ((struct objc_class *)clsDesc)->super_class;
1136 if ((super != Nil) && (!ISINITIALIZED(super)))
1137 class_initialize (super);
1139 // Initializing the super class might have initialized us,
1140 // or another thread might have initialized us during this time.
1141 if (ISINITIALIZED(((struct objc_class *)clsDesc)))
1144 // Mark the class initialized so it can receive the "initialize"
1145 // message. This solution to the catch-22 is the source of a
1146 // bug: the class is able to receive messages *from anyone* now
1147 // that it is marked, even though initialization is not complete.
1148 MARKINITIALIZED(((struct objc_class *)clsDesc));
1150 #ifndef OBJC_COLLECTING_CACHE
1151 // Release the message lock so that messages can be sent.
1152 OBJC_UNLOCK(&messageLock);
1155 // Send the initialize method.
1156 [(id)clsDesc initialize];
1158 #ifndef OBJC_COLLECTING_CACHE
1159 // Re-acquire the lock
1160 OBJC_LOCK(&messageLock);
1166 /***********************************************************************
1167 * _class_install_relationships. Fill in the class pointers of a class
1168 * that was loaded before some or all of the classes it needs to point to.
1169 * The deal here is that the class pointer fields have been usurped to
1170 * hold the string name of the pertinent class. Our job is to look up
1171 * the real thing based on those stored names.
1172 **********************************************************************/
1173 void _class_install_relationships (Class cls,
1176 struct objc_class * meta;
1177 struct objc_class * clstmp;
1179 // Get easy access to meta class structure
1180 meta = ((struct objc_class *)cls)->isa;
1182 // Set version in meta class strucure
1183 meta->version = version;
1185 // Install superclass based on stored name. No name iff
1186 // cls is a root class.
1187 if (((struct objc_class *)cls)->super_class)
1189 clstmp = objc_getClass ((const char *) ((struct objc_class *)cls)->super_class);
1192 _objc_inform("failed objc_getClass(%s) for %s->super_class", (const char *)((struct objc_class *)cls)->super_class, ((struct objc_class *)cls)->name);
1196 ((struct objc_class *)cls)->super_class = clstmp;
1199 // Install meta's isa based on stored name. Meta class isa
1200 // pointers always point to the meta class of the root class
1201 // (root meta class, too, it points to itself!).
1202 clstmp = objc_getClass ((const char *) meta->isa);
1205 _objc_inform("failed objc_getClass(%s) for %s->isa->isa", (const char *) meta->isa, ((struct objc_class *)cls)->name);
1209 meta->isa = clstmp->isa;
1211 // Install meta's superclass based on stored name. No name iff
1212 // cls is a root class.
1213 if (meta->super_class)
1215 // Locate instance class of super class
1216 clstmp = objc_getClass ((const char *) meta->super_class);
1219 _objc_inform("failed objc_getClass(%s) for %s->isa->super_class", (const char *)meta->super_class, ((struct objc_class *)cls)->name);
1223 // Store meta class of super class
1224 meta->super_class = clstmp->isa;
1227 // cls is root, so `tie' the (root) meta class down to its
1228 // instance class. This way, class methods can come from
1229 // the root instance class.
1231 ((struct objc_class *)meta)->super_class = cls;
1233 // Use common static empty cache instead of NULL
1234 if (((struct objc_class *)cls)->cache == NULL)
1235 ((struct objc_class *)cls)->cache = (Cache) &emptyCache;
1236 if (((struct objc_class *)meta)->cache == NULL)
1237 ((struct objc_class *)meta)->cache = (Cache) &emptyCache;
1242 _objc_fatal ("please link appropriate classes in your program");
1245 /***********************************************************************
1247 **********************************************************************/
1248 static void * objc_malloc (int byteCount)
1252 space = malloc_zone_malloc (_objc_create_zone (), byteCount);
1253 if (!space && byteCount)
1254 _objc_fatal ("unable to allocate space");
1257 bzero (space, byteCount);
1264 /***********************************************************************
1265 * class_respondsToMethod.
1267 * Called from -[Object respondsTo:] and +[Object instancesRespondTo:]
1268 **********************************************************************/
1269 BOOL class_respondsToMethod (Class cls,
1272 struct objc_class * thisCls;
1278 // No one responds to zero!
1282 // Synchronize access to caches
1283 OBJC_LOCK(&messageLock);
1285 // Look in the cache of the specified class
1286 mask = ((struct objc_class *)cls)->cache->mask;
1287 buckets = ((struct objc_class *)cls)->cache->buckets;
1288 index = ((uarith_t) sel & mask);
1289 while (CACHE_BUCKET_VALID(buckets[index])) {
1290 if (CACHE_BUCKET_NAME(buckets[index]) == sel) {
1291 if (CACHE_BUCKET_IMP(buckets[index]) == &_objc_msgForward) {
1292 OBJC_UNLOCK(&messageLock);
1295 OBJC_UNLOCK(&messageLock);
1304 // Handle cache miss
1305 meth = _getMethod(cls, sel);
1307 OBJC_UNLOCK(&messageLock);
1308 _cache_fill (cls, meth, sel);
1312 // Not implememted. Use _objc_msgForward.
1316 smt = malloc_zone_malloc (_objc_create_zone(), sizeof(struct objc_method));
1317 smt->method_name = sel;
1318 smt->method_types = "";
1319 smt->method_imp = &_objc_msgForward;
1320 _cache_fill (cls, smt, sel);
1323 OBJC_UNLOCK(&messageLock);
1329 /***********************************************************************
1330 * class_lookupMethod.
1332 * Called from -[Object methodFor:] and +[Object instanceMethodFor:]
1333 **********************************************************************/
1335 IMP class_lookupMethod (Class cls,
1343 // No one responds to zero!
1345 [(id) cls error:_errBadSel, sel];
1347 // Synchronize access to caches
1348 OBJC_LOCK(&messageLock);
1351 mask = ((struct objc_class *)cls)->cache->mask;
1352 buckets = ((struct objc_class *)cls)->cache->buckets;
1353 index = ((unsigned int) sel & mask);
1354 while (CACHE_BUCKET_VALID(buckets[index]))
1356 if (CACHE_BUCKET_NAME(buckets[index]) == sel)
1358 result = CACHE_BUCKET_IMP(buckets[index]);
1359 OBJC_UNLOCK(&messageLock);
1367 // Handle cache miss
1368 result = _class_lookupMethodAndLoadCache (cls, sel);
1369 OBJC_UNLOCK(&messageLock);
1373 /***********************************************************************
1374 * class_lookupMethodInMethodList.
1376 * Called from objc-load.m and _objc_callLoads ()
1377 **********************************************************************/
1378 IMP class_lookupMethodInMethodList (struct objc_method_list * mlist,
1381 Method m = _findMethodInList(mlist, sel);
1382 return (m ? m->method_imp : NULL);
1385 IMP class_lookupNamedMethodInMethodList(struct objc_method_list *mlist,
1386 const char *meth_name)
1388 Method m = meth_name ? _findNamedMethodInList(mlist, meth_name) : NULL;
1389 return (m ? m->method_imp : NULL);
1392 /***********************************************************************
1395 * Called from _cache_expand () and objc_addClass ()
1396 **********************************************************************/
1397 Cache _cache_create (Class cls)
1403 // Select appropriate size
1404 slotCount = (ISMETA(cls)) ? INIT_META_CACHE_SIZE : INIT_CACHE_SIZE;
1406 // Allocate table (why not check for failure?)
1407 #ifdef OBJC_INSTRUMENTED
1408 new_cache = malloc_zone_malloc (_objc_create_zone(),
1409 sizeof(struct objc_cache) + TABLE_SIZE(slotCount)
1410 + sizeof(CacheInstrumentation));
1412 new_cache = malloc_zone_malloc (_objc_create_zone(),
1413 sizeof(struct objc_cache) + TABLE_SIZE(slotCount));
1416 // Invalidate all the buckets
1417 for (index = 0; index < slotCount; index += 1)
1418 CACHE_BUCKET_VALID(new_cache->buckets[index]) = NULL;
1420 // Zero the valid-entry counter
1421 new_cache->occupied = 0;
1423 // Set the mask so indexing wraps at the end-of-table
1424 new_cache->mask = slotCount - 1;
1426 #ifdef OBJC_INSTRUMENTED
1428 CacheInstrumentation * cacheData;
1430 // Zero out the cache dynamic instrumention data
1431 cacheData = CACHE_INSTRUMENTATION(new_cache);
1432 bzero ((char *) cacheData, sizeof(CacheInstrumentation));
1436 // Install the cache
1437 ((struct objc_class *)cls)->cache = new_cache;
1439 // Clear the cache flush flag so that we will not flush this cache
1440 // before expanding it for the first time.
1441 ((struct objc_class * )cls)->info &= ~(CLS_FLUSH_CACHE);
1443 // Clear the grow flag so that we will re-use the current storage,
1444 // rather than actually grow the cache, when expanding the cache
1445 // for the first time
1446 if (_class_slow_grow)
1447 ((struct objc_class * )cls)->info &= ~(CLS_GROW_CACHE);
1449 // Return our creation
1453 /***********************************************************************
1456 * #ifdef OBJC_COLLECTING_CACHE
1457 * The cacheUpdateLock is assumed to be taken at this point.
1460 * Called from _cache_fill ()
1461 **********************************************************************/
1462 static Cache _cache_expand (Class cls)
1466 unsigned int slotCount;
1469 // First growth goes from emptyCache to a real one
1470 old_cache = ((struct objc_class *)cls)->cache;
1471 if (old_cache == &emptyCache)
1472 return _cache_create (cls);
1474 // iff _class_slow_grow, trade off actual cache growth with re-using
1475 // the current one, so that growth only happens every odd time
1476 if (_class_slow_grow)
1478 // CLS_GROW_CACHE controls every-other-time behavior. If it
1479 // is non-zero, let the cache grow this time, but clear the
1480 // flag so the cache is reused next time
1481 if ((((struct objc_class * )cls)->info & CLS_GROW_CACHE) != 0)
1482 ((struct objc_class * )cls)->info &= ~CLS_GROW_CACHE;
1484 // Reuse the current cache storage this time
1487 // Clear the valid-entry counter
1488 old_cache->occupied = 0;
1490 // Invalidate all the cache entries
1491 for (index = 0; index < old_cache->mask + 1; index += 1)
1493 // Remember what this entry was, so we can possibly
1494 // deallocate it after the bucket has been invalidated
1495 Method oldEntry = old_cache->buckets[index];
1496 // Skip invalid entry
1497 if (!CACHE_BUCKET_VALID(old_cache->buckets[index]))
1500 // Invalidate this entry
1501 CACHE_BUCKET_VALID(old_cache->buckets[index]) = NULL;
1503 // Deallocate "forward::" entry
1504 if (CACHE_BUCKET_IMP(oldEntry) == &_objc_msgForward)
1506 #ifdef OBJC_COLLECTING_CACHE
1507 _cache_collect_free (oldEntry, NO);
1509 malloc_zone_free (_objc_create_zone(), oldEntry);
1514 // Set the slow growth flag so the cache is next grown
1515 ((struct objc_class * )cls)->info |= CLS_GROW_CACHE;
1517 // Return the same old cache, freshly emptied
1523 // Double the cache size
1524 slotCount = (old_cache->mask + 1) << 1;
1526 // Allocate a new cache table
1527 #ifdef OBJC_INSTRUMENTED
1528 new_cache = malloc_zone_malloc (_objc_create_zone(),
1529 sizeof(struct objc_cache) + TABLE_SIZE(slotCount)
1530 + sizeof(CacheInstrumentation));
1532 new_cache = malloc_zone_malloc (_objc_create_zone(),
1533 sizeof(struct objc_cache) + TABLE_SIZE(slotCount));
1536 // Zero out the new cache
1537 new_cache->mask = slotCount - 1;
1538 new_cache->occupied = 0;
1539 for (index = 0; index < slotCount; index += 1)
1540 CACHE_BUCKET_VALID(new_cache->buckets[index]) = NULL;
1542 #ifdef OBJC_INSTRUMENTED
1543 // Propagate the instrumentation data
1545 CacheInstrumentation * oldCacheData;
1546 CacheInstrumentation * newCacheData;
1548 oldCacheData = CACHE_INSTRUMENTATION(old_cache);
1549 newCacheData = CACHE_INSTRUMENTATION(new_cache);
1550 bcopy ((const char *)oldCacheData, (char *)newCacheData, sizeof(CacheInstrumentation));
1554 // iff _class_uncache, copy old cache entries into the new cache
1555 if (_class_uncache == 0)
1559 newMask = new_cache->mask;
1561 // Look at all entries in the old cache
1562 for (index = 0; index < old_cache->mask + 1; index += 1)
1566 // Skip invalid entry
1567 if (!CACHE_BUCKET_VALID(old_cache->buckets[index]))
1570 // Hash the old entry into the new table
1571 index2 = ((unsigned int) CACHE_BUCKET_NAME(old_cache->buckets[index]) & newMask);
1573 // Find an available spot, at or following the hashed spot;
1574 // Guaranteed to not infinite loop, because table has grown
1577 if (!CACHE_BUCKET_VALID(new_cache->buckets[index2]))
1579 new_cache->buckets[index2] = old_cache->buckets[index];
1587 // Account for the addition
1588 new_cache->occupied += 1;
1591 // Set the cache flush flag so that we will flush this cache
1592 // before expanding it again.
1593 ((struct objc_class * )cls)->info |= CLS_FLUSH_CACHE;
1596 // Deallocate "forward::" entries from the old cache
1599 for (index = 0; index < old_cache->mask + 1; index += 1)
1601 if (CACHE_BUCKET_VALID(old_cache->buckets[index]) &&
1602 CACHE_BUCKET_IMP(old_cache->buckets[index]) == &_objc_msgForward)
1604 #ifdef OBJC_COLLECTING_CACHE
1605 _cache_collect_free (old_cache->buckets[index], NO);
1607 malloc_zone_free (_objc_create_zone(), old_cache->buckets[index]);
1613 // Install new cache
1614 ((struct objc_class *)cls)->cache = new_cache;
1616 // Deallocate old cache, try freeing all the garbage
1617 #ifdef OBJC_COLLECTING_CACHE
1618 _cache_collect_free (old_cache, YES);
1620 malloc_zone_free (_objc_create_zone(), old_cache);
1625 /***********************************************************************
1626 * instrumentObjcMessageSends/logObjcMessageSends.
1627 **********************************************************************/
1628 static int LogObjCMessageSend (BOOL isClassMethod,
1629 const char * objectsClass,
1630 const char * implementingClass,
1635 // Create/open the log file
1636 if (objcMsgLogFD == (-1))
1638 sprintf (buf, "/tmp/msgSends-%d", (int) getpid ());
1639 objcMsgLogFD = open (buf, O_WRONLY | O_CREAT, 0666);
1642 // Make the log entry
1643 sprintf(buf, "%c %s %s %s\n",
1644 isClassMethod ? '+' : '-',
1649 write (objcMsgLogFD, buf, strlen(buf));
1651 // Tell caller to not cache the method
1655 void instrumentObjcMessageSends (BOOL flag)
1657 int enabledValue = (flag) ? 1 : 0;
1660 if (objcMsgLogEnabled == enabledValue)
1663 // If enabling, flush all method caches so we get some traces
1665 flush_caches (Nil, YES);
1667 // Sync our log file
1668 if (objcMsgLogFD != (-1))
1669 fsync (objcMsgLogFD);
1671 objcMsgLogEnabled = enabledValue;
1674 void logObjcMessageSends (ObjCLogProc logProc)
1678 objcMsgLogProc = logProc;
1679 objcMsgLogEnabled = 1;
1683 objcMsgLogProc = logProc;
1684 objcMsgLogEnabled = 0;
1687 if (objcMsgLogFD != (-1))
1688 fsync (objcMsgLogFD);
1691 /***********************************************************************
1692 * _cache_fill. Add the specified method to the specified class' cache.
1694 * Called only from _class_lookupMethodAndLoadCache and
1695 * class_respondsToMethod.
1697 * #ifdef OBJC_COLLECTING_CACHE
1698 * It doesn't matter if someone has the messageLock when we enter this
1699 * function. This function will fail to do the update if someone else
1700 * is already updating the cache, i.e. they have the cacheUpdateLock.
1702 * The messageLock is already assumed to be taken out.
1704 **********************************************************************/
1706 static void _cache_fill (Class cls,
1715 unsigned int newOccupied;
1717 // Keep tally of cache additions
1718 totalCacheFills += 1;
1720 #ifdef OBJC_COLLECTING_CACHE
1721 // Make sure only one thread is updating the cache at a time, but don't
1722 // wait for concurrent updater to finish, because it might be a while, or
1723 // a deadlock! Instead, just leave the method out of the cache until
1724 // next time. This is nasty given that cacheUpdateLock is per task!
1725 if (!OBJC_TRYLOCK(&cacheUpdateLock))
1728 // Set up invariants for cache traversals
1729 cache = ((struct objc_class *)cls)->cache;
1731 buckets = cache->buckets;
1733 // Check for duplicate entries, if we're in the mode
1734 if (traceDuplicates)
1739 for (index2 = 0; index2 < mask + 1; index2 += 1)
1741 // Skip invalid or non-duplicate entry
1742 if ((!CACHE_BUCKET_VALID(buckets[index2])) ||
1743 (strcmp ((char *) CACHE_BUCKET_NAME(buckets[index2]), (char *) smt->method_name) != 0))
1746 // Tally duplication, but report iff wanted
1747 cacheFillDuplicates += 1;
1748 if (traceDuplicatesVerbose)
1750 _objc_inform ("Cache fill duplicate #%d: found %x adding %x: %s\n",
1751 cacheFillDuplicates,
1752 (unsigned int) CACHE_BUCKET_NAME(buckets[index2]),
1753 (unsigned int) smt->method_name,
1754 (char *) smt->method_name);
1759 // Do nothing if entry is already placed. This re-check is needed
1760 // only in the OBJC_COLLECTING_CACHE code, because the probe is
1762 index = ((unsigned int) sel & mask);
1763 while (CACHE_BUCKET_VALID(buckets[index]))
1765 if (CACHE_BUCKET_NAME(buckets[index]) == sel)
1767 OBJC_UNLOCK(&cacheUpdateLock);
1775 #else // not OBJC_COLLECTING_CACHE
1776 cache = ((struct objc_class *)cls)->cache;
1780 // Use the cache as-is if it is less than 3/4 full
1781 newOccupied = cache->occupied + 1;
1782 if ((newOccupied * 4) <= (mask + 1) * 3)
1783 cache->occupied = newOccupied;
1785 // Cache is getting full
1789 if ((((struct objc_class * )cls)->info & CLS_FLUSH_CACHE) != 0)
1795 cache = _cache_expand (cls);
1799 // Account for the addition
1800 cache->occupied += 1;
1803 // Insert the new entry. This can be done by either:
1804 // (a) Scanning for the first unused spot. Easy!
1805 // (b) Opening up an unused spot by sliding existing
1806 // entries down by one. The benefit of this
1807 // extra work is that it puts the most recently
1808 // loaded entries closest to where the selector
1809 // hash starts the search.
1811 // The loop is a little more complicated because there
1812 // are two kinds of entries, so there have to be two ways
1814 buckets = cache->buckets;
1815 index = ((unsigned int) sel & mask);
1818 // Slide existing entries down by one
1821 // Copy current entry to a local
1822 saveMethod = buckets[index];
1824 // Copy previous entry (or new entry) to current slot
1825 buckets[index] = smt;
1827 // Done if current slot had been invalid
1828 if (saveMethod == NULL)
1831 // Prepare to copy saved value into next slot
1834 // Move on to next slot
1839 #ifdef OBJC_COLLECTING_CACHE
1840 OBJC_UNLOCK(&cacheUpdateLock);
1844 /***********************************************************************
1845 * _cache_flush. Invalidate all valid entries in the given class' cache,
1846 * and clear the CLS_FLUSH_CACHE in the cls->info.
1848 * Called from flush_caches ().
1849 **********************************************************************/
1850 static void _cache_flush (Class cls)
1855 // Locate cache. Ignore unused cache.
1856 cache = ((struct objc_class *)cls)->cache;
1857 if (cache == &emptyCache)
1860 #ifdef OBJC_INSTRUMENTED
1862 CacheInstrumentation * cacheData;
1865 cacheData = CACHE_INSTRUMENTATION(cache);
1866 cacheData->flushCount += 1;
1867 cacheData->flushedEntries += cache->occupied;
1868 if (cache->occupied > cacheData->maxFlushedEntries)
1869 cacheData->maxFlushedEntries = cache->occupied;
1873 // Traverse the cache
1874 for (index = 0; index <= cache->mask; index += 1)
1876 // Remember what this entry was, so we can possibly
1877 // deallocate it after the bucket has been invalidated
1878 Method oldEntry = cache->buckets[index];
1880 // Invalidate this entry
1881 CACHE_BUCKET_VALID(cache->buckets[index]) = NULL;
1883 // Deallocate "forward::" entry
1884 if (oldEntry && oldEntry->method_imp == &_objc_msgForward)
1885 #ifdef OBJC_COLLECTING_CACHE
1886 _cache_collect_free (oldEntry, NO);
1888 malloc_zone_free (_objc_create_zone(), oldEntry);
1892 // Clear the valid-entry counter
1893 cache->occupied = 0;
1895 // Clear the cache flush flag so that we will not flush this cache
1896 // before expanding it again.
1897 ((struct objc_class * )cls)->info &= ~CLS_FLUSH_CACHE;
1900 /***********************************************************************
1901 * _objc_getFreedObjectClass. Return a pointer to the dummy freed
1902 * object class. Freed objects get their isa pointers replaced with
1903 * a pointer to the freedObjectClass, so that we can catch usages of
1905 **********************************************************************/
1906 Class _objc_getFreedObjectClass (void)
1908 return (Class) &freedObjectClass;
1911 /***********************************************************************
1912 * _objc_getNonexistentClass. Return a pointer to the dummy nonexistent
1913 * object class. This is used when, for example, mapping the class
1914 * refs for an image, and the class can not be found, so that we can
1915 * catch later uses of the non-existent class.
1916 **********************************************************************/
1917 Class _objc_getNonexistentClass (void)
1919 return (Class) &nonexistentObjectClass;
1922 /***********************************************************************
1923 * _class_lookupMethodAndLoadCache.
1925 * Called only from objc_msgSend, objc_msgSendSuper and class_lookupMethod.
1926 **********************************************************************/
1927 IMP _class_lookupMethodAndLoadCache (Class cls,
1930 struct objc_class * curClass;
1932 BOOL calledSingleThreaded;
1935 ptrace(0xb300, 0, 0, 0);
1937 // Check for freed class
1938 if (cls == &freedObjectClass)
1939 return (IMP) _freedHandler;
1941 // Check for nonexistent class
1942 if (cls == &nonexistentObjectClass)
1943 return (IMP) _nonexistentHandler;
1945 #ifndef OBJC_COLLECTING_CACHE
1946 // Control can get here via the single-threaded message dispatcher,
1947 // but class_initialize can cause application to go multithreaded. Notice
1948 // whether this is the case, so we can leave the messageLock unlocked
1949 // on the way out, just as the single-threaded message dispatcher
1950 // expects. Note that the messageLock locking in classinitialize is
1951 // appropriate in this case, because there are more than one thread now.
1952 calledSingleThreaded = (_objc_multithread_mask != 0);
1955 ptrace(0xb301, 0, 0, 0);
1957 // Lazy initialization. This unlocks and relocks messageLock,
1958 // so cache information we might already have becomes invalid.
1959 if (!ISINITIALIZED(cls))
1960 class_initialize (objc_getClass (((struct objc_class *)cls)->name));
1962 ptrace(0xb302, 0, 0, 0);
1964 // Outer loop - search the caches and method lists of the
1965 // class and its super-classes
1967 for (curClass = cls; curClass; curClass = ((struct objc_class * )curClass)->super_class)
1972 arith_t methodCount;
1973 struct objc_method_list *mlist;
1975 #ifdef PRELOAD_SUPERCLASS_CACHES
1976 struct objc_class * curClass2;
1979 ptrace(0xb303, 0, 0, 0);
1981 mask = curClass->cache->mask;
1982 buckets = curClass->cache->buckets;
1984 // Minor loop #1 - check cache of given class
1985 for (idx = ((uarith_t) sel & mask);
1986 CACHE_BUCKET_VALID(buckets[idx]);
1987 idx = (++idx & mask))
1989 // Skip entries until selector matches
1990 if (CACHE_BUCKET_NAME(buckets[idx]) != sel)
1993 // Found the method. Add it to the cache(s)
1994 // unless it was found in the cache of the
1995 // class originally being messaged.
1997 // NOTE: The method is usually not found
1998 // the original class' cache, because
1999 // objc_msgSend () has already looked.
2000 // BUT, if sending this method resulted in
2001 // a +initialize on the class, and +initialize
2002 // sends the same method, the method will
2003 // indeed now be in the cache. Calling
2004 // _cache_fill with a buckets[idx] from the
2005 // cache being filled results in a crash
2006 // if the cache has to grow, because the
2007 // buckets[idx] address is no longer valid.
2008 if (curClass != cls)
2010 #ifdef PRELOAD_SUPERCLASS_CACHES
2011 for (curClass2 = cls; curClass2 != curClass; curClass2 = curClass2->super_class)
2012 _cache_fill (curClass2, buckets[idx], sel);
2013 _cache_fill (curClass, buckets[idx], sel);
2015 _cache_fill (cls, buckets[idx], sel);
2019 // Return the implementation address
2020 methodPC = CACHE_BUCKET_IMP(buckets[idx]);
2024 ptrace(0xb304, (int)methodPC, 0, 0);
2026 // Done if that found it
2030 smt = _findMethodInClass(curClass, sel);
2033 // If logging is enabled, log the message send and let
2034 // the logger decide whether to encache the method.
2035 if ((objcMsgLogEnabled == 0) ||
2036 (objcMsgLogProc (CLS_GETINFO(((struct objc_class * )curClass),CLS_META) ? YES : NO,
2037 ((struct objc_class *)cls)->name,
2038 curClass->name, sel)))
2040 // Cache the method implementation
2041 #ifdef PRELOAD_SUPERCLASS_CACHES
2042 for (curClass2 = cls; curClass2 != curClass; curClass2 = curClass2->super_class)
2043 _cache_fill (curClass2, smt, sel);
2044 _cache_fill (curClass, smt, sel);
2046 _cache_fill (cls, smt, sel);
2049 // Return the implementation
2050 methodPC = smt->method_imp;
2053 ptrace(0xb305, (int)methodPC, 0, 0);
2055 // Done if that found it
2060 ptrace(0xb306, (int)methodPC, 0, 0);
2062 if (methodPC == NULL)
2064 // Class and superclasses do not respond -- use forwarding
2065 smt = malloc_zone_malloc (_objc_create_zone(), sizeof(struct objc_method));
2066 smt->method_name = sel;
2067 smt->method_types = "";
2068 smt->method_imp = &_objc_msgForward;
2069 _cache_fill (cls, smt, sel);
2070 methodPC = &_objc_msgForward;
2073 #ifndef OBJC_COLLECTING_CACHE
2075 if (calledSingleThreaded)
2076 OBJC_UNLOCK(&messageLock);
2079 ptrace(0xb30f, (int)methodPC, 0, 0);
2084 /***********************************************************************
2088 **********************************************************************/
2089 static int SubtypeUntil (const char * type,
2093 const char * head = type;
2098 if (!*type || (!level && (*type == end)))
2099 return (int)(type - head);
2103 case ']': case '}': case ')': level--; break;
2104 case '[': case '{': case '(': level += 1; break;
2110 _objc_fatal ("Object: SubtypeUntil: end of type encountered prematurely\n");
2114 /***********************************************************************
2116 **********************************************************************/
2117 static const char * SkipFirstType (const char * type)
2123 case 'O': /* bycopy */
2126 case 'N': /* inout */
2127 case 'r': /* const */
2128 case 'V': /* oneway */
2129 case '^': /* pointers */
2134 while ((*type >= '0') && (*type <= '9'))
2136 return type + SubtypeUntil (type, ']') + 1;
2140 return type + SubtypeUntil (type, '}') + 1;
2144 return type + SubtypeUntil (type, ')') + 1;
2153 /***********************************************************************
2154 * method_getNumberOfArguments.
2155 **********************************************************************/
2156 unsigned method_getNumberOfArguments (Method method)
2158 const char * typedesc;
2161 // First, skip the return type
2162 typedesc = method->method_types;
2163 typedesc = SkipFirstType (typedesc);
2165 // Next, skip stack size
2166 while ((*typedesc >= '0') && (*typedesc <= '9'))
2169 // Now, we have the arguments - count how many
2173 // Traverse argument type
2174 typedesc = SkipFirstType (typedesc);
2176 // Traverse (possibly negative) argument offset
2177 if (*typedesc == '-')
2179 while ((*typedesc >= '0') && (*typedesc <= '9'))
2182 // Made it past an argument
2189 /***********************************************************************
2190 * method_getSizeOfArguments.
2191 **********************************************************************/
2193 unsigned method_getSizeOfArguments (Method method)
2195 const char * typedesc;
2196 unsigned stack_size;
2197 #if defined(__ppc__) || defined(ppc)
2198 unsigned trueBaseOffset;
2199 unsigned foundBaseOffset;
2202 // Get our starting points
2204 typedesc = method->method_types;
2206 // Skip the return type
2207 #if defined (__ppc__) || defined(ppc)
2208 // Struct returns cause the parameters to be bumped
2209 // by a register, so the offset to the receiver is
2210 // 4 instead of the normal 0.
2211 trueBaseOffset = (*typedesc == '{') ? 4 : 0;
2213 typedesc = SkipFirstType (typedesc);
2215 // Convert ASCII number string to integer
2216 while ((*typedesc >= '0') && (*typedesc <= '9'))
2217 stack_size = (stack_size * 10) + (*typedesc++ - '0');
2218 #if defined (__ppc__) || defined(ppc)
2219 // NOTE: This is a temporary measure pending a compiler fix.
2220 // Work around PowerPC compiler bug wherein the method argument
2221 // string contains an incorrect value for the "stack size."
2222 // Generally, the size is reported 4 bytes too small, so we apply
2223 // that fudge factor. Unfortunately, there is at least one case
2224 // where the error is something other than -4: when the last
2225 // parameter is a double, the reported stack is much too high
2226 // (about 32 bytes). We do not attempt to detect that case.
2227 // The result of returning a too-high value is that objc_msgSendv
2228 // can bus error if the destination of the marg_list copying
2229 // butts up against excluded memory.
2230 // This fix disables itself when it sees a correctly built
2231 // type string (i.e. the offset for the Id is correct). This
2232 // keeps us out of lockstep with the compiler.
2234 // skip the '@' marking the Id field
2235 typedesc = SkipFirstType (typedesc);
2237 // pick up the offset for the Id field
2238 foundBaseOffset = 0;
2239 while ((*typedesc >= '0') && (*typedesc <= '9'))
2240 foundBaseOffset = (foundBaseOffset * 10) + (*typedesc++ - '0');
2242 // add fudge factor iff the Id field offset was wrong
2243 if (foundBaseOffset != trueBaseOffset)
2251 // XXX Getting the size of a type is done all over the place
2252 // (Here, Foundation, remote project)! - Should unify
2254 unsigned int getSizeOfType (const char * type, unsigned int * alignPtr);
2256 unsigned method_getSizeOfArguments (Method method)
2263 unsigned stack_size;
2266 nargs = method_getNumberOfArguments (method);
2267 stack_size = (*method->method_types == '{') ? sizeof(void *) : 0;
2269 for (index = 0; index < nargs; index += 1)
2271 (void) method_getArgumentInfo (method, index, &type, &offset);
2272 size = getSizeOfType (type, &align);
2273 stack_size += ((size + 7) & ~7);
2280 /***********************************************************************
2281 * method_getArgumentInfo.
2282 **********************************************************************/
2283 unsigned method_getArgumentInfo (Method method,
2288 const char * typedesc = method->method_types;
2290 unsigned self_offset = 0;
2291 BOOL offset_is_negative = NO;
2293 // First, skip the return type
2294 typedesc = SkipFirstType (typedesc);
2296 // Next, skip stack size
2297 while ((*typedesc >= '0') && (*typedesc <= '9'))
2300 // Now, we have the arguments - position typedesc to the appropriate argument
2301 while (*typedesc && nargs != arg)
2304 // Skip argument type
2305 typedesc = SkipFirstType (typedesc);
2309 // Skip negative sign in offset
2310 if (*typedesc == '-')
2312 offset_is_negative = YES;
2316 offset_is_negative = NO;
2318 while ((*typedesc >= '0') && (*typedesc <= '9'))
2319 self_offset = self_offset * 10 + (*typedesc++ - '0');
2320 if (offset_is_negative)
2321 self_offset = -(self_offset);
2327 // Skip (possibly negative) argument offset
2328 if (*typedesc == '-')
2330 while ((*typedesc >= '0') && (*typedesc <= '9'))
2339 unsigned arg_offset = 0;
2342 typedesc = SkipFirstType (typedesc);
2347 *offset = -sizeof(id);
2355 // Pick up (possibly negative) argument offset
2356 if (*typedesc == '-')
2358 offset_is_negative = YES;
2362 offset_is_negative = NO;
2364 while ((*typedesc >= '0') && (*typedesc <= '9'))
2365 arg_offset = arg_offset * 10 + (*typedesc++ - '0');
2366 if (offset_is_negative)
2367 arg_offset = - arg_offset;
2370 // For stacks which grow up, since margs points
2371 // to the top of the stack or the END of the args,
2372 // the first offset is at -sizeof(id) rather than 0.
2373 self_offset += sizeof(id);
2375 *offset = arg_offset - self_offset;
2389 /***********************************************************************
2390 * _objc_create_zone.
2391 **********************************************************************/
2393 void * _objc_create_zone (void)
2395 static void *_objc_z = (void *)0xffffffff;
2396 if ( _objc_z == (void *)0xffffffff ) {
2397 char *s = getenv("OBJC_USE_OBJC_ZONE");
2399 if ( (*s == '1') || (*s == 'y') || (*s == 'Y') ) {
2400 _objc_z = malloc_create_zone(vm_page_size, 0);
2401 malloc_set_zone_name(_objc_z, "ObjC");
2404 if ( _objc_z == (void *)0xffffffff ) {
2405 _objc_z = malloc_default_zone();
2411 /***********************************************************************
2413 **********************************************************************/
2414 #ifdef OBJC_COLLECTING_CACHE
2416 static unsigned long _get_pc_for_thread (mach_port_t thread)
2419 struct hp_pa_frame_thread_state state;
2420 unsigned int count = HPPA_FRAME_THREAD_STATE_COUNT;
2421 thread_get_state (thread, HPPA_FRAME_THREAD_STATE, (thread_state_t)&state, &count);
2422 return state.ts_pcoq_front;
2424 #elif defined(sparc)
2426 struct sparc_thread_state_regs state;
2427 unsigned int count = SPARC_THREAD_STATE_REGS_COUNT;
2428 thread_get_state (thread, SPARC_THREAD_STATE_REGS, (thread_state_t)&state, &count);
2429 return state.regs.r_pc;
2431 #elif defined(__i386__) || defined(i386)
2433 i386_thread_state_t state;
2434 unsigned int count = i386_THREAD_STATE_COUNT;
2435 thread_get_state (thread, i386_THREAD_STATE, (thread_state_t)&state, &count);
2440 struct m68k_thread_state_regs state;
2441 unsigned int count = M68K_THREAD_STATE_REGS_COUNT;
2442 thread_get_state (thread, M68K_THREAD_STATE_REGS, (thread_state_t)&state, &count);
2445 #elif defined(__ppc__) || defined(ppc)
2447 struct ppc_thread_state state;
2448 unsigned int count = PPC_THREAD_STATE_COUNT;
2449 thread_get_state (thread, PPC_THREAD_STATE, (thread_state_t)&state, &count);
2454 #error _get_pc_for_thread () not implemented for this architecture
2458 /***********************************************************************
2459 * _collecting_in_critical.
2460 **********************************************************************/
2461 OBJC_EXPORT unsigned long objc_entryPoints[];
2462 OBJC_EXPORT unsigned long objc_exitPoints[];
2464 static int _collecting_in_critical (void)
2466 thread_act_port_array_t threads;
2471 mach_port_t mythread = pthread_mach_thread_np(pthread_self());
2473 // Get a list of all the threads in the current task
2474 ret = task_threads (mach_task_self (), &threads, &number);
2475 if (ret != KERN_SUCCESS)
2477 _objc_inform ("objc: task_thread failed\n");
2481 // Check whether any thread is in the cache lookup code
2483 for (count = 0; !result && (count < number); count += 1)
2488 // Don't bother checking ourselves
2489 if (threads[count] == mythread)
2492 // Find out where thread is executing
2493 pc = _get_pc_for_thread (threads[count]);
2495 // Check whether it is in the cache lookup code
2496 for (region = 0; !result && (objc_entryPoints[region] != 0); region += 1)
2498 if ((pc >= objc_entryPoints[region]) &&
2499 (pc <= objc_exitPoints[region]))
2503 // Deallocate the port rights for the threads
2504 for (count = 0; count < number; count++) {
2505 mach_port_deallocate(mach_task_self (), threads[count]);
2508 // Deallocate the thread list
2509 vm_deallocate (mach_task_self (), (vm_address_t) threads, sizeof(threads) * number);
2511 // Return our finding
2515 /***********************************************************************
2516 * _garbage_make_room. Ensure that there is enough room for at least
2517 * one more ref in the garbage.
2518 **********************************************************************/
2520 // amount of memory represented by all refs in the garbage
2521 static int garbage_byte_size = 0;
2523 // do not empty the garbage until garbage_byte_size gets at least this big
2524 static int garbage_threshold = 1024;
2526 // table of refs to free
2527 static void **garbage_refs = 0;
2529 // current number of refs in garbage_refs
2530 static int garbage_count = 0;
2532 // capacity of current garbage_refs
2533 static int garbage_max = 0;
2535 // capacity of initial garbage_refs
2537 INIT_GARBAGE_COUNT = 128
2540 static void _garbage_make_room (void)
2542 static int first = 1;
2543 volatile void * tempGarbage;
2545 // Create the collection table the first time it is needed
2549 garbage_refs = malloc_zone_malloc (_objc_create_zone(),
2550 INIT_GARBAGE_COUNT * sizeof(void *));
2551 garbage_max = INIT_GARBAGE_COUNT;
2554 // Double the table if it is full
2555 else if (garbage_count == garbage_max)
2557 tempGarbage = malloc_zone_realloc ((void *) _objc_create_zone(),
2558 (void *) garbage_refs,
2559 (size_t) garbage_max * 2 * sizeof(void *));
2560 garbage_refs = (void **) tempGarbage;
2565 /***********************************************************************
2566 * _cache_collect_free. Add the specified malloc'd memory to the list
2567 * of them to free at some later point.
2568 **********************************************************************/
2569 static void _cache_collect_free (void * data,
2572 static char *report_garbage = (char *)0xffffffff;
2574 if ((char *)0xffffffff == report_garbage) {
2575 // Check whether to log our activity
2576 report_garbage = getenv ("OBJC_REPORT_GARBAGE");
2580 OBJC_LOCK(&cacheCollectionLock);
2582 // Insert new element in garbage list
2583 // Note that we do this even if we end up free'ing everything
2584 _garbage_make_room ();
2585 garbage_byte_size += malloc_size (data);
2586 garbage_refs[garbage_count++] = data;
2589 if (tryCollect && report_garbage)
2590 _objc_inform ("total of %d bytes of garbage ...", garbage_byte_size);
2592 // Done if caller says not to empty or the garbage is not full
2593 if (!tryCollect || (garbage_byte_size < garbage_threshold))
2595 OBJC_UNLOCK(&cacheCollectionLock);
2596 if (tryCollect && report_garbage)
2597 _objc_inform ("below threshold\n");
2602 // Synchronize garbage collection with messageLock holders
2603 if (OBJC_TRYLOCK(&messageLock))
2605 // Synchronize garbage collection with cache lookers
2606 if (!_collecting_in_critical ())
2609 if (tryCollect && report_garbage)
2610 _objc_inform ("collecting!\n");
2612 // Dispose all refs now in the garbage
2613 while (garbage_count)
2614 free (garbage_refs[--garbage_count]);
2616 // Clear the total size indicator
2617 garbage_byte_size = 0;
2620 // Someone is actively looking in the cache
2621 else if (tryCollect && report_garbage)
2622 _objc_inform ("in critical region\n");
2624 OBJC_UNLOCK(&messageLock);
2627 // Someone already holds messageLock
2628 else if (tryCollect && report_garbage)
2629 _objc_inform ("messageLock taken\n");
2631 OBJC_UNLOCK(&cacheCollectionLock);
2633 #endif // OBJC_COLLECTING_CACHE
2636 /***********************************************************************
2638 **********************************************************************/
2639 static void _cache_print (Cache cache)
2644 count = cache->mask + 1;
2645 for (index = 0; index < count; index += 1)
2646 if (CACHE_BUCKET_VALID(cache->buckets[index]))
2648 if (CACHE_BUCKET_IMP(cache->buckets[index]) == &_objc_msgForward)
2649 printf ("does not recognize: \n");
2650 printf ("%s\n", (const char *) CACHE_BUCKET_NAME(cache->buckets[index]));
2654 /***********************************************************************
2655 * _class_printMethodCaches.
2656 **********************************************************************/
2657 void _class_printMethodCaches (Class cls)
2659 if (((struct objc_class *)cls)->cache == &emptyCache)
2660 printf ("no instance-method cache for class %s\n", ((struct objc_class *)cls)->name);
2664 printf ("instance-method cache for class %s:\n", ((struct objc_class *)cls)->name);
2665 _cache_print (((struct objc_class *)cls)->cache);
2668 if (((struct objc_class * )((struct objc_class * )cls)->isa)->cache == &emptyCache)
2669 printf ("no class-method cache for class %s\n", ((struct objc_class *)cls)->name);
2673 printf ("class-method cache for class %s:\n", ((struct objc_class *)cls)->name);
2674 _cache_print (((struct objc_class * )((struct objc_class * )cls)->isa)->cache);
2678 /***********************************************************************
2680 **********************************************************************/
2681 static unsigned int log2 (unsigned int x)
2692 /***********************************************************************
2693 * _class_printDuplicateCacheEntries.
2694 **********************************************************************/
2695 void _class_printDuplicateCacheEntries (BOOL detail)
2697 NXHashTable * class_hash;
2699 struct objc_class * cls;
2700 unsigned int duplicates;
2701 unsigned int index1;
2702 unsigned int index2;
2705 unsigned int isMeta;
2709 printf ("Checking for duplicate cache entries \n");
2711 // Outermost loop - iterate over all classes
2712 class_hash = objc_getClasses ();
2713 state = NXInitHashState (class_hash);
2715 while (NXNextHashState (class_hash, &state, (void **) &cls))
2717 // Control loop - do given class' cache, then its isa's cache
2718 for (isMeta = 0; isMeta <= 1; isMeta += 1)
2720 // Select cache of interest and make sure it exists
2721 cache = isMeta ? cls->isa->cache : ((struct objc_class *)cls)->cache;
2722 if (cache == &emptyCache)
2725 // Middle loop - check each entry in the given cache
2728 for (index1 = 0; index1 < count; index1 += 1)
2730 // Skip invalid entry
2731 if (!CACHE_BUCKET_VALID(cache->buckets[index1]))
2734 // Inner loop - check that given entry matches no later entry
2735 for (index2 = index1 + 1; index2 < count; index2 += 1)
2737 // Skip invalid entry
2738 if (!CACHE_BUCKET_VALID(cache->buckets[index2]))
2741 // Check for duplication by method name comparison
2742 if (strcmp ((char *) CACHE_BUCKET_NAME(cache->buckets[index1]),
2743 (char *) CACHE_BUCKET_NAME(cache->buckets[index2])) == 0)
2746 printf ("%s %s\n", ((struct objc_class *)cls)->name, (char *) CACHE_BUCKET_NAME(cache->buckets[index1]));
2756 printf ("duplicates = %d\n", duplicates);
2757 printf ("total cache fills = %d\n", totalCacheFills);
2760 /***********************************************************************
2762 **********************************************************************/
2763 static void PrintCacheHeader (void)
2765 #ifdef OBJC_INSTRUMENTED
2766 printf ("Cache Cache Slots Avg Max AvgS MaxS AvgS MaxS TotalD AvgD MaxD TotalD AvgD MaxD TotD AvgD MaxD\n");
2767 printf ("Size Count Used Used Used Hit Hit Miss Miss Hits Prbs Prbs Misses Prbs Prbs Flsh Flsh Flsh\n");
2768 printf ("----- ----- ----- ----- ---- ---- ---- ---- ---- ------- ---- ---- ------- ---- ---- ---- ---- ----\n");
2770 printf ("Cache Cache Slots Avg Max AvgS MaxS AvgS MaxS\n");
2771 printf ("Size Count Used Used Used Hit Hit Miss Miss\n");
2772 printf ("----- ----- ----- ----- ---- ---- ---- ---- ----\n");
2776 /***********************************************************************
2778 **********************************************************************/
2779 static void PrintCacheInfo (unsigned int cacheSize,
2780 unsigned int cacheCount,
2781 unsigned int slotsUsed,
2783 unsigned int maxUsed,
2785 unsigned int maxSHit,
2787 unsigned int maxSMiss
2788 #ifdef OBJC_INSTRUMENTED
2789 , unsigned int totDHits,
2791 unsigned int maxDHit,
2792 unsigned int totDMisses,
2794 unsigned int maxDMiss,
2795 unsigned int totDFlsh,
2797 unsigned int maxDFlsh
2801 #ifdef OBJC_INSTRUMENTED
2802 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",
2804 printf ("%5u %5u %5u %5.1f %4u %4.1f %4u %4.1f %4u\n",
2806 cacheSize, cacheCount, slotsUsed, avgUsed, maxUsed, avgSHit, maxSHit, avgSMiss, maxSMiss
2807 #ifdef OBJC_INSTRUMENTED
2808 , totDHits, avgDHit, maxDHit, totDMisses, avgDMiss, maxDMiss, totDFlsh, avgDFlsh, maxDFlsh
2814 #ifdef OBJC_INSTRUMENTED
2815 /***********************************************************************
2816 * PrintCacheHistogram. Show the non-zero entries from the specified
2818 **********************************************************************/
2819 static void PrintCacheHistogram (char * title,
2820 unsigned int * firstEntry,
2821 unsigned int entryCount)
2824 unsigned int * thisEntry;
2826 printf ("%s\n", title);
2827 printf (" Probes Tally\n");
2828 printf (" ------ -----\n");
2829 for (index = 0, thisEntry = firstEntry;
2831 index += 1, thisEntry += 1)
2833 if (*thisEntry == 0)
2836 printf (" %6d %5d\n", index, *thisEntry);
2841 /***********************************************************************
2842 * _class_printMethodCacheStatistics.
2843 **********************************************************************/
2845 #define MAX_LOG2_SIZE 32
2846 #define MAX_CHAIN_SIZE 100
2848 void _class_printMethodCacheStatistics (void)
2850 unsigned int isMeta;
2852 NXHashTable * class_hash;
2854 struct objc_class * cls;
2855 unsigned int totalChain;
2856 unsigned int totalMissChain;
2857 unsigned int maxChain;
2858 unsigned int maxMissChain;
2859 unsigned int classCount;
2860 unsigned int negativeEntryCount;
2861 unsigned int cacheExpandCount;
2862 unsigned int cacheCountBySize[2][MAX_LOG2_SIZE] = {{0}};
2863 unsigned int totalEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};
2864 unsigned int maxEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};
2865 unsigned int totalChainBySize[2][MAX_LOG2_SIZE] = {{0}};
2866 unsigned int totalMissChainBySize[2][MAX_LOG2_SIZE] = {{0}};
2867 unsigned int totalMaxChainBySize[2][MAX_LOG2_SIZE] = {{0}};
2868 unsigned int totalMaxMissChainBySize[2][MAX_LOG2_SIZE] = {{0}};
2869 unsigned int maxChainBySize[2][MAX_LOG2_SIZE] = {{0}};
2870 unsigned int maxMissChainBySize[2][MAX_LOG2_SIZE] = {{0}};
2871 unsigned int chainCount[MAX_CHAIN_SIZE] = {0};
2872 unsigned int missChainCount[MAX_CHAIN_SIZE] = {0};
2873 #ifdef OBJC_INSTRUMENTED
2874 unsigned int hitCountBySize[2][MAX_LOG2_SIZE] = {{0}};
2875 unsigned int hitProbesBySize[2][MAX_LOG2_SIZE] = {{0}};
2876 unsigned int maxHitProbesBySize[2][MAX_LOG2_SIZE] = {{0}};
2877 unsigned int missCountBySize[2][MAX_LOG2_SIZE] = {{0}};
2878 unsigned int missProbesBySize[2][MAX_LOG2_SIZE] = {{0}};
2879 unsigned int maxMissProbesBySize[2][MAX_LOG2_SIZE] = {{0}};
2880 unsigned int flushCountBySize[2][MAX_LOG2_SIZE] = {{0}};
2881 unsigned int flushedEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};
2882 unsigned int maxFlushedEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};
2885 printf ("Printing cache statistics\n");
2887 // Outermost loop - iterate over all classes
2888 class_hash = objc_getClasses ();
2889 state = NXInitHashState (class_hash);
2891 negativeEntryCount = 0;
2892 cacheExpandCount = 0;
2893 while (NXNextHashState (class_hash, &state, (void **) &cls))
2898 // Control loop - do given class' cache, then its isa's cache
2899 for (isMeta = 0; isMeta <= 1; isMeta += 1)
2903 unsigned int log2Size;
2904 unsigned int entryCount;
2906 // Select cache of interest
2907 cache = isMeta ? cls->isa->cache : ((struct objc_class *)cls)->cache;
2909 // Ignore empty cache... should we?
2910 if (cache == &emptyCache)
2913 // Middle loop - do each entry in the given cache
2920 for (index = 0; index < mask + 1; index += 1)
2925 uarith_t methodChain;
2926 uarith_t methodMissChain;
2929 // If entry is invalid, the only item of
2930 // interest is that future insert hashes
2931 // to this entry can use it directly.
2932 buckets = cache->buckets;
2933 if (!CACHE_BUCKET_VALID(buckets[index]))
2935 missChainCount[0] += 1;
2939 method = buckets[index];
2941 // Tally valid entries
2944 // Tally "forward::" entries
2945 if (CACHE_BUCKET_IMP(method) == &_objc_msgForward)
2946 negativeEntryCount += 1;
2948 // Calculate search distance (chain length) for this method
2949 hash = (uarith_t) CACHE_BUCKET_NAME(method);
2950 methodChain = ((index - hash) & mask);
2952 // Tally chains of this length
2953 if (methodChain < MAX_CHAIN_SIZE)
2954 chainCount[methodChain] += 1;
2956 // Keep sum of all chain lengths
2957 totalChain += methodChain;
2959 // Record greatest chain length
2960 if (methodChain > maxChain)
2961 maxChain = methodChain;
2963 // Calculate search distance for miss that hashes here
2965 while (CACHE_BUCKET_VALID(buckets[index2]))
2970 methodMissChain = ((index2 - index) & mask);
2972 // Tally miss chains of this length
2973 if (methodMissChain < MAX_CHAIN_SIZE)
2974 missChainCount[methodMissChain] += 1;
2976 // Keep sum of all miss chain lengths in this class
2977 totalMissChain += methodMissChain;
2979 // Record greatest miss chain length
2980 if (methodMissChain > maxMissChain)
2981 maxMissChain = methodMissChain;
2984 // Factor this cache into statistics about caches of the same
2985 // type and size (all caches are a power of two in size)
2986 log2Size = log2 (mask + 1);
2987 cacheCountBySize[isMeta][log2Size] += 1;
2988 totalEntriesBySize[isMeta][log2Size] += entryCount;
2989 if (entryCount > maxEntriesBySize[isMeta][log2Size])
2990 maxEntriesBySize[isMeta][log2Size] = entryCount;
2991 totalChainBySize[isMeta][log2Size] += totalChain;
2992 totalMissChainBySize[isMeta][log2Size] += totalMissChain;
2993 totalMaxChainBySize[isMeta][log2Size] += maxChain;
2994 totalMaxMissChainBySize[isMeta][log2Size] += maxMissChain;
2995 if (maxChain > maxChainBySize[isMeta][log2Size])
2996 maxChainBySize[isMeta][log2Size] = maxChain;
2997 if (maxMissChain > maxMissChainBySize[isMeta][log2Size])
2998 maxMissChainBySize[isMeta][log2Size] = maxMissChain;
2999 #ifdef OBJC_INSTRUMENTED
3001 CacheInstrumentation * cacheData;
3003 cacheData = CACHE_INSTRUMENTATION(cache);
3004 hitCountBySize[isMeta][log2Size] += cacheData->hitCount;
3005 hitProbesBySize[isMeta][log2Size] += cacheData->hitProbes;
3006 if (cacheData->maxHitProbes > maxHitProbesBySize[isMeta][log2Size])
3007 maxHitProbesBySize[isMeta][log2Size] = cacheData->maxHitProbes;
3008 missCountBySize[isMeta][log2Size] += cacheData->missCount;
3009 missProbesBySize[isMeta][log2Size] += cacheData->missProbes;
3010 if (cacheData->maxMissProbes > maxMissProbesBySize[isMeta][log2Size])
3011 maxMissProbesBySize[isMeta][log2Size] = cacheData->maxMissProbes;
3012 flushCountBySize[isMeta][log2Size] += cacheData->flushCount;
3013 flushedEntriesBySize[isMeta][log2Size] += cacheData->flushedEntries;
3014 if (cacheData->maxFlushedEntries > maxFlushedEntriesBySize[isMeta][log2Size])
3015 maxFlushedEntriesBySize[isMeta][log2Size] = cacheData->maxFlushedEntries;
3018 // Caches start with a power of two number of entries, and grow by doubling, so
3019 // we can calculate the number of times this cache has expanded
3021 cacheExpandCount += log2Size - INIT_META_CACHE_SIZE_LOG2;
3023 cacheExpandCount += log2Size - INIT_CACHE_SIZE_LOG2;
3029 unsigned int cacheCountByType[2] = {0};
3030 unsigned int totalCacheCount = 0;
3031 unsigned int totalEntries = 0;
3032 unsigned int maxEntries = 0;
3033 unsigned int totalSlots = 0;
3034 #ifdef OBJC_INSTRUMENTED
3035 unsigned int totalHitCount = 0;
3036 unsigned int totalHitProbes = 0;
3037 unsigned int maxHitProbes = 0;
3038 unsigned int totalMissCount = 0;
3039 unsigned int totalMissProbes = 0;
3040 unsigned int maxMissProbes = 0;
3041 unsigned int totalFlushCount = 0;
3042 unsigned int totalFlushedEntries = 0;
3043 unsigned int maxFlushedEntries = 0;
3051 // Sum information over all caches
3052 for (isMeta = 0; isMeta <= 1; isMeta += 1)
3054 for (index = 0; index < MAX_LOG2_SIZE; index += 1)
3056 cacheCountByType[isMeta] += cacheCountBySize[isMeta][index];
3057 totalEntries += totalEntriesBySize[isMeta][index];
3058 totalSlots += cacheCountBySize[isMeta][index] * (1 << index);
3059 totalChain += totalChainBySize[isMeta][index];
3060 if (maxEntriesBySize[isMeta][index] > maxEntries)
3061 maxEntries = maxEntriesBySize[isMeta][index];
3062 if (maxChainBySize[isMeta][index] > maxChain)
3063 maxChain = maxChainBySize[isMeta][index];
3064 totalMissChain += totalMissChainBySize[isMeta][index];
3065 if (maxMissChainBySize[isMeta][index] > maxMissChain)
3066 maxMissChain = maxMissChainBySize[isMeta][index];
3067 #ifdef OBJC_INSTRUMENTED
3068 totalHitCount += hitCountBySize[isMeta][index];
3069 totalHitProbes += hitProbesBySize[isMeta][index];
3070 if (maxHitProbesBySize[isMeta][index] > maxHitProbes)
3071 maxHitProbes = maxHitProbesBySize[isMeta][index];
3072 totalMissCount += missCountBySize[isMeta][index];
3073 totalMissProbes += missProbesBySize[isMeta][index];
3074 if (maxMissProbesBySize[isMeta][index] > maxMissProbes)
3075 maxMissProbes = maxMissProbesBySize[isMeta][index];
3076 totalFlushCount += flushCountBySize[isMeta][index];
3077 totalFlushedEntries += flushedEntriesBySize[isMeta][index];
3078 if (maxFlushedEntriesBySize[isMeta][index] > maxFlushedEntries)
3079 maxFlushedEntries = maxFlushedEntriesBySize[isMeta][index];
3083 totalCacheCount += cacheCountByType[isMeta];
3087 printf ("There are %u classes\n", classCount);
3089 for (isMeta = 0; isMeta <= 1; isMeta += 1)
3091 // Number of this type of class
3092 printf ("\nThere are %u %s-method caches, broken down by size (slot count):\n",
3093 cacheCountByType[isMeta],
3094 isMeta ? "class" : "instance");
3097 PrintCacheHeader ();
3099 // Keep format consistent even if there are caches of this kind
3100 if (cacheCountByType[isMeta] == 0)
3102 printf ("(none)\n");
3106 // Usage information by cache size
3107 for (index = 0; index < MAX_LOG2_SIZE; index += 1)
3109 unsigned int cacheCount;
3110 unsigned int cacheSlotCount;
3111 unsigned int cacheEntryCount;
3113 // Get number of caches of this type and size
3114 cacheCount = cacheCountBySize[isMeta][index];
3115 if (cacheCount == 0)
3118 // Get the cache slot count and the total number of valid entries
3119 cacheSlotCount = (1 << index);
3120 cacheEntryCount = totalEntriesBySize[isMeta][index];
3122 // Give the analysis
3123 PrintCacheInfo (cacheSlotCount,
3126 (float) cacheEntryCount / (float) cacheCount,
3127 maxEntriesBySize[isMeta][index],
3128 (float) totalChainBySize[isMeta][index] / (float) cacheEntryCount,
3129 maxChainBySize[isMeta][index],
3130 (float) totalMissChainBySize[isMeta][index] / (float) (cacheCount * cacheSlotCount),
3131 maxMissChainBySize[isMeta][index]
3132 #ifdef OBJC_INSTRUMENTED
3133 , hitCountBySize[isMeta][index],
3134 hitCountBySize[isMeta][index] ?
3135 (float) hitProbesBySize[isMeta][index] / (float) hitCountBySize[isMeta][index] : 0.0,
3136 maxHitProbesBySize[isMeta][index],
3137 missCountBySize[isMeta][index],
3138 missCountBySize[isMeta][index] ?
3139 (float) missProbesBySize[isMeta][index] / (float) missCountBySize[isMeta][index] : 0.0,
3140 maxMissProbesBySize[isMeta][index],
3141 flushCountBySize[isMeta][index],
3142 flushCountBySize[isMeta][index] ?
3143 (float) flushedEntriesBySize[isMeta][index] / (float) flushCountBySize[isMeta][index] : 0.0,
3144 maxFlushedEntriesBySize[isMeta][index]
3150 // Give overall numbers
3151 printf ("\nCumulative:\n");
3152 PrintCacheHeader ();
3153 PrintCacheInfo (totalSlots,
3156 (float) totalEntries / (float) totalCacheCount,
3158 (float) totalChain / (float) totalEntries,
3160 (float) totalMissChain / (float) totalSlots,
3162 #ifdef OBJC_INSTRUMENTED
3165 (float) totalHitProbes / (float) totalHitCount : 0.0,
3169 (float) totalMissProbes / (float) totalMissCount : 0.0,
3173 (float) totalFlushedEntries / (float) totalFlushCount : 0.0,
3178 printf ("\nNumber of \"forward::\" entries: %d\n", negativeEntryCount);
3179 printf ("Number of cache expansions: %d\n", cacheExpandCount);
3180 #ifdef OBJC_INSTRUMENTED
3181 printf ("flush_caches: total calls total visits average visits max visits total classes visits/class\n");
3182 printf (" ----------- ------------ -------------- ---------- ------------- -------------\n");
3183 printf (" linear %11u %12u %14.1f %10u %13u %12.2f\n",
3184 LinearFlushCachesCount,
3185 LinearFlushCachesVisitedCount,
3186 LinearFlushCachesCount ?
3187 (float) LinearFlushCachesVisitedCount / (float) LinearFlushCachesCount : 0.0,
3188 MaxLinearFlushCachesVisitedCount,
3189 LinearFlushCachesVisitedCount,
3191 printf (" nonlinear %11u %12u %14.1f %10u %13u %12.2f\n",
3192 NonlinearFlushCachesCount,
3193 NonlinearFlushCachesVisitedCount,
3194 NonlinearFlushCachesCount ?
3195 (float) NonlinearFlushCachesVisitedCount / (float) NonlinearFlushCachesCount : 0.0,
3196 MaxNonlinearFlushCachesVisitedCount,
3197 NonlinearFlushCachesClassCount,
3198 NonlinearFlushCachesClassCount ?
3199 (float) NonlinearFlushCachesVisitedCount / (float) NonlinearFlushCachesClassCount : 0.0);
3200 printf (" ideal %11u %12u %14.1f %10u %13u %12.2f\n",
3201 LinearFlushCachesCount + NonlinearFlushCachesCount,
3202 IdealFlushCachesCount,
3203 LinearFlushCachesCount + NonlinearFlushCachesCount ?
3204 (float) IdealFlushCachesCount / (float) (LinearFlushCachesCount + NonlinearFlushCachesCount) : 0.0,
3205 MaxIdealFlushCachesCount,
3206 LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount,
3207 LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount ?
3208 (float) IdealFlushCachesCount / (float) (LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount) : 0.0);
3210 PrintCacheHistogram ("\nCache hit histogram:", &CacheHitHistogram[0], CACHE_HISTOGRAM_SIZE);
3211 PrintCacheHistogram ("\nCache miss histogram:", &CacheMissHistogram[0], CACHE_HISTOGRAM_SIZE);
3215 printf ("\nLookup chains:");
3216 for (index = 0; index < MAX_CHAIN_SIZE; index += 1)
3218 if (chainCount[index] != 0)
3219 printf (" %u:%u", index, chainCount[index]);
3222 printf ("\nMiss chains:");
3223 for (index = 0; index < MAX_CHAIN_SIZE; index += 1)
3225 if (missChainCount[index] != 0)
3226 printf (" %u:%u", index, missChainCount[index]);
3229 printf ("\nTotal memory usage for cache data structures: %lu bytes\n",
3230 totalCacheCount * (sizeof(struct objc_cache) - sizeof(Method)) +
3231 totalSlots * sizeof(Method) +
3232 negativeEntryCount * sizeof(struct objc_method));
3237 /***********************************************************************
3239 **********************************************************************/
3240 void checkUniqueness (SEL s1,
3246 if (s1 && s2 && (strcmp ((const char *) s1, (const char *) s2) == 0))
3247 _NXLogError ("%p != %p but !strcmp (%s, %s)\n", s1, s2, (char *) s1, (char *) s2);