]> git.saurik.com Git - apple/objc4.git/blame - runtime/objc-class.m
objc4-267.1.tar.gz
[apple/objc4.git] / runtime / objc-class.m
CommitLineData
13d88034
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
390d5862
A
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
13d88034 15 * The Original Code and all software distributed under the License are
390d5862 16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
13d88034
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
390d5862
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
13d88034
A
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/***********************************************************************
41c8faa5
A
26* objc-class.m
27* Copyright 1988-1997, Apple Computer, Inc.
28* Author: s. naroff
29**********************************************************************/
13d88034 30
1f20c7a7
A
31
32/***********************************************************************
33 * Method cache locking (GrP 2001-1-14)
34 *
35 * For speed, objc_msgSend does not acquire any locks when it reads
36 * method caches. Instead, all cache changes are performed so that any
37 * objc_msgSend running concurrently with the cache mutator will not
38 * crash or hang or get an incorrect result from the cache.
39 *
40 * When cache memory becomes unused (e.g. the old cache after cache
41 * expansion), it is not immediately freed, because a concurrent
42 * objc_msgSend could still be using it. Instead, the memory is
43 * disconnected from the data structures and placed on a garbage list.
44 * The memory is now only accessible to instances of objc_msgSend that
45 * were running when the memory was disconnected; any further calls to
46 * objc_msgSend will not see the garbage memory because the other data
47 * structures don't point to it anymore. The collecting_in_critical
48 * function checks the PC of all threads and returns FALSE when all threads
49 * are found to be outside objc_msgSend. This means any call to objc_msgSend
50 * that could have had access to the garbage has finished or moved past the
51 * cache lookup stage, so it is safe to free the memory.
52 *
53 * All functions that modify cache data or structures must acquire the
54 * cacheUpdateLock to prevent interference from concurrent modifications.
55 * The function that frees cache garbage must acquire the cacheUpdateLock
56 * and use collecting_in_critical() to flush out cache readers.
2bfd4448
A
57 * The cacheUpdateLock is also used to protect the custom allocator used
58 * for large method cache blocks.
1f20c7a7
A
59 *
60 * Cache readers (PC-checked by collecting_in_critical())
61 * objc_msgSend*
62 * _cache_getImp
63 * _cache_getMethod
64 *
65 * Cache writers (hold cacheUpdateLock while reading or writing; not PC-checked)
66 * _cache_fill (acquires lock)
67 * _cache_expand (only called from cache_fill)
68 * _cache_create (only called from cache_expand)
69 * bcopy (only called from instrumented cache_expand)
70 * flush_caches (acquires lock)
71 * _cache_flush (only called from cache_fill and flush_caches)
72 * _cache_collect_free (only called from cache_expand and cache_flush)
73 *
74 * UNPROTECTED cache readers (NOT thread-safe; used for debug info only)
75 * _cache_print
76 * _class_printMethodCaches
77 * _class_printDuplicateCacheEntries
78 * _class_printMethodCacheStatistics
79 *
80 * _class_lookupMethodAndLoadCache is a special case. It may read a
81 * method triplet out of one cache and store it in another cache. This
82 * is unsafe if the method triplet is a forward:: entry, because the
83 * triplet itself could be freed unless _class_lookupMethodAndLoadCache
84 * were PC-checked or used a lock. Additionally, storing the method
85 * triplet in both caches would result in double-freeing if both caches
86 * were flushed or expanded. The solution is for _cache_getMethod to
87 * ignore all entries whose implementation is _objc_msgForward, so
88 * _class_lookupMethodAndLoadCache cannot look at a forward:: entry
89 * unsafely or place it in multiple caches.
90 ***********************************************************************/
91
2bfd4448
A
92/***********************************************************************
93 * Lazy method list arrays and method list locking (2004-10-19)
94 *
95 * cls->methodLists may be in one of three forms:
96 * 1. NULL: The class has no methods.
97 * 2. non-NULL, with CLS_NO_METHOD_ARRAY set: cls->methodLists points
98 * to a single method list, which is the class's only method list.
99 * 3. non-NULL, with CLS_NO_METHOD_ARRAY clear: cls->methodLists points to
100 * an array of method list pointers. The end of the array's block
101 * is set to -1. If the actual number of method lists is smaller
102 * than that, the rest of the array is NULL.
103 *
104 * Attaching categories and adding and removing classes may change
105 * the form of the class list. In addition, individual method lists
106 * may be reallocated when fixed up.
107 *
108 * Classes are initially read as #1 or #2. If a category is attached
109 * or other methods added, the class is changed to #3. Once in form #3,
110 * the class is never downgraded to #1 or #2, even if methods are removed.
111 * Classes added with objc_addClass are initially either #1 or #3.
112 *
113 * Accessing and manipulating a class's method lists are synchronized,
114 * to prevent races when one thread restructures the list. However,
115 * if the class is not yet in use (i.e. not in class_hash), then the
116 * thread loading the class may access its method lists without locking.
117 *
118 * The following functions acquire methodListLock:
119 * class_getInstanceMethod
120 * class_getClassMethod
121 * class_nextMethodList
122 * class_addMethods
123 * class_removeMethods
124 * class_respondsToMethod
125 * _class_lookupMethodAndLoadCache
126 * lookupMethodInClassAndLoadCache
127 * _objc_add_category_flush_caches
128 *
129 * The following functions don't acquire methodListLock because they
130 * only access method lists during class load and unload:
131 * _objc_register_category
132 * _resolve_categories_for_class (calls _objc_add_category)
133 * add_class_to_loadable_list
134 * _objc_addClass
135 * _objc_remove_classes_in_image
136 *
137 * The following functions use method lists without holding methodListLock.
138 * The caller must either hold methodListLock, or be loading the class.
139 * _getMethod (called by class_getInstanceMethod, class_getClassMethod,
140 * and class_respondsToMethod)
141 * _findMethodInClass (called by _class_lookupMethodAndLoadCache,
142 * lookupMethodInClassAndLoadCache, _getMethod)
143 * _findMethodInList (called by _findMethodInClass)
144 * nextMethodList (called by _findMethodInClass and class_nextMethodList
145 * fixupSelectorsInMethodList (called by nextMethodList)
146 * _objc_add_category (called by _objc_add_category_flush_caches,
147 * resolve_categories_for_class and _objc_register_category)
148 * _objc_insertMethods (called by class_addMethods and _objc_add_category)
149 * _objc_removeMethods (called by class_removeMethods)
150 * _objcTweakMethodListPointerForClass (called by _objc_insertMethods)
151 * get_base_method_list (called by add_class_to_loadable_list)
152 * lookupNamedMethodInMethodList (called by add_class_to_loadable_list)
153 ***********************************************************************/
154
155/***********************************************************************
156 * Thread-safety of class info bits (2004-10-19)
157 *
158 * Some class info bits are used to store mutable runtime state.
159 * Modifications of the info bits at particular times need to be
160 * synchronized to prevent races.
161 *
162 * Three thread-safe modification functions are provided:
163 * _class_setInfo() // atomically sets some bits
164 * _class_clearInfo() // atomically clears some bits
165 * _class_changeInfo() // atomically sets some bits and clears others
166 * These replace CLS_SETINFO() for the multithreaded cases.
167 *
168 * Three modification windows are defined:
169 * - compile time
170 * - class construction or image load (before +load) in one thread
171 * - multi-threaded messaging and method caches
172 *
173 * Info bit modification at compile time and class construction do not
174 * need to be locked, because only one thread is manipulating the class.
175 * Info bit modification during messaging needs to be locked, because
176 * there may be other threads simultaneously messaging or otherwise
177 * manipulating the class.
178 *
179 * Modification windows for each flag:
180 *
181 * CLS_CLASS: compile-time and class load
182 * CLS_META: compile-time and class load
183 * CLS_INITIALIZED: +initialize
184 * CLS_POSING: messaging
185 * CLS_MAPPED: compile-time
186 * CLS_FLUSH_CACHE: messaging
187 * CLS_GROW_CACHE: messaging
188 * CLS_NEED_BIND: unused
189 * CLS_METHOD_ARRAY: unused
190 * CLS_JAVA_HYBRID: JavaBridge only
191 * CLS_JAVA_CLASS: JavaBridge only
192 * CLS_INITIALIZING: messaging
193 * CLS_FROM_BUNDLE: class load
194 * CLS_HAS_CXX_STRUCTORS: compile-time and class load
195 * CLS_NO_METHOD_ARRAY: class load and messaging
cacad474 196 * CLS_HAS_LOAD_METHOD: class load
2bfd4448
A
197 *
198 * CLS_INITIALIZED and CLS_INITIALIZING have additional thread-safety
199 * constraints to support thread-safe +initialize. See "Thread safety
200 * during class initialization" for details.
201 *
202 * CLS_JAVA_HYBRID and CLS_JAVA_CLASS are set immediately after JavaBridge
203 * calls objc_addClass(). The JavaBridge does not use an atomic update,
204 * but the modification counts as "class construction" unless some other
205 * thread quickly finds the class via the class list. This race is
206 * small and unlikely in well-behaved code.
207 *
208 * Most info bits that may be modified during messaging are also never
209 * read without a lock. There is no general read lock for the info bits.
210 * CLS_INITIALIZED: classInitLock
211 * CLS_FLUSH_CACHE: cacheUpdateLock
212 * CLS_GROW_CACHE: cacheUpdateLock
213 * CLS_NO_METHOD_ARRAY: methodListLock
214 * CLS_INITIALIZING: classInitLock
215 ***********************************************************************/
216
1f20c7a7
A
217/***********************************************************************
218 * Thread-safety during class initialization (GrP 2001-9-24)
219 *
220 * Initial state: CLS_INITIALIZING and CLS_INITIALIZED both clear.
221 * During initialization: CLS_INITIALIZING is set
222 * After initialization: CLS_INITIALIZING clear and CLS_INITIALIZED set.
223 * CLS_INITIALIZING and CLS_INITIALIZED are never set at the same time.
224 * CLS_INITIALIZED is never cleared once set.
225 *
226 * Only one thread is allowed to actually initialize a class and send
227 * +initialize. Enforced by allowing only one thread to set CLS_INITIALIZING.
228 *
229 * Additionally, threads trying to send messages to a class must wait for
230 * +initialize to finish. During initialization of a class, that class's
231 * method cache is kept empty. objc_msgSend will revert to
232 * class_lookupMethodAndLoadCache, which checks CLS_INITIALIZED before
233 * messaging. If CLS_INITIALIZED is clear but CLS_INITIALIZING is set,
234 * the thread must block, unless it is the thread that started
235 * initializing the class in the first place.
236 *
237 * Each thread keeps a list of classes it's initializing.
238 * The global classInitLock is used to synchronize changes to CLS_INITIALIZED
239 * and CLS_INITIALIZING: the transition to CLS_INITIALIZING must be
240 * an atomic test-and-set with respect to itself and the transition
241 * to CLS_INITIALIZED.
242 * The global classInitWaitCond is used to block threads waiting for an
243 * initialization to complete. The classInitLock synchronizes
244 * condition checking and the condition variable.
245 **********************************************************************/
246
247/***********************************************************************
248 * +initialize deadlock case when a class is marked initializing while
249 * its superclass is initialized. Solved by completely initializing
250 * superclasses before beginning to initialize a class.
251 *
252 * OmniWeb class hierarchy:
253 * OBObject
254 * | ` OBPostLoader
255 * OFObject
256 * / \
257 * OWAddressEntry OWController
258 * |
259 * OWConsoleController
260 *
261 * Thread 1 (evil testing thread):
262 * initialize OWAddressEntry
263 * super init OFObject
264 * super init OBObject
265 * [OBObject initialize] runs OBPostLoader, which inits lots of classes...
266 * initialize OWConsoleController
267 * super init OWController - wait for Thread 2 to finish OWController init
268 *
269 * Thread 2 (normal OmniWeb thread):
270 * initialize OWController
271 * super init OFObject - wait for Thread 1 to finish OFObject init
272 *
273 * deadlock!
274 *
275 * Solution: fully initialize super classes before beginning to initialize
276 * a subclass. Then the initializing+initialized part of the class hierarchy
277 * will be a contiguous subtree starting at the root, so other threads
278 * can't jump into the middle between two initializing classes, and we won't
279 * get stuck while a superclass waits for its subclass which waits for the
280 * superclass.
281 **********************************************************************/
282
283
284
13d88034 285/***********************************************************************
41c8faa5
A
286* Imports.
287**********************************************************************/
13d88034 288
41c8faa5
A
289#import <mach/mach_interface.h>
290#include <mach-o/ldsyms.h>
291#include <mach-o/dyld.h>
13d88034 292
41c8faa5
A
293#include <sys/types.h>
294#include <unistd.h>
295#include <stdlib.h>
296#include <sys/uio.h>
297#include <sys/fcntl.h>
298
299#import "objc-class.h"
13d88034
A
300
301#import <objc/Object.h>
302#import <objc/objc-runtime.h>
303#import "objc-private.h"
304#import "hashtable2.h"
305#import "maptable.h"
306
307#include <sys/types.h>
308
13d88034
A
309// Needed functions not in any header file
310size_t malloc_size (const void * ptr);
311
312// Needed kernel interface
313#import <mach/mach.h>
13d88034 314#import <mach/thread_status.h>
13d88034 315
13d88034
A
316
317/***********************************************************************
41c8faa5
A
318* Conditionals.
319**********************************************************************/
13d88034
A
320
321// Define PRELOAD_SUPERCLASS_CACHES to cause method lookups to add the
322// method the appropriate superclass caches, in addition to the normal
323// encaching in the subclass where the method was messaged. Doing so
324// will speed up messaging the same method from instances of the
325// superclasses, but also uses up valuable cache space for a speculative
326// purpose
41c8faa5
A
327// See radar 2364264 about incorrectly propogating _objc_forward entries
328// and double freeing them, first, before turning this on!
1f20c7a7
A
329// (Radar 2364264 is now "inactive".)
330// Double-freeing is also a potential problem when this is off. See
331// note about _class_lookupMethodAndLoadCache in "Method cache locking".
13d88034
A
332//#define PRELOAD_SUPERCLASS_CACHES
333
334/***********************************************************************
41c8faa5
A
335* Exports.
336**********************************************************************/
13d88034
A
337
338#ifdef OBJC_INSTRUMENTED
339enum {
41c8faa5 340 CACHE_HISTOGRAM_SIZE = 512
13d88034
A
341};
342
343unsigned int CacheHitHistogram [CACHE_HISTOGRAM_SIZE];
344unsigned int CacheMissHistogram [CACHE_HISTOGRAM_SIZE];
345#endif
346
347/***********************************************************************
41c8faa5
A
348* Constants and macros internal to this module.
349**********************************************************************/
13d88034
A
350
351// INIT_CACHE_SIZE and INIT_META_CACHE_SIZE must be a power of two
352enum {
41c8faa5
A
353 INIT_CACHE_SIZE_LOG2 = 2,
354 INIT_META_CACHE_SIZE_LOG2 = 2,
355 INIT_CACHE_SIZE = (1 << INIT_CACHE_SIZE_LOG2),
356 INIT_META_CACHE_SIZE = (1 << INIT_META_CACHE_SIZE_LOG2)
13d88034
A
357};
358
359// Amount of space required for count hash table buckets, knowing that
360// one entry is embedded in the cache structure itself
361#define TABLE_SIZE(count) ((count - 1) * sizeof(Method))
362
390d5862
A
363// A sentinal (magic value) to report bad thread_get_state status
364#define PC_SENTINAL 0
365
13d88034
A
366
367/***********************************************************************
41c8faa5
A
368* Types internal to this module.
369**********************************************************************/
13d88034
A
370
371#ifdef OBJC_INSTRUMENTED
372struct CacheInstrumentation
373{
41c8faa5
A
374 unsigned int hitCount; // cache lookup success tally
375 unsigned int hitProbes; // sum entries checked to hit
376 unsigned int maxHitProbes; // max entries checked to hit
377 unsigned int missCount; // cache lookup no-find tally
378 unsigned int missProbes; // sum entries checked to miss
379 unsigned int maxMissProbes; // max entries checked to miss
380 unsigned int flushCount; // cache flush tally
381 unsigned int flushedEntries; // sum cache entries flushed
382 unsigned int maxFlushedEntries; // max cache entries flushed
13d88034
A
383};
384typedef struct CacheInstrumentation CacheInstrumentation;
385
386// Cache instrumentation data follows table, so it is most compatible
387#define CACHE_INSTRUMENTATION(cache) (CacheInstrumentation *) &cache->buckets[cache->mask + 1];
388#endif
389
390/***********************************************************************
41c8faa5
A
391* Function prototypes internal to this module.
392**********************************************************************/
13d88034
A
393
394static Ivar class_getVariable (Class cls, const char * name);
395static void flush_caches (Class cls, BOOL flush_meta);
2bfd4448 396static struct objc_method_list *nextMethodList(struct objc_class *cls, void **it);
13d88034
A
397static void addClassToOriginalClass (Class posingClass, Class originalClass);
398static void _objc_addOrigClass (Class origClass);
41c8faa5 399static void _freedHandler (id self, SEL sel);
13d88034 400static void _nonexistentHandler (id self, SEL sel);
1f20c7a7 401static void class_initialize (Class cls);
13d88034
A
402static Cache _cache_expand (Class cls);
403static int LogObjCMessageSend (BOOL isClassMethod, const char * objectsClass, const char * implementingClass, SEL selector);
1f20c7a7
A
404static BOOL _cache_fill (Class cls, Method smt, SEL sel);
405static void _cache_addForwardEntry(Class cls, SEL sel);
13d88034 406static void _cache_flush (Class cls);
2bfd4448 407static IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel);
41c8faa5
A
408static int SubtypeUntil (const char * type, char end);
409static const char * SkipFirstType (const char * type);
13d88034 410
13d88034
A
411static unsigned long _get_pc_for_thread (mach_port_t thread);
412static int _collecting_in_critical (void);
413static void _garbage_make_room (void);
2bfd4448
A
414static void _cache_collect_free (void * data, size_t size, BOOL tryCollect);
415
416static BOOL cache_allocator_is_block(void *block);
417static void *cache_allocator_calloc(size_t size);
418static void cache_allocator_free(void *block);
13d88034
A
419
420static void _cache_print (Cache cache);
421static unsigned int log2 (unsigned int x);
422static void PrintCacheHeader (void);
423#ifdef OBJC_INSTRUMENTED
424static void PrintCacheHistogram (char * title, unsigned int * firstEntry, unsigned int entryCount);
425#endif
426
427/***********************************************************************
41c8faa5
A
428* Static data internal to this module.
429**********************************************************************/
13d88034
A
430
431// When _class_uncache is non-zero, cache growth copies the existing
432// entries into the new (larger) cache. When this flag is zero, new
433// (larger) caches start out empty.
434static int _class_uncache = 1;
435
436// When _class_slow_grow is non-zero, any given cache is actually grown
437// only on the odd-numbered times it becomes full; on the even-numbered
438// times, it is simply emptied and re-used. When this flag is zero,
439// caches are grown every time.
440static int _class_slow_grow = 1;
441
1f20c7a7
A
442// Lock for cache access.
443// Held when modifying a cache in place.
444// Held when installing a new cache on a class.
445// Held when adding to the cache garbage list.
446// Held when disposing cache garbage.
447// See "Method cache locking" above for notes about cache locking.
13d88034
A
448static OBJC_DECLARE_LOCK(cacheUpdateLock);
449
1f20c7a7
A
450// classInitLock protects classInitWaitCond and examination and modification
451// of CLS_INITIALIZED and CLS_INITIALIZING.
452OBJC_DECLARE_LOCK(classInitLock);
453// classInitWaitCond is signalled when any class is done initializing.
454// Threads that are waiting for a class to finish initializing wait on this.
455pthread_cond_t classInitWaitCond = PTHREAD_COND_INITIALIZER;
13d88034 456
2bfd4448
A
457// Lock for method list access and modification.
458// Protects methodLists fields, method arrays, and CLS_NO_METHOD_ARRAY bits.
459// Classes not yet in use do not need to take this lock.
460OBJC_DECLARE_LOCK(methodListLock);
13d88034
A
461
462// When traceDuplicates is non-zero, _cacheFill checks whether the method
463// being encached is already there. The number of times it finds a match
464// is tallied in cacheFillDuplicates. When traceDuplicatesVerbose is
465// non-zero, each duplication is logged when found in this way.
13d88034
A
466static int traceDuplicates = 0;
467static int traceDuplicatesVerbose = 0;
468static int cacheFillDuplicates = 0;
13d88034 469
2bfd4448
A
470// Custom cache allocator parameters
471// CACHE_REGION_SIZE must be a multiple of CACHE_QUANTUM.
472#define CACHE_QUANTUM 520
473#define CACHE_REGION_SIZE 131040 // quantized just under 128KB (131072)
474// #define CACHE_REGION_SIZE 262080 // quantized just under 256KB (262144)
475
13d88034
A
476#ifdef OBJC_INSTRUMENTED
477// Instrumentation
478static unsigned int LinearFlushCachesCount = 0;
479static unsigned int LinearFlushCachesVisitedCount = 0;
480static unsigned int MaxLinearFlushCachesVisitedCount = 0;
481static unsigned int NonlinearFlushCachesCount = 0;
482static unsigned int NonlinearFlushCachesClassCount = 0;
483static unsigned int NonlinearFlushCachesVisitedCount = 0;
484static unsigned int MaxNonlinearFlushCachesVisitedCount = 0;
485static unsigned int IdealFlushCachesCount = 0;
486static unsigned int MaxIdealFlushCachesCount = 0;
487#endif
488
489// Method call logging
490typedef int (*ObjCLogProc)(BOOL, const char *, const char *, SEL);
491
2bfd4448 492static int totalCacheFills NOBSS = 0;
13d88034
A
493static int objcMsgLogFD = (-1);
494static ObjCLogProc objcMsgLogProc = &LogObjCMessageSend;
495static int objcMsgLogEnabled = 0;
496
497// Error Messages
498static const char
41c8faa5
A
499_errNoMem[] = "failed -- out of memory(%s, %u)",
500_errAllocNil[] = "allocating nil object",
501_errFreedObject[] = "message %s sent to freed object=0x%lx",
502_errNonExistentObject[] = "message %s sent to non-existent object=0x%lx",
503_errBadSel[] = "invalid selector %s",
504_errNotSuper[] = "[%s poseAs:%s]: target not immediate superclass",
505_errNewVars[] = "[%s poseAs:%s]: %s defines new instance variables";
506
507/***********************************************************************
508* Information about multi-thread support:
509*
510* Since we do not lock many operations which walk the superclass, method
511* and ivar chains, these chains must remain intact once a class is published
512* by inserting it into the class hashtable. All modifications must be
513* atomic so that someone walking these chains will always geta valid
514* result.
515***********************************************************************/
516/***********************************************************************
517* A static empty cache. All classes initially point at this cache.
518* When the first message is sent it misses in the cache, and when
519* the cache is grown it checks for this case and uses malloc rather
520* than realloc. This avoids the need to check for NULL caches in the
521* messenger.
522***********************************************************************/
13d88034 523
2bfd4448 524#ifndef OBJC_INSTRUMENTED
13d88034
A
525const struct objc_cache emptyCache =
526{
41c8faa5
A
527 0, // mask
528 0, // occupied
529 { NULL } // buckets
13d88034 530};
2bfd4448
A
531#else
532// OBJC_INSTRUMENTED requires writable data immediately following emptyCache.
533struct objc_cache emptyCache =
534{
535 0, // mask
536 0, // occupied
537 { NULL } // buckets
538};
539CacheInstrumentation emptyCacheInstrumentation = {0};
540#endif
541
13d88034
A
542
543// Freed objects have their isa set to point to this dummy class.
544// This avoids the need to check for Nil classes in the messenger.
545static const struct objc_class freedObjectClass =
546{
41c8faa5
A
547 Nil, // isa
548 Nil, // super_class
549 "FREED(id)", // name
550 0, // version
551 0, // info
552 0, // instance_size
553 NULL, // ivars
554 NULL, // methodLists
555 (Cache) &emptyCache, // cache
556 NULL // protocols
13d88034
A
557};
558
559static const struct objc_class nonexistentObjectClass =
560{
41c8faa5
A
561 Nil, // isa
562 Nil, // super_class
563 "NONEXISTENT(id)", // name
564 0, // version
565 0, // info
566 0, // instance_size
567 NULL, // ivars
568 NULL, // methodLists
569 (Cache) &emptyCache, // cache
570 NULL // protocols
13d88034
A
571};
572
573/***********************************************************************
41c8faa5
A
574* object_getClassName.
575**********************************************************************/
13d88034
A
576const char * object_getClassName (id obj)
577{
41c8faa5
A
578 // Even nil objects have a class name, sort of
579 if (obj == nil)
580 return "nil";
13d88034 581
41c8faa5
A
582 // Retrieve name from object's class
583 return ((struct objc_class *) obj->isa)->name;
13d88034
A
584}
585
586/***********************************************************************
41c8faa5
A
587* object_getIndexedIvars.
588**********************************************************************/
13d88034
A
589void * object_getIndexedIvars (id obj)
590{
41c8faa5
A
591 // ivars are tacked onto the end of the object
592 return ((char *) obj) + ((struct objc_class *) obj->isa)->instance_size;
13d88034
A
593}
594
595
2bfd4448
A
596/***********************************************************************
597* object_cxxDestructFromClass.
598* Call C++ destructors on obj, starting with cls's
599* dtor method (if any) followed by superclasses' dtors (if any),
600* stopping at cls's dtor (if any).
601* Uses methodListLock and cacheUpdateLock. The caller must hold neither.
602**********************************************************************/
603static void object_cxxDestructFromClass(id obj, Class cls)
604{
605 void (*dtor)(id);
606
607 // Call cls's dtor first, then superclasses's dtors.
608
609 for ( ; cls != NULL; cls = cls->super_class) {
610 if (!(cls->info & CLS_HAS_CXX_STRUCTORS)) continue;
611 dtor = (void(*)(id))
612 lookupMethodInClassAndLoadCache(cls, cxx_destruct_sel);
613 if (dtor != (void(*)(id))&_objc_msgForward) {
614 if (PrintCxxCtors) {
615 _objc_inform("CXX: calling C++ destructors for class %s",
616 cls->name);
617 }
618 (*dtor)(obj);
619 }
620 }
621}
622
623
624/***********************************************************************
625* object_cxxDestruct.
626* Call C++ destructors on obj, if any.
627* Uses methodListLock and cacheUpdateLock. The caller must hold neither.
628**********************************************************************/
629void object_cxxDestruct(id obj)
630{
631 if (!obj) return;
632 object_cxxDestructFromClass(obj, obj->isa);
633}
634
635
636/***********************************************************************
637* object_cxxConstructFromClass.
638* Recursively call C++ constructors on obj, starting with base class's
639* ctor method (if any) followed by subclasses' ctors (if any), stopping
640* at cls's ctor (if any).
641* Returns YES if construction succeeded.
642* Returns NO if some constructor threw an exception. The exception is
643* caught and discarded. Any partial construction is destructed.
644* Uses methodListLock and cacheUpdateLock. The caller must hold neither.
645*
646* .cxx_construct returns id. This really means:
647* return self: construction succeeded
648* return nil: construction failed because a C++ constructor threw an exception
649**********************************************************************/
650static BOOL object_cxxConstructFromClass(id obj, Class cls)
651{
652 id (*ctor)(id);
653
654 // Call superclasses' ctors first, if any.
655 if (cls->super_class) {
656 BOOL ok = object_cxxConstructFromClass(obj, cls->super_class);
657 if (!ok) return NO; // some superclass's ctor failed - give up
658 }
659
660 // Find this class's ctor, if any.
661 if (!(cls->info & CLS_HAS_CXX_STRUCTORS)) return YES; // no ctor - ok
662 ctor = (id(*)(id))lookupMethodInClassAndLoadCache(cls, cxx_construct_sel);
663 if (ctor == (id(*)(id))&_objc_msgForward) return YES; // no ctor - ok
664
665 // Call this class's ctor.
666 if (PrintCxxCtors) {
667 _objc_inform("CXX: calling C++ constructors for class %s", cls->name);
668 }
669 if ((*ctor)(obj)) return YES; // ctor called and succeeded - ok
670
671 // This class's ctor was called and failed.
672 // Call superclasses's dtors to clean up.
673 if (cls->super_class) object_cxxDestructFromClass(obj, cls->super_class);
674 return NO;
675}
676
677
678/***********************************************************************
679* object_cxxConstructFromClass.
680* Call C++ constructors on obj, if any.
681* Returns YES if construction succeeded.
682* Returns NO if some constructor threw an exception. The exception is
683* caught and discarded. Any partial construction is destructed.
684* Uses methodListLock and cacheUpdateLock. The caller must hold neither.
685**********************************************************************/
686BOOL object_cxxConstruct(id obj)
687{
688 if (!obj) return YES;
689 return object_cxxConstructFromClass(obj, obj->isa);
690}
691
692
13d88034 693/***********************************************************************
41c8faa5
A
694* _internal_class_createInstanceFromZone. Allocate an instance of the
695* specified class with the specified number of bytes for indexed
696* variables, in the specified zone. The isa field is set to the
2bfd4448 697* class, C++ default constructors are called, and all other fields are zeroed.
41c8faa5 698**********************************************************************/
13d88034 699static id _internal_class_createInstanceFromZone (Class aClass,
41c8faa5
A
700 unsigned nIvarBytes,
701 void * z)
702{
703 id obj;
704 register unsigned byteCount;
705
706 // Can't create something for nothing
707 if (aClass == Nil)
708 {
709 __objc_error ((id) aClass, _errAllocNil, 0);
710 return nil;
711 }
712
713 // Allocate and initialize
714 byteCount = ((struct objc_class *) aClass)->instance_size + nIvarBytes;
715 obj = (id) malloc_zone_calloc (z, 1, byteCount);
716 if (!obj)
717 {
718 __objc_error ((id) aClass, _errNoMem, ((struct objc_class *) aClass)->name, nIvarBytes);
719 return nil;
720 }
721
722 // Set the isa pointer
723 obj->isa = aClass;
2bfd4448
A
724
725 // Call C++ constructors, if any.
726 if (!object_cxxConstruct(obj)) {
727 // Some C++ constructor threw an exception.
728 malloc_zone_free(z, obj);
729 return nil;
730 }
731
41c8faa5
A
732 return obj;
733}
734
735/***********************************************************************
736* _internal_class_createInstance. Allocate an instance of the specified
737* class with the specified number of bytes for indexed variables, in
738* the default zone, using _internal_class_createInstanceFromZone.
739**********************************************************************/
13d88034 740static id _internal_class_createInstance (Class aClass,
41c8faa5 741 unsigned nIvarBytes)
13d88034 742{
41c8faa5
A
743 return _internal_class_createInstanceFromZone (aClass,
744 nIvarBytes,
745 malloc_default_zone ());
746}
13d88034
A
747
748id (*_poseAs)() = (id (*)())class_poseAs;
749id (*_alloc)(Class, unsigned) = _internal_class_createInstance;
750id (*_zoneAlloc)(Class, unsigned, void *) = _internal_class_createInstanceFromZone;
751
752/***********************************************************************
41c8faa5
A
753* class_createInstanceFromZone. Allocate an instance of the specified
754* class with the specified number of bytes for indexed variables, in
755* the specified zone, using _zoneAlloc.
756**********************************************************************/
13d88034 757id class_createInstanceFromZone (Class aClass,
41c8faa5
A
758 unsigned nIvarBytes,
759 void * z)
13d88034 760{
41c8faa5
A
761 // _zoneAlloc can be overridden, but is initially set to
762 // _internal_class_createInstanceFromZone
763 return (*_zoneAlloc) (aClass, nIvarBytes, z);
764}
13d88034
A
765
766/***********************************************************************
41c8faa5
A
767* class_createInstance. Allocate an instance of the specified class with
768* the specified number of bytes for indexed variables, using _alloc.
769**********************************************************************/
13d88034 770id class_createInstance (Class aClass,
41c8faa5 771 unsigned nIvarBytes)
13d88034 772{
41c8faa5
A
773 // _alloc can be overridden, but is initially set to
774 // _internal_class_createInstance
775 return (*_alloc) (aClass, nIvarBytes);
776}
13d88034
A
777
778/***********************************************************************
41c8faa5
A
779* class_setVersion. Record the specified version with the class.
780**********************************************************************/
13d88034 781void class_setVersion (Class aClass,
41c8faa5 782 int version)
13d88034 783{
41c8faa5 784 ((struct objc_class *) aClass)->version = version;
13d88034
A
785}
786
787/***********************************************************************
41c8faa5
A
788* class_getVersion. Return the version recorded with the class.
789**********************************************************************/
13d88034
A
790int class_getVersion (Class aClass)
791{
41c8faa5 792 return ((struct objc_class *) aClass)->version;
13d88034
A
793}
794
13d88034
A
795
796static inline Method _findNamedMethodInList(struct objc_method_list * mlist, const char *meth_name) {
797 int i;
798 if (!mlist) return NULL;
799 for (i = 0; i < mlist->method_count; i++) {
41c8faa5
A
800 Method m = &mlist->method_list[i];
801 if (*((const char *)m->method_name) == *meth_name && 0 == strcmp((const char *)(m->method_name), meth_name)) {
802 return m;
803 }
13d88034
A
804 }
805 return NULL;
806}
807
2bfd4448
A
808
809/***********************************************************************
810* fixupSelectorsInMethodList
811* Uniques selectors in the given method list.
812* The given method list must be non-NULL and not already fixed-up.
813* If the class was loaded from a bundle:
814* fixes up the given list in place with heap-allocated selector strings
815* If the class was not from a bundle:
816* allocates a copy of the method list, fixes up the copy, and returns
817* the copy. The given list is unmodified.
818*
819* If cls is already in use, methodListLock must be held by the caller.
820**********************************************************************/
821// Fixed-up method lists get mlist->obsolete = _OBJC_FIXED_UP.
822#define _OBJC_FIXED_UP ((void *)1771)
823
824static struct objc_method_list *fixupSelectorsInMethodList(Class cls, struct objc_method_list *mlist)
825{
826 unsigned i, size;
827 Method method;
828 struct objc_method_list *old_mlist;
829
830 if ( ! mlist ) return (struct objc_method_list *)0;
831 if ( mlist->obsolete != _OBJC_FIXED_UP ) {
832 BOOL isBundle = CLS_GETINFO(cls, CLS_FROM_BUNDLE) ? YES : NO;
833 if (!isBundle) {
834 old_mlist = mlist;
835 size = sizeof(struct objc_method_list) - sizeof(struct objc_method) + old_mlist->method_count * sizeof(struct objc_method);
836 mlist = _malloc_internal(size);
837 memmove(mlist, old_mlist, size);
838 } else {
839 // Mach-O bundles are fixed up in place.
840 // This prevents leaks when a bundle is unloaded.
841 }
842 sel_lock();
843 for ( i = 0; i < mlist->method_count; i += 1 ) {
844 method = &mlist->method_list[i];
845 method->method_name =
846 sel_registerNameNoLock((const char *)method->method_name, isBundle); // Always copy selector data from bundles.
847 }
848 sel_unlock();
849 mlist->obsolete = _OBJC_FIXED_UP;
850 }
851 return mlist;
852}
853
854
855/***********************************************************************
856* nextMethodList
857* Returns successive method lists from the given class.
858* Method lists are returned in method search order (i.e. highest-priority
859* implementations first).
860* All necessary method list fixups are performed, so the
861* returned method list is fully-constructed.
862*
863* If cls is already in use, methodListLock must be held by the caller.
864* For full thread-safety, methodListLock must be continuously held by the
865* caller across all calls to nextMethodList(). If the lock is released,
866* the bad results listed in class_nextMethodList() may occur.
867*
868* void *iterator = NULL;
869* struct objc_method_list *mlist;
870* OBJC_LOCK(&methodListLock);
871* while ((mlist = nextMethodList(cls, &iterator))) {
872* // do something with mlist
873* }
874* OBJC_UNLOCK(&methodListLock);
875**********************************************************************/
876static struct objc_method_list *nextMethodList(struct objc_class *cls,
877 void **it)
878{
879 uintptr_t index = *(uintptr_t *)it;
880 struct objc_method_list **resultp;
881
882 if (index == 0) {
883 // First call to nextMethodList.
884 if (!cls->methodLists) {
885 resultp = NULL;
886 } else if (cls->info & CLS_NO_METHOD_ARRAY) {
887 resultp = (struct objc_method_list **)&cls->methodLists;
888 } else {
889 resultp = &cls->methodLists[0];
890 if (!*resultp || *resultp == END_OF_METHODS_LIST) {
891 resultp = NULL;
892 }
893 }
894 } else {
895 // Subsequent call to nextMethodList.
896 if (!cls->methodLists) {
897 resultp = NULL;
898 } else if (cls->info & CLS_NO_METHOD_ARRAY) {
899 resultp = NULL;
900 } else {
901 resultp = &cls->methodLists[index];
902 if (!*resultp || *resultp == END_OF_METHODS_LIST) {
903 resultp = NULL;
904 }
905 }
906 }
907
908 // resultp now is NULL, meaning there are no more method lists,
909 // OR the address of the method list pointer to fix up and return.
910
911 if (resultp) {
912 if (*resultp && (*resultp)->obsolete != _OBJC_FIXED_UP) {
913 *resultp = fixupSelectorsInMethodList(cls, *resultp);
914 }
915 *it = (void *)(index + 1);
916 return *resultp;
917 } else {
918 *it = 0;
919 return NULL;
920 }
921}
922
923
924/* These next three functions are the heart of ObjC method lookup.
925 * If the class is currently in use, methodListLock must be held by the caller.
926 */
13d88034
A
927static inline Method _findMethodInList(struct objc_method_list * mlist, SEL sel) {
928 int i;
929 if (!mlist) return NULL;
930 for (i = 0; i < mlist->method_count; i++) {
41c8faa5
A
931 Method m = &mlist->method_list[i];
932 if (m->method_name == sel) {
933 return m;
934 }
13d88034
A
935 }
936 return NULL;
937}
938
2bfd4448 939static inline Method _findMethodInClass(Class cls, SEL sel) __attribute__((always_inline));
13d88034 940static inline Method _findMethodInClass(Class cls, SEL sel) {
2bfd4448
A
941 // Flattened version of nextMethodList(). The optimizer doesn't
942 // do a good job with hoisting the conditionals out of the loop.
943 // Conceptually, this looks like:
944 // while ((mlist = nextMethodList(cls, &iterator))) {
945 // Method m = _findMethodInList(mlist, sel);
946 // if (m) return m;
947 // }
948
949 if (!cls->methodLists) {
950 // No method lists.
951 return NULL;
952 }
953 else if (cls->info & CLS_NO_METHOD_ARRAY) {
954 // One method list.
955 struct objc_method_list **mlistp;
956 mlistp = (struct objc_method_list **)&cls->methodLists;
957 if ((*mlistp)->obsolete != _OBJC_FIXED_UP) {
958 *mlistp = fixupSelectorsInMethodList(cls, *mlistp);
959 }
960 return _findMethodInList(*mlistp, sel);
961 }
962 else {
963 // Multiple method lists.
964 struct objc_method_list **mlistp;
965 for (mlistp = cls->methodLists;
966 *mlistp != NULL && *mlistp != END_OF_METHODS_LIST;
967 mlistp++)
968 {
969 Method m;
970 if ((*mlistp)->obsolete != _OBJC_FIXED_UP) {
971 *mlistp = fixupSelectorsInMethodList(cls, *mlistp);
972 }
973 m = _findMethodInList(*mlistp, sel);
974 if (m) return m;
975 }
976 return NULL;
13d88034 977 }
13d88034
A
978}
979
980static inline Method _getMethod(Class cls, SEL sel) {
981 for (; cls; cls = cls->super_class) {
2bfd4448
A
982 Method m;
983 m = _findMethodInClass(cls, sel);
41c8faa5 984 if (m) return m;
13d88034
A
985 }
986 return NULL;
987}
988
989
2bfd4448
A
990// fixme for gc debugging temporary use
991__private_extern__ IMP findIMPInClass(Class cls, SEL sel)
992{
993 Method m = _findMethodInClass(cls, sel);
994 if (m) return m->method_imp;
995 else return NULL;
996}
997
13d88034 998/***********************************************************************
41c8faa5
A
999* class_getInstanceMethod. Return the instance method for the
1000* specified class and selector.
1001**********************************************************************/
13d88034 1002Method class_getInstanceMethod (Class aClass,
41c8faa5 1003 SEL aSelector)
13d88034 1004{
2bfd4448
A
1005 Method result;
1006
41c8faa5
A
1007 // Need both a class and a selector
1008 if (!aClass || !aSelector)
1009 return NULL;
13d88034 1010
41c8faa5 1011 // Go to the class
2bfd4448
A
1012 OBJC_LOCK(&methodListLock);
1013 result = _getMethod (aClass, aSelector);
1014 OBJC_UNLOCK(&methodListLock);
1015 return result;
13d88034
A
1016}
1017
1018/***********************************************************************
41c8faa5
A
1019* class_getClassMethod. Return the class method for the specified
1020* class and selector.
1021**********************************************************************/
13d88034 1022Method class_getClassMethod (Class aClass,
41c8faa5 1023 SEL aSelector)
13d88034 1024{
2bfd4448
A
1025 Method result;
1026
41c8faa5
A
1027 // Need both a class and a selector
1028 if (!aClass || !aSelector)
1029 return NULL;
13d88034 1030
41c8faa5 1031 // Go to the class or isa
2bfd4448
A
1032 OBJC_LOCK(&methodListLock);
1033 result = _getMethod (GETMETA(aClass), aSelector);
1034 OBJC_UNLOCK(&methodListLock);
1035 return result;
13d88034
A
1036}
1037
1038/***********************************************************************
41c8faa5
A
1039* class_getVariable. Return the named instance variable.
1040**********************************************************************/
13d88034 1041static Ivar class_getVariable (Class cls,
41c8faa5
A
1042 const char * name)
1043{
1044 struct objc_class * thisCls;
1045
1046 // Outer loop - search the class and its superclasses
1047 for (thisCls = cls; thisCls != Nil; thisCls = ((struct objc_class *) thisCls)->super_class)
1048 {
1049 int index;
1050 Ivar thisIvar;
1051
1052 // Skip class having no ivars
1053 if (!thisCls->ivars)
1054 continue;
1055
1056 // Inner loop - search the given class
1057 thisIvar = &thisCls->ivars->ivar_list[0];
1058 for (index = 0; index < thisCls->ivars->ivar_count; index += 1)
1059 {
1060 // Check this ivar's name. Be careful because the
1061 // compiler generates ivar entries with NULL ivar_name
1062 // (e.g. for anonymous bit fields).
1063 if ((thisIvar->ivar_name) &&
1064 (strcmp (name, thisIvar->ivar_name) == 0))
1065 return thisIvar;
1066
1067 // Move to next ivar
1068 thisIvar += 1;
1069 }
1070 }
13d88034 1071
41c8faa5
A
1072 // Not found
1073 return NULL;
13d88034
A
1074}
1075
1076/***********************************************************************
41c8faa5
A
1077* class_getInstanceVariable. Return the named instance variable.
1078*
1079* Someday add class_getClassVariable ().
1080**********************************************************************/
13d88034 1081Ivar class_getInstanceVariable (Class aClass,
41c8faa5 1082 const char * name)
13d88034 1083{
41c8faa5
A
1084 // Must have a class and a name
1085 if (!aClass || !name)
1086 return NULL;
13d88034 1087
41c8faa5
A
1088 // Look it up
1089 return class_getVariable (aClass, name);
13d88034
A
1090}
1091
1092/***********************************************************************
41c8faa5
A
1093* flush_caches. Flush the instance and optionally class method caches
1094* of cls and all its subclasses.
1095*
1096* Specifying Nil for the class "all classes."
1097**********************************************************************/
1f20c7a7 1098static void flush_caches(Class cls, BOOL flush_meta)
13d88034 1099{
41c8faa5
A
1100 int numClasses = 0, newNumClasses;
1101 struct objc_class * * classes = NULL;
1102 int i;
1103 struct objc_class * clsObject;
13d88034 1104#ifdef OBJC_INSTRUMENTED
41c8faa5
A
1105 unsigned int classesVisited;
1106 unsigned int subclassCount;
13d88034
A
1107#endif
1108
41c8faa5 1109 // Do nothing if class has no cache
1f20c7a7 1110 // This check is safe to do without any cache locks.
41c8faa5
A
1111 if (cls && !((struct objc_class *) cls)->cache)
1112 return;
1113
1114 newNumClasses = objc_getClassList((Class *)NULL, 0);
1115 while (numClasses < newNumClasses) {
1116 numClasses = newNumClasses;
2bfd4448 1117 classes = _realloc_internal(classes, sizeof(Class) * numClasses);
41c8faa5
A
1118 newNumClasses = objc_getClassList((Class *)classes, numClasses);
1119 }
1120 numClasses = newNumClasses;
1121
1f20c7a7
A
1122 OBJC_LOCK(&cacheUpdateLock);
1123
41c8faa5
A
1124 // Handle nil and root instance class specially: flush all
1125 // instance and class method caches. Nice that this
1126 // loop is linear vs the N-squared loop just below.
1127 if (!cls || !((struct objc_class *) cls)->super_class)
1128 {
13d88034 1129#ifdef OBJC_INSTRUMENTED
41c8faa5
A
1130 LinearFlushCachesCount += 1;
1131 classesVisited = 0;
1132 subclassCount = 0;
13d88034 1133#endif
41c8faa5
A
1134 // Traverse all classes in the hash table
1135 for (i = 0; i < numClasses; i++)
1136 {
1137 struct objc_class * metaClsObject;
13d88034 1138#ifdef OBJC_INSTRUMENTED
41c8faa5 1139 classesVisited += 1;
13d88034 1140#endif
41c8faa5
A
1141 clsObject = classes[i];
1142
1143 // Skip class that is known not to be a subclass of this root
1144 // (the isa pointer of any meta class points to the meta class
1145 // of the root).
1146 // NOTE: When is an isa pointer of a hash tabled class ever nil?
1f20c7a7
A
1147 metaClsObject = clsObject->isa;
1148 if (cls && metaClsObject && cls->isa != metaClsObject->isa)
1149 {
41c8faa5 1150 continue;
1f20c7a7 1151 }
13d88034
A
1152
1153#ifdef OBJC_INSTRUMENTED
41c8faa5 1154 subclassCount += 1;
13d88034
A
1155#endif
1156
1f20c7a7
A
1157 _cache_flush (clsObject);
1158 if (flush_meta && metaClsObject != NULL) {
1159 _cache_flush (metaClsObject);
1160 }
41c8faa5 1161 }
13d88034 1162#ifdef OBJC_INSTRUMENTED
41c8faa5
A
1163 LinearFlushCachesVisitedCount += classesVisited;
1164 if (classesVisited > MaxLinearFlushCachesVisitedCount)
1165 MaxLinearFlushCachesVisitedCount = classesVisited;
1166 IdealFlushCachesCount += subclassCount;
1167 if (subclassCount > MaxIdealFlushCachesCount)
1168 MaxIdealFlushCachesCount = subclassCount;
13d88034
A
1169#endif
1170
1f20c7a7 1171 OBJC_UNLOCK(&cacheUpdateLock);
2bfd4448 1172 _free_internal(classes);
41c8faa5
A
1173 return;
1174 }
13d88034 1175
41c8faa5
A
1176 // Outer loop - flush any cache that could now get a method from
1177 // cls (i.e. the cache associated with cls and any of its subclasses).
13d88034 1178#ifdef OBJC_INSTRUMENTED
41c8faa5
A
1179 NonlinearFlushCachesCount += 1;
1180 classesVisited = 0;
1181 subclassCount = 0;
13d88034 1182#endif
41c8faa5
A
1183 for (i = 0; i < numClasses; i++)
1184 {
1185 struct objc_class * clsIter;
13d88034
A
1186
1187#ifdef OBJC_INSTRUMENTED
41c8faa5 1188 NonlinearFlushCachesClassCount += 1;
13d88034 1189#endif
41c8faa5 1190 clsObject = classes[i];
13d88034 1191
41c8faa5
A
1192 // Inner loop - Process a given class
1193 clsIter = clsObject;
1194 while (clsIter)
1195 {
13d88034
A
1196
1197#ifdef OBJC_INSTRUMENTED
41c8faa5 1198 classesVisited += 1;
13d88034 1199#endif
41c8faa5
A
1200 // Flush clsObject instance method cache if
1201 // clsObject is a subclass of cls, or is cls itself
1202 // Flush the class method cache if that was asked for
1203 if (clsIter == cls)
1204 {
13d88034 1205#ifdef OBJC_INSTRUMENTED
41c8faa5 1206 subclassCount += 1;
13d88034 1207#endif
41c8faa5
A
1208 _cache_flush (clsObject);
1209 if (flush_meta)
1210 _cache_flush (clsObject->isa);
1211
1212 break;
1213
1214 }
1215
1216 // Flush clsObject class method cache if cls is
1217 // the meta class of clsObject or of one
1218 // of clsObject's superclasses
1219 else if (clsIter->isa == cls)
1220 {
13d88034 1221#ifdef OBJC_INSTRUMENTED
41c8faa5 1222 subclassCount += 1;
13d88034 1223#endif
41c8faa5
A
1224 _cache_flush (clsObject->isa);
1225 break;
1226 }
1227
1228 // Move up superclass chain
1229 else if (ISINITIALIZED(clsIter))
1230 clsIter = clsIter->super_class;
1231
1232 // clsIter is not initialized, so its cache
1233 // must be empty. This happens only when
1234 // clsIter == clsObject, because
1235 // superclasses are initialized before
1236 // subclasses, and this loop traverses
1237 // from sub- to super- classes.
1238 else
1239 break;
1240 }
1241 }
13d88034 1242#ifdef OBJC_INSTRUMENTED
41c8faa5
A
1243 NonlinearFlushCachesVisitedCount += classesVisited;
1244 if (classesVisited > MaxNonlinearFlushCachesVisitedCount)
1245 MaxNonlinearFlushCachesVisitedCount = classesVisited;
1246 IdealFlushCachesCount += subclassCount;
1247 if (subclassCount > MaxIdealFlushCachesCount)
1248 MaxIdealFlushCachesCount = subclassCount;
13d88034
A
1249#endif
1250
1f20c7a7 1251 OBJC_UNLOCK(&cacheUpdateLock);
2bfd4448 1252 _free_internal(classes);
13d88034
A
1253}
1254
1255/***********************************************************************
41c8faa5
A
1256* _objc_flush_caches. Flush the caches of the specified class and any
1257* of its subclasses. If cls is a meta-class, only meta-class (i.e.
1f20c7a7 1258* class method) caches are flushed. If cls is an instance-class, both
41c8faa5
A
1259* instance-class and meta-class caches are flushed.
1260**********************************************************************/
13d88034
A
1261void _objc_flush_caches (Class cls)
1262{
41c8faa5 1263 flush_caches (cls, YES);
13d88034
A
1264}
1265
1266/***********************************************************************
41c8faa5
A
1267* do_not_remove_this_dummy_function.
1268**********************************************************************/
13d88034
A
1269void do_not_remove_this_dummy_function (void)
1270{
41c8faa5 1271 (void) class_nextMethodList (NULL, NULL);
13d88034
A
1272}
1273
2bfd4448 1274
13d88034 1275/***********************************************************************
41c8faa5 1276* class_nextMethodList.
2bfd4448 1277* External version of nextMethodList().
41c8faa5 1278*
2bfd4448
A
1279* This function is not fully thread-safe. A series of calls to
1280* class_nextMethodList() may fail if methods are added to or removed
1281* from the class between calls.
1282* If methods are added between calls to class_nextMethodList(), it may
1283* return previously-returned method lists again, and may fail to return
1284* newly-added lists.
1285* If methods are removed between calls to class_nextMethodList(), it may
1286* omit surviving method lists or simply crash.
41c8faa5 1287**********************************************************************/
13d88034 1288OBJC_EXPORT struct objc_method_list * class_nextMethodList (Class cls,
41c8faa5 1289 void ** it)
13d88034 1290{
2bfd4448
A
1291 struct objc_method_list *result;
1292 OBJC_LOCK(&methodListLock);
1293 result = nextMethodList(cls, it);
1294 OBJC_UNLOCK(&methodListLock);
1295 return result;
13d88034
A
1296}
1297
1298/***********************************************************************
41c8faa5
A
1299* _dummy.
1300**********************************************************************/
13d88034
A
1301void _dummy (void)
1302{
41c8faa5 1303 (void) class_nextMethodList (Nil, NULL);
13d88034
A
1304}
1305
1306/***********************************************************************
41c8faa5
A
1307* class_addMethods.
1308*
1309* Formerly class_addInstanceMethods ()
1310**********************************************************************/
13d88034 1311void class_addMethods (Class cls,
41c8faa5 1312 struct objc_method_list * meths)
13d88034 1313{
2bfd4448
A
1314 // Add the methods.
1315 OBJC_LOCK(&methodListLock);
1316 _objc_insertMethods(cls, meths);
1317 OBJC_UNLOCK(&methodListLock);
41c8faa5
A
1318
1319 // Must flush when dynamically adding methods. No need to flush
1320 // all the class method caches. If cls is a meta class, though,
1321 // this will still flush it and any of its sub-meta classes.
1322 flush_caches (cls, NO);
13d88034
A
1323}
1324
1325/***********************************************************************
41c8faa5
A
1326* class_addClassMethods.
1327*
1328* Obsolete (for binary compatibility only).
1329**********************************************************************/
13d88034 1330void class_addClassMethods (Class cls,
41c8faa5 1331 struct objc_method_list * meths)
13d88034 1332{
41c8faa5 1333 class_addMethods (((struct objc_class *) cls)->isa, meths);
13d88034
A
1334}
1335
1336/***********************************************************************
41c8faa5
A
1337* class_removeMethods.
1338**********************************************************************/
13d88034 1339void class_removeMethods (Class cls,
41c8faa5 1340 struct objc_method_list * meths)
13d88034 1341{
2bfd4448
A
1342 // Remove the methods
1343 OBJC_LOCK(&methodListLock);
1344 _objc_removeMethods(cls, meths);
1345 OBJC_UNLOCK(&methodListLock);
41c8faa5
A
1346
1347 // Must flush when dynamically removing methods. No need to flush
1348 // all the class method caches. If cls is a meta class, though,
1349 // this will still flush it and any of its sub-meta classes.
1350 flush_caches (cls, NO);
13d88034
A
1351}
1352
1353/***********************************************************************
41c8faa5
A
1354* addClassToOriginalClass. Add to a hash table of classes involved in
1355* a posing situation. We use this when we need to get to the "original"
1356* class for some particular name through the function objc_getOrigClass.
1357* For instance, the implementation of [super ...] will use this to be
1358* sure that it gets hold of the correct super class, so that no infinite
1359* loops will occur if the class it appears in is involved in posing.
1360*
1361* We use the classLock to guard the hash table.
1362*
1363* See tracker bug #51856.
1364**********************************************************************/
13d88034
A
1365
1366static NXMapTable * posed_class_hash = NULL;
1367static NXMapTable * posed_class_to_original_class_hash = NULL;
1368
1369static void addClassToOriginalClass (Class posingClass,
41c8faa5
A
1370 Class originalClass)
1371{
1372 // Install hash table when it is first needed
1373 if (!posed_class_to_original_class_hash)
1374 {
1375 posed_class_to_original_class_hash =
1376 NXCreateMapTableFromZone (NXPtrValueMapPrototype,
1377 8,
2bfd4448 1378 _objc_internal_zone ());
41c8faa5 1379 }
13d88034 1380
41c8faa5
A
1381 // Add pose to hash table
1382 NXMapInsert (posed_class_to_original_class_hash,
1383 posingClass,
1384 originalClass);
13d88034
A
1385}
1386
1387/***********************************************************************
41c8faa5
A
1388* getOriginalClassForPosingClass.
1389**********************************************************************/
13d88034
A
1390Class getOriginalClassForPosingClass (Class posingClass)
1391{
41c8faa5 1392 return NXMapGet (posed_class_to_original_class_hash, posingClass);
13d88034
A
1393}
1394
1395/***********************************************************************
41c8faa5
A
1396* objc_getOrigClass.
1397**********************************************************************/
13d88034
A
1398Class objc_getOrigClass (const char * name)
1399{
41c8faa5 1400 struct objc_class * ret;
13d88034 1401
41c8faa5
A
1402 // Look for class among the posers
1403 ret = Nil;
1404 OBJC_LOCK(&classLock);
1405 if (posed_class_hash)
1406 ret = (Class) NXMapGet (posed_class_hash, name);
1407 OBJC_UNLOCK(&classLock);
1408 if (ret)
1409 return ret;
13d88034 1410
41c8faa5
A
1411 // Not a poser. Do a normal lookup.
1412 ret = objc_getClass (name);
1413 if (!ret)
1414 _objc_inform ("class `%s' not linked into application", name);
13d88034 1415
41c8faa5 1416 return ret;
13d88034
A
1417}
1418
1419/***********************************************************************
41c8faa5
A
1420* _objc_addOrigClass. This function is only used from class_poseAs.
1421* Registers the original class names, before they get obscured by
1422* posing, so that [super ..] will work correctly from categories
1423* in posing classes and in categories in classes being posed for.
1424**********************************************************************/
13d88034
A
1425static void _objc_addOrigClass (Class origClass)
1426{
41c8faa5 1427 OBJC_LOCK(&classLock);
13d88034 1428
41c8faa5
A
1429 // Create the poser's hash table on first use
1430 if (!posed_class_hash)
1431 {
1432 posed_class_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype,
1433 8,
2bfd4448 1434 _objc_internal_zone ());
41c8faa5 1435 }
13d88034 1436
41c8faa5
A
1437 // Add the named class iff it is not already there (or collides?)
1438 if (NXMapGet (posed_class_hash, ((struct objc_class *)origClass)->name) == 0)
1439 NXMapInsert (posed_class_hash, ((struct objc_class *)origClass)->name, origClass);
1440
1441 OBJC_UNLOCK(&classLock);
13d88034
A
1442}
1443
1444/***********************************************************************
41c8faa5
A
1445* class_poseAs.
1446*
1447* !!! class_poseAs () does not currently flush any caches.
1448**********************************************************************/
13d88034 1449Class class_poseAs (Class imposter,
41c8faa5
A
1450 Class original)
1451{
1452 struct objc_class * clsObject;
41c8faa5
A
1453 char * imposterNamePtr;
1454 NXHashTable * class_hash;
1455 NXHashState state;
1456 struct objc_class * copy;
13d88034 1457#ifdef OBJC_CLASS_REFS
41c8faa5 1458 header_info * hInfo;
13d88034
A
1459#endif
1460
41c8faa5
A
1461 // Trivial case is easy
1462 if (imposter == original)
1463 return imposter;
1464
1465 // Imposter must be an immediate subclass of the original
1466 if (((struct objc_class *)imposter)->super_class != original) {
41c8faa5
A
1467 __objc_error(imposter, _errNotSuper, ((struct objc_class *)imposter)->name, ((struct objc_class *)original)->name);
1468 }
1469
1470 // Can't pose when you have instance variables (how could it work?)
1471 if (((struct objc_class *)imposter)->ivars) {
41c8faa5
A
1472 __objc_error(imposter, _errNewVars, ((struct objc_class *)imposter)->name, ((struct objc_class *)original)->name, ((struct objc_class *)imposter)->name);
1473 }
1474
1475 // Build a string to use to replace the name of the original class.
1f20c7a7 1476 #define imposterNamePrefix "_%"
2bfd4448 1477 imposterNamePtr = _malloc_internal(strlen(((struct objc_class *)original)->name) + strlen(imposterNamePrefix) + 1);
1f20c7a7
A
1478 strcpy(imposterNamePtr, imposterNamePrefix);
1479 strcat(imposterNamePtr, ((struct objc_class *)original)->name);
1480 #undef imposterNamePrefix
41c8faa5
A
1481
1482 // We lock the class hashtable, so we are thread safe with respect to
1483 // calls to objc_getClass (). However, the class names are not
1484 // changed atomically, nor are all of the subclasses updated
1485 // atomically. I have ordered the operations so that you will
1486 // never crash, but you may get inconsistent results....
1487
1488 // Register the original class so that [super ..] knows
1489 // exactly which classes are the "original" classes.
1490 _objc_addOrigClass (original);
1491 _objc_addOrigClass (imposter);
1492
2bfd4448
A
1493 // Copy the imposter, so that the imposter can continue
1494 // its normal life in addition to changing the behavior of
1495 // the original. As a hack we don't bother to copy the metaclass.
1496 // For some reason we modify the original rather than the copy.
1497 copy = (*_zoneAlloc)(imposter->isa, sizeof(struct objc_class), _objc_internal_zone());
1498 memmove(copy, imposter, sizeof(struct objc_class));
1499
41c8faa5
A
1500 OBJC_LOCK(&classLock);
1501
1502 class_hash = objc_getClasses ();
1503
1504 // Remove both the imposter and the original class.
1505 NXHashRemove (class_hash, imposter);
1506 NXHashRemove (class_hash, original);
1507
41c8faa5
A
1508 NXHashInsert (class_hash, copy);
1509 addClassToOriginalClass (imposter, copy);
1510
1511 // Mark the imposter as such
2bfd4448
A
1512 _class_setInfo(imposter, CLS_POSING);
1513 _class_setInfo(imposter->isa, CLS_POSING);
41c8faa5
A
1514
1515 // Change the name of the imposter to that of the original class.
1516 ((struct objc_class *)imposter)->name = ((struct objc_class *)original)->name;
1517 ((struct objc_class *)imposter)->isa->name = ((struct objc_class *)original)->isa->name;
1518
1519 // Also copy the version field to avoid archiving problems.
1520 ((struct objc_class *)imposter)->version = ((struct objc_class *)original)->version;
1521
1522 // Change all subclasses of the original to point to the imposter.
1523 state = NXInitHashState (class_hash);
1524 while (NXNextHashState (class_hash, &state, (void **) &clsObject))
1525 {
1526 while ((clsObject) && (clsObject != imposter) &&
1527 (clsObject != copy))
1528 {
1529 if (clsObject->super_class == original)
1530 {
1531 clsObject->super_class = imposter;
1532 clsObject->isa->super_class = ((struct objc_class *)imposter)->isa;
1533 // We must flush caches here!
1534 break;
1535 }
1536
1537 clsObject = clsObject->super_class;
1538 }
1539 }
13d88034
A
1540
1541#ifdef OBJC_CLASS_REFS
41c8faa5
A
1542 // Replace the original with the imposter in all class refs
1543 // Major loop - process all headers
1544 for (hInfo = _objc_headerStart(); hInfo != NULL; hInfo = hInfo->next)
1545 {
1546 Class * cls_refs;
1547 unsigned int refCount;
1548 unsigned int index;
1549
1550 // Get refs associated with this header
1551 cls_refs = (Class *) _getObjcClassRefs ((headerType *) hInfo->mhdr, &refCount);
1552 if (!cls_refs || !refCount)
1553 continue;
1554
1555 // Minor loop - process this header's refs
1556 cls_refs = (Class *) ((unsigned long) cls_refs + hInfo->image_slide);
1557 for (index = 0; index < refCount; index += 1)
1558 {
1559 if (cls_refs[index] == original)
1560 cls_refs[index] = imposter;
1561 }
1562 }
13d88034
A
1563#endif // OBJC_CLASS_REFS
1564
41c8faa5
A
1565 // Change the name of the original class.
1566 ((struct objc_class *)original)->name = imposterNamePtr + 1;
1567 ((struct objc_class *)original)->isa->name = imposterNamePtr;
1568
1569 // Restore the imposter and the original class with their new names.
1570 NXHashInsert (class_hash, imposter);
1571 NXHashInsert (class_hash, original);
1572
1573 OBJC_UNLOCK(&classLock);
1574
1575 return imposter;
13d88034
A
1576}
1577
1578/***********************************************************************
41c8faa5
A
1579* _freedHandler.
1580**********************************************************************/
13d88034 1581static void _freedHandler (id self,
41c8faa5 1582 SEL sel)
13d88034 1583{
41c8faa5 1584 __objc_error (self, _errFreedObject, SELNAME(sel), self);
13d88034
A
1585}
1586
1587/***********************************************************************
41c8faa5
A
1588* _nonexistentHandler.
1589**********************************************************************/
13d88034 1590static void _nonexistentHandler (id self,
41c8faa5 1591 SEL sel)
13d88034 1592{
41c8faa5 1593 __objc_error (self, _errNonExistentObject, SELNAME(sel), self);
13d88034
A
1594}
1595
13d88034 1596/***********************************************************************
41c8faa5
A
1597* class_respondsToMethod.
1598*
1599* Called from -[Object respondsTo:] and +[Object instancesRespondTo:]
1600**********************************************************************/
13d88034 1601BOOL class_respondsToMethod (Class cls,
41c8faa5
A
1602 SEL sel)
1603{
41c8faa5 1604 Method meth;
1f20c7a7 1605 IMP imp;
41c8faa5
A
1606
1607 // No one responds to zero!
1608 if (!sel)
1609 return NO;
1610
1f20c7a7
A
1611 imp = _cache_getImp(cls, sel);
1612 if (imp) {
1613 // Found method in cache.
1614 // If the cache entry is forward::, the class does not respond to sel.
1615 return (imp != &_objc_msgForward);
41c8faa5
A
1616 }
1617
1618 // Handle cache miss
2bfd4448 1619 OBJC_LOCK(&methodListLock);
41c8faa5 1620 meth = _getMethod(cls, sel);
2bfd4448 1621 OBJC_UNLOCK(&methodListLock);
41c8faa5 1622 if (meth) {
1f20c7a7 1623 _cache_fill(cls, meth, sel);
41c8faa5
A
1624 return YES;
1625 }
1626
1f20c7a7
A
1627 // Not implemented. Use _objc_msgForward.
1628 _cache_addForwardEntry(cls, sel);
41c8faa5 1629
41c8faa5 1630 return NO;
41c8faa5
A
1631}
1632
1633
1634/***********************************************************************
1635* class_lookupMethod.
1636*
1637* Called from -[Object methodFor:] and +[Object instanceMethodFor:]
1638**********************************************************************/
13d88034 1639IMP class_lookupMethod (Class cls,
41c8faa5
A
1640 SEL sel)
1641{
1f20c7a7 1642 IMP imp;
41c8faa5
A
1643
1644 // No one responds to zero!
1645 if (!sel) {
41c8faa5
A
1646 __objc_error(cls, _errBadSel, sel);
1647 }
1648
1f20c7a7
A
1649 imp = _cache_getImp(cls, sel);
1650 if (imp) return imp;
41c8faa5
A
1651
1652 // Handle cache miss
1f20c7a7 1653 return _class_lookupMethodAndLoadCache (cls, sel);
41c8faa5
A
1654}
1655
1656/***********************************************************************
2bfd4448
A
1657* lookupNamedMethodInMethodList
1658* Only called to find +load/-.cxx_construct/-.cxx_destruct methods,
1659* without fixing up the entire method list.
1660* The class is not yet in use, so methodListLock is not taken.
41c8faa5 1661**********************************************************************/
2bfd4448 1662__private_extern__ IMP lookupNamedMethodInMethodList(struct objc_method_list *mlist, const char *meth_name)
13d88034
A
1663{
1664 Method m = meth_name ? _findNamedMethodInList(mlist, meth_name) : NULL;
1665 return (m ? m->method_imp : NULL);
1666}
1667
1f20c7a7 1668
13d88034 1669/***********************************************************************
1f20c7a7 1670* _cache_malloc.
41c8faa5 1671*
1f20c7a7 1672* Called from _cache_create() and cache_expand()
2bfd4448 1673* Cache locks: cacheUpdateLock must be held by the caller.
41c8faa5 1674**********************************************************************/
1f20c7a7 1675static Cache _cache_malloc(int slotCount)
13d88034 1676{
1f20c7a7
A
1677 Cache new_cache;
1678 size_t size;
13d88034 1679
41c8faa5 1680 // Allocate table (why not check for failure?)
1f20c7a7 1681 size = sizeof(struct objc_cache) + TABLE_SIZE(slotCount);
13d88034 1682#ifdef OBJC_INSTRUMENTED
2bfd4448 1683 // Custom cache allocator can't handle instrumentation.
1f20c7a7 1684 size += sizeof(CacheInstrumentation);
2bfd4448 1685 new_cache = _calloc_internal(size, 1);
41c8faa5 1686 new_cache->mask = slotCount - 1;
2bfd4448
A
1687#else
1688 if (size < CACHE_QUANTUM || UseInternalZone) {
1689 new_cache = _calloc_internal(size, 1);
1690 new_cache->mask = slotCount - 1;
1691 // occupied and buckets and instrumentation are all zero
1692 } else {
1693 new_cache = cache_allocator_calloc(size);
1694 // mask is already set
1695 // occupied and buckets and instrumentation are all zero
1696 }
1697#endif
13d88034 1698
1f20c7a7
A
1699 return new_cache;
1700}
13d88034 1701
1f20c7a7
A
1702
1703/***********************************************************************
1704* _cache_create.
1705*
1706* Called from _cache_expand().
1707* Cache locks: cacheUpdateLock must be held by the caller.
1708**********************************************************************/
1709Cache _cache_create (Class cls)
1710{
1711 Cache new_cache;
1712 int slotCount;
1713
1714 // Select appropriate size
1715 slotCount = (ISMETA(cls)) ? INIT_META_CACHE_SIZE : INIT_CACHE_SIZE;
1716
1717 new_cache = _cache_malloc(slotCount);
13d88034 1718
41c8faa5
A
1719 // Install the cache
1720 ((struct objc_class *)cls)->cache = new_cache;
13d88034 1721
41c8faa5
A
1722 // Clear the cache flush flag so that we will not flush this cache
1723 // before expanding it for the first time.
2bfd4448 1724 _class_clearInfo(cls, CLS_FLUSH_CACHE);
13d88034 1725
41c8faa5
A
1726 // Clear the grow flag so that we will re-use the current storage,
1727 // rather than actually grow the cache, when expanding the cache
1728 // for the first time
1729 if (_class_slow_grow)
2bfd4448 1730 _class_clearInfo(cls, CLS_GROW_CACHE);
13d88034 1731
41c8faa5
A
1732 // Return our creation
1733 return new_cache;
13d88034
A
1734}
1735
1736/***********************************************************************
41c8faa5
A
1737* _cache_expand.
1738*
41c8faa5 1739* Called from _cache_fill ()
1f20c7a7 1740* Cache locks: cacheUpdateLock must be held by the caller.
41c8faa5 1741**********************************************************************/
13d88034
A
1742static Cache _cache_expand (Class cls)
1743{
41c8faa5
A
1744 Cache old_cache;
1745 Cache new_cache;
1746 unsigned int slotCount;
1747 unsigned int index;
1748
1749 // First growth goes from emptyCache to a real one
1750 old_cache = ((struct objc_class *)cls)->cache;
1751 if (old_cache == &emptyCache)
1752 return _cache_create (cls);
1753
1754 // iff _class_slow_grow, trade off actual cache growth with re-using
1755 // the current one, so that growth only happens every odd time
1756 if (_class_slow_grow)
1757 {
1758 // CLS_GROW_CACHE controls every-other-time behavior. If it
1759 // is non-zero, let the cache grow this time, but clear the
1760 // flag so the cache is reused next time
1761 if ((((struct objc_class * )cls)->info & CLS_GROW_CACHE) != 0)
2bfd4448 1762 _class_clearInfo(cls, CLS_GROW_CACHE);
41c8faa5
A
1763
1764 // Reuse the current cache storage this time
1765 else
1766 {
1767 // Clear the valid-entry counter
1768 old_cache->occupied = 0;
1769
1770 // Invalidate all the cache entries
1771 for (index = 0; index < old_cache->mask + 1; index += 1)
1772 {
1773 // Remember what this entry was, so we can possibly
1774 // deallocate it after the bucket has been invalidated
1775 Method oldEntry = old_cache->buckets[index];
1776 // Skip invalid entry
1777 if (!CACHE_BUCKET_VALID(old_cache->buckets[index]))
1778 continue;
1779
1780 // Invalidate this entry
1781 CACHE_BUCKET_VALID(old_cache->buckets[index]) = NULL;
1782
1783 // Deallocate "forward::" entry
1784 if (CACHE_BUCKET_IMP(oldEntry) == &_objc_msgForward)
1785 {
2bfd4448 1786 _cache_collect_free (oldEntry, sizeof(struct objc_method), NO);
41c8faa5
A
1787 }
1788 }
1789
1790 // Set the slow growth flag so the cache is next grown
2bfd4448 1791 _class_setInfo(cls, CLS_GROW_CACHE);
41c8faa5
A
1792
1793 // Return the same old cache, freshly emptied
1794 return old_cache;
1795 }
1796
1797 }
1798
1799 // Double the cache size
1800 slotCount = (old_cache->mask + 1) << 1;
1801
1f20c7a7 1802 new_cache = _cache_malloc(slotCount);
13d88034
A
1803
1804#ifdef OBJC_INSTRUMENTED
41c8faa5
A
1805 // Propagate the instrumentation data
1806 {
1807 CacheInstrumentation * oldCacheData;
1808 CacheInstrumentation * newCacheData;
1809
1810 oldCacheData = CACHE_INSTRUMENTATION(old_cache);
1811 newCacheData = CACHE_INSTRUMENTATION(new_cache);
1812 bcopy ((const char *)oldCacheData, (char *)newCacheData, sizeof(CacheInstrumentation));
1813 }
13d88034
A
1814#endif
1815
41c8faa5
A
1816 // iff _class_uncache, copy old cache entries into the new cache
1817 if (_class_uncache == 0)
1818 {
1819 int newMask;
1820
1821 newMask = new_cache->mask;
1822
1823 // Look at all entries in the old cache
1824 for (index = 0; index < old_cache->mask + 1; index += 1)
1825 {
1826 int index2;
1827
1828 // Skip invalid entry
1829 if (!CACHE_BUCKET_VALID(old_cache->buckets[index]))
1830 continue;
1831
1832 // Hash the old entry into the new table
1f20c7a7
A
1833 index2 = CACHE_HASH(CACHE_BUCKET_NAME(old_cache->buckets[index]),
1834 newMask);
41c8faa5
A
1835
1836 // Find an available spot, at or following the hashed spot;
1837 // Guaranteed to not infinite loop, because table has grown
1838 for (;;)
1839 {
1840 if (!CACHE_BUCKET_VALID(new_cache->buckets[index2]))
1841 {
1842 new_cache->buckets[index2] = old_cache->buckets[index];
1843 break;
1844 }
1845
1846 index2 += 1;
1847 index2 &= newMask;
1848 }
1849
1850 // Account for the addition
1851 new_cache->occupied += 1;
1852 }
1853
1854 // Set the cache flush flag so that we will flush this cache
1855 // before expanding it again.
2bfd4448 1856 _class_setInfo(cls, CLS_FLUSH_CACHE);
41c8faa5
A
1857 }
1858
1859 // Deallocate "forward::" entries from the old cache
1860 else
1861 {
1862 for (index = 0; index < old_cache->mask + 1; index += 1)
1863 {
1864 if (CACHE_BUCKET_VALID(old_cache->buckets[index]) &&
1865 CACHE_BUCKET_IMP(old_cache->buckets[index]) == &_objc_msgForward)
1866 {
2bfd4448 1867 _cache_collect_free (old_cache->buckets[index], sizeof(struct objc_method), NO);
41c8faa5
A
1868 }
1869 }
1870 }
13d88034 1871
41c8faa5
A
1872 // Install new cache
1873 ((struct objc_class *)cls)->cache = new_cache;
13d88034 1874
41c8faa5 1875 // Deallocate old cache, try freeing all the garbage
2bfd4448 1876 _cache_collect_free (old_cache, old_cache->mask * sizeof(Method), YES);
41c8faa5 1877 return new_cache;
13d88034
A
1878}
1879
1880/***********************************************************************
41c8faa5
A
1881* instrumentObjcMessageSends/logObjcMessageSends.
1882**********************************************************************/
13d88034 1883static int LogObjCMessageSend (BOOL isClassMethod,
41c8faa5
A
1884 const char * objectsClass,
1885 const char * implementingClass,
1886 SEL selector)
13d88034 1887{
41c8faa5 1888 char buf[ 1024 ];
13d88034 1889
41c8faa5
A
1890 // Create/open the log file
1891 if (objcMsgLogFD == (-1))
1892 {
1f20c7a7 1893 snprintf (buf, sizeof(buf), "/tmp/msgSends-%d", (int) getpid ());
2bfd4448
A
1894 objcMsgLogFD = secure_open (buf, O_WRONLY | O_CREAT, geteuid());
1895 if (objcMsgLogFD < 0) {
1896 // no log file - disable logging
1897 objcMsgLogEnabled = 0;
1898 objcMsgLogFD = -1;
1899 return 1;
1900 }
41c8faa5
A
1901 }
1902
1903 // Make the log entry
1f20c7a7 1904 snprintf(buf, sizeof(buf), "%c %s %s %s\n",
41c8faa5
A
1905 isClassMethod ? '+' : '-',
1906 objectsClass,
1907 implementingClass,
1908 (char *) selector);
13d88034 1909
41c8faa5 1910 write (objcMsgLogFD, buf, strlen(buf));
13d88034 1911
41c8faa5
A
1912 // Tell caller to not cache the method
1913 return 0;
13d88034
A
1914}
1915
1916void instrumentObjcMessageSends (BOOL flag)
1917{
41c8faa5
A
1918 int enabledValue = (flag) ? 1 : 0;
1919
1920 // Shortcut NOP
1921 if (objcMsgLogEnabled == enabledValue)
1922 return;
13d88034 1923
41c8faa5
A
1924 // If enabling, flush all method caches so we get some traces
1925 if (flag)
1926 flush_caches (Nil, YES);
13d88034 1927
41c8faa5
A
1928 // Sync our log file
1929 if (objcMsgLogFD != (-1))
1930 fsync (objcMsgLogFD);
1931
1932 objcMsgLogEnabled = enabledValue;
13d88034
A
1933}
1934
1935void logObjcMessageSends (ObjCLogProc logProc)
1936{
41c8faa5
A
1937 if (logProc)
1938 {
1939 objcMsgLogProc = logProc;
1940 objcMsgLogEnabled = 1;
1941 }
1942 else
1943 {
1944 objcMsgLogProc = logProc;
1945 objcMsgLogEnabled = 0;
1946 }
13d88034 1947
41c8faa5
A
1948 if (objcMsgLogFD != (-1))
1949 fsync (objcMsgLogFD);
13d88034
A
1950}
1951
1f20c7a7 1952
13d88034 1953/***********************************************************************
41c8faa5 1954* _cache_fill. Add the specified method to the specified class' cache.
1f20c7a7
A
1955* Returns NO if the cache entry wasn't added: cache was busy,
1956* class is still being initialized, new entry is a duplicate.
41c8faa5
A
1957*
1958* Called only from _class_lookupMethodAndLoadCache and
1f20c7a7 1959* class_respondsToMethod and _cache_addForwardEntry.
41c8faa5 1960*
1f20c7a7 1961* Cache locks: cacheUpdateLock must not be held.
41c8faa5 1962**********************************************************************/
1f20c7a7 1963static BOOL _cache_fill(Class cls, Method smt, SEL sel)
13d88034 1964{
41c8faa5 1965 unsigned int newOccupied;
1f20c7a7
A
1966 arith_t index;
1967 Method *buckets;
1968 Cache cache;
1969
1970 // Never cache before +initialize is done
1971 if (!ISINITIALIZED(cls)) {
1972 return NO;
1973 }
13d88034 1974
41c8faa5
A
1975 // Keep tally of cache additions
1976 totalCacheFills += 1;
13d88034 1977
1f20c7a7 1978 OBJC_LOCK(&cacheUpdateLock);
41c8faa5 1979
1f20c7a7 1980 cache = ((struct objc_class *)cls)->cache;
41c8faa5
A
1981
1982 // Check for duplicate entries, if we're in the mode
1983 if (traceDuplicates)
1984 {
1985 int index2;
1f20c7a7
A
1986 arith_t mask = cache->mask;
1987 buckets = cache->buckets;
41c8faa5
A
1988
1989 // Scan the cache
1990 for (index2 = 0; index2 < mask + 1; index2 += 1)
1991 {
1992 // Skip invalid or non-duplicate entry
1993 if ((!CACHE_BUCKET_VALID(buckets[index2])) ||
1994 (strcmp ((char *) CACHE_BUCKET_NAME(buckets[index2]), (char *) smt->method_name) != 0))
1995 continue;
1996
1997 // Tally duplication, but report iff wanted
1998 cacheFillDuplicates += 1;
1999 if (traceDuplicatesVerbose)
2000 {
2001 _objc_inform ("Cache fill duplicate #%d: found %x adding %x: %s\n",
2002 cacheFillDuplicates,
2003 (unsigned int) CACHE_BUCKET_NAME(buckets[index2]),
2004 (unsigned int) smt->method_name,
2005 (char *) smt->method_name);
2006 }
2007 }
2008 }
2009
1f20c7a7
A
2010 // Make sure the entry wasn't added to the cache by some other thread
2011 // before we grabbed the cacheUpdateLock.
2012 // Don't use _cache_getMethod() because _cache_getMethod() doesn't
2013 // return forward:: entries.
2014 if (_cache_getImp(cls, sel)) {
2015 OBJC_UNLOCK(&cacheUpdateLock);
2016 return NO; // entry is already cached, didn't add new one
41c8faa5 2017 }
13d88034 2018
41c8faa5
A
2019 // Use the cache as-is if it is less than 3/4 full
2020 newOccupied = cache->occupied + 1;
1f20c7a7
A
2021 if ((newOccupied * 4) <= (cache->mask + 1) * 3) {
2022 // Cache is less than 3/4 full.
41c8faa5 2023 cache->occupied = newOccupied;
1f20c7a7
A
2024 } else {
2025 // Cache is too full. Flush it or expand it.
2026 if ((((struct objc_class * )cls)->info & CLS_FLUSH_CACHE) != 0) {
41c8faa5 2027 _cache_flush (cls);
1f20c7a7 2028 } else {
41c8faa5 2029 cache = _cache_expand (cls);
41c8faa5
A
2030 }
2031
2032 // Account for the addition
2033 cache->occupied += 1;
2034 }
2035
2036 // Insert the new entry. This can be done by either:
2037 // (a) Scanning for the first unused spot. Easy!
2038 // (b) Opening up an unused spot by sliding existing
2039 // entries down by one. The benefit of this
2040 // extra work is that it puts the most recently
2041 // loaded entries closest to where the selector
2042 // hash starts the search.
2043 //
2044 // The loop is a little more complicated because there
2045 // are two kinds of entries, so there have to be two ways
2046 // to slide them.
2047 buckets = cache->buckets;
1f20c7a7 2048 index = CACHE_HASH(sel, cache->mask);
41c8faa5
A
2049 for (;;)
2050 {
2051 // Slide existing entries down by one
2052 Method saveMethod;
2053
2054 // Copy current entry to a local
2055 saveMethod = buckets[index];
2056
2057 // Copy previous entry (or new entry) to current slot
2058 buckets[index] = smt;
2059
2060 // Done if current slot had been invalid
2061 if (saveMethod == NULL)
2062 break;
2063
2064 // Prepare to copy saved value into next slot
2065 smt = saveMethod;
2066
2067 // Move on to next slot
2068 index += 1;
1f20c7a7 2069 index &= cache->mask;
41c8faa5 2070 }
13d88034 2071
41c8faa5 2072 OBJC_UNLOCK(&cacheUpdateLock);
1f20c7a7
A
2073
2074 return YES; // successfully added new cache entry
13d88034
A
2075}
2076
1f20c7a7
A
2077
2078/***********************************************************************
2079* _cache_addForwardEntry
2080* Add a forward:: entry for the given selector to cls's method cache.
2081* Does nothing if the cache addition fails for any reason.
2082* Called from class_respondsToMethod and _class_lookupMethodAndLoadCache.
2083* Cache locks: cacheUpdateLock must not be held.
2084**********************************************************************/
2085static void _cache_addForwardEntry(Class cls, SEL sel)
2086{
2087 Method smt;
2088
2bfd4448 2089 smt = _malloc_internal(sizeof(struct objc_method));
1f20c7a7
A
2090 smt->method_name = sel;
2091 smt->method_types = "";
2092 smt->method_imp = &_objc_msgForward;
2093 if (! _cache_fill(cls, smt, sel)) {
2094 // Entry not added to cache. Don't leak the method struct.
2bfd4448 2095 _free_internal(smt);
1f20c7a7
A
2096 }
2097}
2098
2099
13d88034 2100/***********************************************************************
41c8faa5
A
2101* _cache_flush. Invalidate all valid entries in the given class' cache,
2102* and clear the CLS_FLUSH_CACHE in the cls->info.
2103*
1f20c7a7
A
2104* Called from flush_caches() and _cache_fill()
2105* Cache locks: cacheUpdateLock must be held by the caller.
41c8faa5 2106**********************************************************************/
13d88034
A
2107static void _cache_flush (Class cls)
2108{
41c8faa5
A
2109 Cache cache;
2110 unsigned int index;
2111
2112 // Locate cache. Ignore unused cache.
2113 cache = ((struct objc_class *)cls)->cache;
1f20c7a7 2114 if (cache == NULL || cache == &emptyCache)
41c8faa5 2115 return;
13d88034
A
2116
2117#ifdef OBJC_INSTRUMENTED
41c8faa5
A
2118 {
2119 CacheInstrumentation * cacheData;
2120
2121 // Tally this flush
2122 cacheData = CACHE_INSTRUMENTATION(cache);
2123 cacheData->flushCount += 1;
2124 cacheData->flushedEntries += cache->occupied;
2125 if (cache->occupied > cacheData->maxFlushedEntries)
2126 cacheData->maxFlushedEntries = cache->occupied;
2127 }
13d88034 2128#endif
41c8faa5
A
2129
2130 // Traverse the cache
2131 for (index = 0; index <= cache->mask; index += 1)
2132 {
2133 // Remember what this entry was, so we can possibly
2134 // deallocate it after the bucket has been invalidated
2135 Method oldEntry = cache->buckets[index];
2136
2137 // Invalidate this entry
2138 CACHE_BUCKET_VALID(cache->buckets[index]) = NULL;
2139
2140 // Deallocate "forward::" entry
2141 if (oldEntry && oldEntry->method_imp == &_objc_msgForward)
2bfd4448 2142 _cache_collect_free (oldEntry, sizeof(struct objc_method), NO);
41c8faa5 2143 }
13d88034 2144
41c8faa5
A
2145 // Clear the valid-entry counter
2146 cache->occupied = 0;
2147
2148 // Clear the cache flush flag so that we will not flush this cache
2149 // before expanding it again.
2bfd4448 2150 _class_clearInfo(cls, CLS_FLUSH_CACHE);
13d88034
A
2151}
2152
2153/***********************************************************************
41c8faa5
A
2154* _objc_getFreedObjectClass. Return a pointer to the dummy freed
2155* object class. Freed objects get their isa pointers replaced with
2156* a pointer to the freedObjectClass, so that we can catch usages of
2157* the freed object.
2158**********************************************************************/
13d88034
A
2159Class _objc_getFreedObjectClass (void)
2160{
41c8faa5 2161 return (Class) &freedObjectClass;
13d88034
A
2162}
2163
2164/***********************************************************************
41c8faa5
A
2165* _objc_getNonexistentClass. Return a pointer to the dummy nonexistent
2166* object class. This is used when, for example, mapping the class
2167* refs for an image, and the class can not be found, so that we can
2168* catch later uses of the non-existent class.
2169**********************************************************************/
13d88034
A
2170Class _objc_getNonexistentClass (void)
2171{
41c8faa5 2172 return (Class) &nonexistentObjectClass;
13d88034
A
2173}
2174
1f20c7a7
A
2175
2176/***********************************************************************
2177* struct _objc_initializing_classes
2178* Per-thread list of classes currently being initialized by that thread.
2179* During initialization, that thread is allowed to send messages to that
2180* class, but other threads have to wait.
2181* The list is a simple array of metaclasses (the metaclass stores
2182* the initialization state).
2183**********************************************************************/
2184typedef struct _objc_initializing_classes {
2185 int classesAllocated;
2186 struct objc_class** metaclasses;
2187} _objc_initializing_classes;
2188
2189
2190/***********************************************************************
2191* _fetchInitializingClassList
2192* Return the list of classes being initialized by this thread.
2193* If create == YES, create the list when no classes are being initialized by this thread.
2194* If create == NO, return NULL when no classes are being initialized by this thread.
2195**********************************************************************/
2196static _objc_initializing_classes *_fetchInitializingClassList(BOOL create)
2197{
2198 _objc_pthread_data *data;
2199 _objc_initializing_classes *list;
2200 struct objc_class **classes;
2201
2202 data = pthread_getspecific(_objc_pthread_key);
2203 if (data == NULL) {
2204 if (!create) {
2205 return NULL;
2206 } else {
2bfd4448 2207 data = _calloc_internal(1, sizeof(_objc_pthread_data));
1f20c7a7
A
2208 pthread_setspecific(_objc_pthread_key, data);
2209 }
2210 }
2211
2212 list = data->initializingClasses;
2213 if (list == NULL) {
2214 if (!create) {
2215 return NULL;
2216 } else {
2bfd4448 2217 list = _calloc_internal(1, sizeof(_objc_initializing_classes));
1f20c7a7
A
2218 data->initializingClasses = list;
2219 }
2220 }
2221
2222 classes = list->metaclasses;
2223 if (classes == NULL) {
2224 // If _objc_initializing_classes exists, allocate metaclass array,
2225 // even if create == NO.
2226 // Allow 4 simultaneous class inits on this thread before realloc.
2227 list->classesAllocated = 4;
2bfd4448 2228 classes = _calloc_internal(list->classesAllocated, sizeof(struct objc_class *));
1f20c7a7
A
2229 list->metaclasses = classes;
2230 }
2231 return list;
2232}
2233
2234
2235/***********************************************************************
2236* _destroyInitializingClassList
2237* Deallocate memory used by the given initialization list.
2238* Any part of the list may be NULL.
2239* Called from _objc_pthread_destroyspecific().
2240**********************************************************************/
2241void _destroyInitializingClassList(_objc_initializing_classes *list)
2242{
2243 if (list != NULL) {
2244 if (list->metaclasses != NULL) {
2bfd4448 2245 _free_internal(list->metaclasses);
1f20c7a7 2246 }
2bfd4448 2247 _free_internal(list);
1f20c7a7
A
2248 }
2249}
2250
2251
2252/***********************************************************************
2253* _thisThreadIsInitializingClass
2254* Return TRUE if this thread is currently initializing the given class.
2255**********************************************************************/
2256static BOOL _thisThreadIsInitializingClass(struct objc_class *cls)
2257{
2258 int i;
2259
2260 _objc_initializing_classes *list = _fetchInitializingClassList(NO);
2261 if (list) {
2262 cls = GETMETA(cls);
2263 for (i = 0; i < list->classesAllocated; i++) {
2264 if (cls == list->metaclasses[i]) return YES;
2265 }
2266 }
2267
2268 // no list or not found in list
2269 return NO;
2270}
2271
2272
2273/***********************************************************************
2274* _setThisThreadIsInitializingClass
2275* Record that this thread is currently initializing the given class.
2276* This thread will be allowed to send messages to the class, but
2277* other threads will have to wait.
2278**********************************************************************/
2279static void _setThisThreadIsInitializingClass(struct objc_class *cls)
2280{
2281 int i;
2282 _objc_initializing_classes *list = _fetchInitializingClassList(YES);
2283 cls = GETMETA(cls);
2284
2285 // paranoia: explicitly disallow duplicates
2286 for (i = 0; i < list->classesAllocated; i++) {
2287 if (cls == list->metaclasses[i]) {
2288 _objc_fatal("thread is already initializing this class!");
2289 return; // already the initializer
2290 }
2291 }
2292
2293 for (i = 0; i < list->classesAllocated; i++) {
2294 if (0 == list->metaclasses[i]) {
2295 list->metaclasses[i] = cls;
2296 return;
2297 }
2298 }
2299
2300 // class list is full - reallocate
2301 list->classesAllocated = list->classesAllocated * 2 + 1;
2bfd4448 2302 list->metaclasses = _realloc_internal(list->metaclasses, list->classesAllocated * sizeof(struct objc_class *));
1f20c7a7
A
2303 // zero out the new entries
2304 list->metaclasses[i++] = cls;
2305 for ( ; i < list->classesAllocated; i++) {
2306 list->metaclasses[i] = NULL;
2307 }
2308}
2309
2310
2311/***********************************************************************
2312* _setThisThreadIsNotInitializingClass
2313* Record that this thread is no longer initializing the given class.
2314**********************************************************************/
2315static void _setThisThreadIsNotInitializingClass(struct objc_class *cls)
2316{
2317 int i;
2318
2319 _objc_initializing_classes *list = _fetchInitializingClassList(NO);
2320 if (list) {
2321 cls = GETMETA(cls);
2322 for (i = 0; i < list->classesAllocated; i++) {
2323 if (cls == list->metaclasses[i]) {
2324 list->metaclasses[i] = NULL;
2325 return;
2326 }
2327 }
2328 }
2329
2330 // no list or not found in list
2331 _objc_fatal("thread is not initializing this class!");
2332}
2333
2334
2335/***********************************************************************
2336* class_initialize. Send the '+initialize' message on demand to any
2337* uninitialized class. Force initialization of superclasses first.
2338*
2339* Called only from _class_lookupMethodAndLoadCache (or itself).
2340**********************************************************************/
2341static void class_initialize(struct objc_class *cls)
2342{
2bfd4448 2343 struct objc_class *infoCls = GETMETA(cls);
1f20c7a7
A
2344 BOOL reallyInitialize = NO;
2345
2346 // Get the real class from the metaclass. The superclass chain
2347 // hangs off the real class only.
2bfd4448 2348 // fixme ick
1f20c7a7
A
2349 if (ISMETA(cls)) {
2350 if (strncmp(cls->name, "_%", 2) == 0) {
2351 // Posee's meta's name is smashed and isn't in the class_hash,
2352 // so objc_getClass doesn't work.
2353 char *baseName = strchr(cls->name, '%'); // get posee's real name
2354 cls = objc_getClass(baseName);
2355 } else {
2356 cls = objc_getClass(cls->name);
2357 }
2358 }
2359
2360 // Make sure super is done initializing BEFORE beginning to initialize cls.
2361 // See note about deadlock above.
2362 if (cls->super_class && !ISINITIALIZED(cls->super_class)) {
2363 class_initialize(cls->super_class);
2364 }
2365
2366 // Try to atomically set CLS_INITIALIZING.
2367 pthread_mutex_lock(&classInitLock);
2368 if (!ISINITIALIZED(cls) && !ISINITIALIZING(cls)) {
2bfd4448 2369 _class_setInfo(infoCls, CLS_INITIALIZING);
1f20c7a7
A
2370 reallyInitialize = YES;
2371 }
2372 pthread_mutex_unlock(&classInitLock);
2373
2374 if (reallyInitialize) {
2375 // We successfully set the CLS_INITIALIZING bit. Initialize the class.
2376
2377 // Record that we're initializing this class so we can message it.
2378 _setThisThreadIsInitializingClass(cls);
2379
1f20c7a7
A
2380 // Send the +initialize message.
2381 // Note that +initialize is sent to the superclass (again) if
2382 // this class doesn't implement +initialize. 2157218
2383 [(id)cls initialize];
2384
2385 // Done initializing. Update the info bits and notify waiting threads.
2386 pthread_mutex_lock(&classInitLock);
2bfd4448 2387 _class_changeInfo(infoCls, CLS_INITIALIZED, CLS_INITIALIZING);
1f20c7a7
A
2388 pthread_cond_broadcast(&classInitWaitCond);
2389 pthread_mutex_unlock(&classInitLock);
2390 _setThisThreadIsNotInitializingClass(cls);
2391 return;
2392 }
2393
2394 else if (ISINITIALIZING(cls)) {
2395 // We couldn't set INITIALIZING because INITIALIZING was already set.
2396 // If this thread set it earlier, continue normally.
2397 // If some other thread set it, block until initialize is done.
2398 // It's ok if INITIALIZING changes to INITIALIZED while we're here,
2399 // because we safely check for INITIALIZED inside the lock
2400 // before blocking.
2401 if (_thisThreadIsInitializingClass(cls)) {
2402 return;
2403 } else {
2404 pthread_mutex_lock(&classInitLock);
2405 while (!ISINITIALIZED(cls)) {
2406 pthread_cond_wait(&classInitWaitCond, &classInitLock);
2407 }
2408 pthread_mutex_unlock(&classInitLock);
2409 return;
2410 }
2411 }
2412
2413 else if (ISINITIALIZED(cls)) {
2414 // Set CLS_INITIALIZING failed because someone else already
2415 // initialized the class. Continue normally.
2416 // NOTE this check must come AFTER the ISINITIALIZING case.
2417 // Otherwise: Another thread is initializing this class. ISINITIALIZED
2418 // is false. Skip this clause. Then the other thread finishes
2419 // initialization and sets INITIALIZING=no and INITIALIZED=yes.
2420 // Skip the ISINITIALIZING clause. Die horribly.
2421 return;
2422 }
2423
2424 else {
2425 // We shouldn't be here.
2426 _objc_fatal("thread-safe class init in objc runtime is buggy!");
2427 }
2428}
2429
2430
13d88034 2431/***********************************************************************
41c8faa5
A
2432* _class_lookupMethodAndLoadCache.
2433*
2434* Called only from objc_msgSend, objc_msgSendSuper and class_lookupMethod.
2435**********************************************************************/
13d88034 2436IMP _class_lookupMethodAndLoadCache (Class cls,
41c8faa5
A
2437 SEL sel)
2438{
2439 struct objc_class * curClass;
1f20c7a7
A
2440 Method meth;
2441 IMP methodPC = NULL;
41c8faa5
A
2442
2443 trace(0xb300, 0, 0, 0);
2444
2445 // Check for freed class
2446 if (cls == &freedObjectClass)
2447 return (IMP) _freedHandler;
2448
2449 // Check for nonexistent class
2450 if (cls == &nonexistentObjectClass)
2451 return (IMP) _nonexistentHandler;
2452
41c8faa5
A
2453 trace(0xb301, 0, 0, 0);
2454
1f20c7a7
A
2455 if (!ISINITIALIZED(cls)) {
2456 class_initialize ((struct objc_class *)cls);
2457 // If sel == initialize, class_initialize will send +initialize and
2458 // then the messenger will send +initialize again after this
2459 // procedure finishes. Of course, if this is not being called
2460 // from the messenger then it won't happen. 2778172
2461 }
41c8faa5
A
2462
2463 trace(0xb302, 0, 0, 0);
2464
2465 // Outer loop - search the caches and method lists of the
2466 // class and its super-classes
41c8faa5
A
2467 for (curClass = cls; curClass; curClass = ((struct objc_class * )curClass)->super_class)
2468 {
13d88034 2469#ifdef PRELOAD_SUPERCLASS_CACHES
1f20c7a7 2470 struct objc_class *curClass2;
13d88034
A
2471#endif
2472
41c8faa5
A
2473 trace(0xb303, 0, 0, 0);
2474
1f20c7a7
A
2475 // Beware of thread-unsafety and double-freeing of forward::
2476 // entries here! See note in "Method cache locking" above.
2477 // The upshot is that _cache_getMethod() will return NULL
2478 // instead of returning a forward:: entry.
390d5862 2479 meth = _cache_getMethod(curClass, sel, &_objc_msgForward);
1f20c7a7
A
2480 if (meth) {
2481 // Found the method in this class or a superclass.
2482 // Cache the method in this class, unless we just found it in
2483 // this class's cache.
2484 if (curClass != cls) {
13d88034 2485#ifdef PRELOAD_SUPERCLASS_CACHES
41c8faa5 2486 for (curClass2 = cls; curClass2 != curClass; curClass2 = curClass2->super_class)
1f20c7a7
A
2487 _cache_fill (curClass2, meth, sel);
2488 _cache_fill (curClass, meth, sel);
13d88034 2489#else
1f20c7a7 2490 _cache_fill (cls, meth, sel);
13d88034 2491#endif
41c8faa5
A
2492 }
2493
1f20c7a7 2494 methodPC = meth->method_imp;
41c8faa5
A
2495 break;
2496 }
2497
2498 trace(0xb304, (int)methodPC, 0, 0);
2499
1f20c7a7 2500 // Cache scan failed. Search method list.
41c8faa5 2501
2bfd4448 2502 OBJC_LOCK(&methodListLock);
1f20c7a7 2503 meth = _findMethodInClass(curClass, sel);
2bfd4448 2504 OBJC_UNLOCK(&methodListLock);
1f20c7a7 2505 if (meth) {
41c8faa5
A
2506 // If logging is enabled, log the message send and let
2507 // the logger decide whether to encache the method.
2508 if ((objcMsgLogEnabled == 0) ||
1f20c7a7
A
2509 (objcMsgLogProc (CLS_GETINFO(((struct objc_class * )curClass),
2510 CLS_META) ? YES : NO,
41c8faa5
A
2511 ((struct objc_class *)cls)->name,
2512 curClass->name, sel)))
2513 {
2514 // Cache the method implementation
13d88034 2515#ifdef PRELOAD_SUPERCLASS_CACHES
41c8faa5 2516 for (curClass2 = cls; curClass2 != curClass; curClass2 = curClass2->super_class)
1f20c7a7
A
2517 _cache_fill (curClass2, meth, sel);
2518 _cache_fill (curClass, meth, sel);
13d88034 2519#else
1f20c7a7 2520 _cache_fill (cls, meth, sel);
13d88034 2521#endif
41c8faa5 2522 }
1f20c7a7
A
2523
2524 methodPC = meth->method_imp;
2525 break;
41c8faa5
A
2526 }
2527
2528 trace(0xb305, (int)methodPC, 0, 0);
41c8faa5
A
2529 }
2530
2531 trace(0xb306, (int)methodPC, 0, 0);
2532
2533 if (methodPC == NULL)
2534 {
2535 // Class and superclasses do not respond -- use forwarding
1f20c7a7 2536 _cache_addForwardEntry(cls, sel);
41c8faa5
A
2537 methodPC = &_objc_msgForward;
2538 }
2539
41c8faa5
A
2540 trace(0xb30f, (int)methodPC, 0, 0);
2541
2542 return methodPC;
13d88034
A
2543}
2544
1f20c7a7 2545
2bfd4448
A
2546/***********************************************************************
2547* lookupMethodInClassAndLoadCache.
2548* Like _class_lookupMethodAndLoadCache, but does not search superclasses.
2549* Caches and returns objc_msgForward if the method is not found in the class.
2550**********************************************************************/
2551static IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel)
2552{
2553 Method meth;
2554 IMP imp;
2555
2556 // Search cache first.
2557 imp = _cache_getImp(cls, sel);
2558 if (imp) return imp;
2559
2560 // Cache miss. Search method list.
2561
2562 OBJC_LOCK(&methodListLock);
2563 meth = _findMethodInClass(cls, sel);
2564 OBJC_UNLOCK(&methodListLock);
2565
2566 if (meth) {
2567 // Hit in method list. Cache it.
2568 _cache_fill(cls, meth, sel);
2569 return meth->method_imp;
2570 } else {
2571 // Miss in method list. Cache objc_msgForward.
2572 _cache_addForwardEntry(cls, sel);
2573 return &_objc_msgForward;
2574 }
2575}
2576
2577
2578
2579/***********************************************************************
2580* _class_changeInfo
2581* Atomically sets and clears some bits in cls's info field.
2582* set and clear must not overlap.
2583**********************************************************************/
2584static pthread_mutex_t infoLock = PTHREAD_MUTEX_INITIALIZER;
2585__private_extern__ void _class_changeInfo(struct objc_class *cls,
2586 long set, long clear)
2587{
2588 pthread_mutex_lock(&infoLock);
2589 cls->info = (cls->info | set) & ~clear;
2590 pthread_mutex_unlock(&infoLock);
2591}
2592
2593
2594/***********************************************************************
2595* _class_setInfo
2596* Atomically sets some bits in cls's info field.
2597**********************************************************************/
2598__private_extern__ void _class_setInfo(struct objc_class *cls, long set)
2599{
2600 _class_changeInfo(cls, set, 0);
2601}
2602
2603
2604/***********************************************************************
2605* _class_clearInfo
2606* Atomically clears some bits in cls's info field.
2607**********************************************************************/
2608__private_extern__ void _class_clearInfo(struct objc_class *cls, long clear)
2609{
2610 _class_changeInfo(cls, 0, clear);
2611}
2612
2613
13d88034 2614/***********************************************************************
41c8faa5
A
2615* SubtypeUntil.
2616*
2617* Delegation.
2618**********************************************************************/
13d88034 2619static int SubtypeUntil (const char * type,
41c8faa5
A
2620 char end)
2621{
2622 int level = 0;
2623 const char * head = type;
2624
2625 //
2626 while (*type)
2627 {
2628 if (!*type || (!level && (*type == end)))
2629 return (int)(type - head);
2630
2631 switch (*type)
2632 {
2633 case ']': case '}': case ')': level--; break;
2634 case '[': case '{': case '(': level += 1; break;
2635 }
2636
2637 type += 1;
2638 }
2639
2640 _objc_fatal ("Object: SubtypeUntil: end of type encountered prematurely\n");
2641 return 0;
2642}
2643
2644/***********************************************************************
2645* SkipFirstType.
2646**********************************************************************/
2647static const char * SkipFirstType (const char * type)
2648{
2649 while (1)
2650 {
2651 switch (*type++)
2652 {
2653 case 'O': /* bycopy */
2654 case 'n': /* in */
2655 case 'o': /* out */
2656 case 'N': /* inout */
2657 case 'r': /* const */
2658 case 'V': /* oneway */
2659 case '^': /* pointers */
2660 break;
2661
2662 /* arrays */
2663 case '[':
2664 while ((*type >= '0') && (*type <= '9'))
2665 type += 1;
2666 return type + SubtypeUntil (type, ']') + 1;
2667
2668 /* structures */
2669 case '{':
2670 return type + SubtypeUntil (type, '}') + 1;
2671
2672 /* unions */
2673 case '(':
2674 return type + SubtypeUntil (type, ')') + 1;
2675
2676 /* basic types */
2677 default:
2678 return type;
2679 }
2680 }
2681}
2682
2683/***********************************************************************
2684* method_getNumberOfArguments.
2685**********************************************************************/
13d88034
A
2686unsigned method_getNumberOfArguments (Method method)
2687{
41c8faa5
A
2688 const char * typedesc;
2689 unsigned nargs;
2690
2691 // First, skip the return type
2692 typedesc = method->method_types;
2693 typedesc = SkipFirstType (typedesc);
2694
2695 // Next, skip stack size
2696 while ((*typedesc >= '0') && (*typedesc <= '9'))
2697 typedesc += 1;
2698
2699 // Now, we have the arguments - count how many
2700 nargs = 0;
2701 while (*typedesc)
2702 {
2703 // Traverse argument type
2704 typedesc = SkipFirstType (typedesc);
2705
1f20c7a7
A
2706 // Skip GNU runtime's register parameter hint
2707 if (*typedesc == '+') typedesc++;
2708
41c8faa5
A
2709 // Traverse (possibly negative) argument offset
2710 if (*typedesc == '-')
2711 typedesc += 1;
2712 while ((*typedesc >= '0') && (*typedesc <= '9'))
2713 typedesc += 1;
2714
2715 // Made it past an argument
2716 nargs += 1;
2717 }
2718
2719 return nargs;
2720}
2721
2722/***********************************************************************
2723* method_getSizeOfArguments.
2724**********************************************************************/
13d88034
A
2725#ifndef __alpha__
2726unsigned method_getSizeOfArguments (Method method)
2727{
41c8faa5
A
2728 const char * typedesc;
2729 unsigned stack_size;
13d88034 2730#if defined(__ppc__) || defined(ppc)
41c8faa5
A
2731 unsigned trueBaseOffset;
2732 unsigned foundBaseOffset;
13d88034 2733#endif
13d88034 2734
41c8faa5
A
2735 // Get our starting points
2736 stack_size = 0;
2737 typedesc = method->method_types;
2738
2739 // Skip the return type
13d88034 2740#if defined (__ppc__) || defined(ppc)
41c8faa5
A
2741 // Struct returns cause the parameters to be bumped
2742 // by a register, so the offset to the receiver is
2743 // 4 instead of the normal 0.
2744 trueBaseOffset = (*typedesc == '{') ? 4 : 0;
13d88034 2745#endif
41c8faa5
A
2746 typedesc = SkipFirstType (typedesc);
2747
2748 // Convert ASCII number string to integer
2749 while ((*typedesc >= '0') && (*typedesc <= '9'))
2750 stack_size = (stack_size * 10) + (*typedesc++ - '0');
13d88034 2751#if defined (__ppc__) || defined(ppc)
41c8faa5
A
2752 // NOTE: This is a temporary measure pending a compiler fix.
2753 // Work around PowerPC compiler bug wherein the method argument
2754 // string contains an incorrect value for the "stack size."
2755 // Generally, the size is reported 4 bytes too small, so we apply
2756 // that fudge factor. Unfortunately, there is at least one case
2757 // where the error is something other than -4: when the last
2758 // parameter is a double, the reported stack is much too high
2759 // (about 32 bytes). We do not attempt to detect that case.
2760 // The result of returning a too-high value is that objc_msgSendv
2761 // can bus error if the destination of the marg_list copying
2762 // butts up against excluded memory.
2763 // This fix disables itself when it sees a correctly built
2764 // type string (i.e. the offset for the Id is correct). This
2765 // keeps us out of lockstep with the compiler.
2766
2767 // skip the '@' marking the Id field
2768 typedesc = SkipFirstType (typedesc);
2769
1f20c7a7
A
2770 // Skip GNU runtime's register parameter hint
2771 if (*typedesc == '+') typedesc++;
2772
41c8faa5
A
2773 // pick up the offset for the Id field
2774 foundBaseOffset = 0;
2775 while ((*typedesc >= '0') && (*typedesc <= '9'))
2776 foundBaseOffset = (foundBaseOffset * 10) + (*typedesc++ - '0');
2777
2778 // add fudge factor iff the Id field offset was wrong
2779 if (foundBaseOffset != trueBaseOffset)
2780 stack_size += 4;
13d88034
A
2781#endif
2782
41c8faa5 2783 return stack_size;
13d88034
A
2784}
2785
2786#else // __alpha__
41c8faa5
A
2787 // XXX Getting the size of a type is done all over the place
2788 // (Here, Foundation, remote project)! - Should unify
13d88034
A
2789
2790unsigned int getSizeOfType (const char * type, unsigned int * alignPtr);
2791
2792unsigned method_getSizeOfArguments (Method method)
2793{
41c8faa5
A
2794 const char * type;
2795 int size;
2796 int index;
2797 int align;
2798 int offset;
2799 unsigned stack_size;
2800 int nargs;
2801
2802 nargs = method_getNumberOfArguments (method);
2803 stack_size = (*method->method_types == '{') ? sizeof(void *) : 0;
2804
2805 for (index = 0; index < nargs; index += 1)
2806 {
2807 (void) method_getArgumentInfo (method, index, &type, &offset);
2808 size = getSizeOfType (type, &align);
2809 stack_size += ((size + 7) & ~7);
2810 }
2811
2812 return stack_size;
13d88034
A
2813}
2814#endif // __alpha__
2815
2816/***********************************************************************
41c8faa5
A
2817* method_getArgumentInfo.
2818**********************************************************************/
13d88034 2819unsigned method_getArgumentInfo (Method method,
41c8faa5
A
2820 int arg,
2821 const char ** type,
2822 int * offset)
2823{
2824 const char * typedesc = method->method_types;
2825 unsigned nargs = 0;
2826 unsigned self_offset = 0;
2827 BOOL offset_is_negative = NO;
2828
2829 // First, skip the return type
2830 typedesc = SkipFirstType (typedesc);
2831
2832 // Next, skip stack size
2833 while ((*typedesc >= '0') && (*typedesc <= '9'))
2834 typedesc += 1;
2835
2836 // Now, we have the arguments - position typedesc to the appropriate argument
2837 while (*typedesc && nargs != arg)
2838 {
2839
2840 // Skip argument type
2841 typedesc = SkipFirstType (typedesc);
2842
2843 if (nargs == 0)
2844 {
1f20c7a7
A
2845 // Skip GNU runtime's register parameter hint
2846 if (*typedesc == '+') typedesc++;
2847
41c8faa5
A
2848 // Skip negative sign in offset
2849 if (*typedesc == '-')
2850 {
2851 offset_is_negative = YES;
2852 typedesc += 1;
2853 }
2854 else
2855 offset_is_negative = NO;
2856
2857 while ((*typedesc >= '0') && (*typedesc <= '9'))
2858 self_offset = self_offset * 10 + (*typedesc++ - '0');
2859 if (offset_is_negative)
2860 self_offset = -(self_offset);
2861
2862 }
2863
2864 else
2865 {
1f20c7a7
A
2866 // Skip GNU runtime's register parameter hint
2867 if (*typedesc == '+') typedesc++;
2868
41c8faa5
A
2869 // Skip (possibly negative) argument offset
2870 if (*typedesc == '-')
2871 typedesc += 1;
2872 while ((*typedesc >= '0') && (*typedesc <= '9'))
2873 typedesc += 1;
2874 }
2875
2876 nargs += 1;
2877 }
2878
2879 if (*typedesc)
2880 {
2881 unsigned arg_offset = 0;
2882
2883 *type = typedesc;
2884 typedesc = SkipFirstType (typedesc);
2885
2886 if (arg == 0)
2887 {
13d88034 2888#ifdef hppa
41c8faa5 2889 *offset = -sizeof(id);
13d88034 2890#else
41c8faa5
A
2891 *offset = 0;
2892#endif // hppa
2893 }
2894
2895 else
2896 {
1f20c7a7
A
2897 // Skip GNU register parameter hint
2898 if (*typedesc == '+') typedesc++;
2899
41c8faa5
A
2900 // Pick up (possibly negative) argument offset
2901 if (*typedesc == '-')
2902 {
2903 offset_is_negative = YES;
2904 typedesc += 1;
2905 }
2906 else
2907 offset_is_negative = NO;
2908
2909 while ((*typedesc >= '0') && (*typedesc <= '9'))
2910 arg_offset = arg_offset * 10 + (*typedesc++ - '0');
2911 if (offset_is_negative)
2912 arg_offset = - arg_offset;
2913
13d88034 2914#ifdef hppa
41c8faa5
A
2915 // For stacks which grow up, since margs points
2916 // to the top of the stack or the END of the args,
2917 // the first offset is at -sizeof(id) rather than 0.
2918 self_offset += sizeof(id);
13d88034 2919#endif
41c8faa5
A
2920 *offset = arg_offset - self_offset;
2921 }
2922
2923 }
2924
2925 else
2926 {
2927 *type = 0;
2928 *offset = 0;
2929 }
2930
2931 return nargs;
13d88034
A
2932}
2933
2934/***********************************************************************
41c8faa5
A
2935* _objc_create_zone.
2936**********************************************************************/
13d88034
A
2937
2938void * _objc_create_zone (void)
2939{
2bfd4448
A
2940 return malloc_default_zone();
2941}
2942
2943
2944/***********************************************************************
2945* _objc_internal_zone.
2946* Malloc zone for internal runtime data.
2947* By default this is the default malloc zone, but a dedicated zone is
2948* used if environment variable OBJC_USE_INTERNAL_ZONE is set.
2949**********************************************************************/
2950__private_extern__ malloc_zone_t *_objc_internal_zone(void)
2951{
2952 static malloc_zone_t *z = (malloc_zone_t *)-1;
2953 if (z == (malloc_zone_t *)-1) {
2954 if (UseInternalZone) {
2955 z = malloc_create_zone(vm_page_size, 0);
2956 malloc_set_zone_name(z, "ObjC");
2957 } else {
2958 z = malloc_default_zone();
41c8faa5
A
2959 }
2960 }
2bfd4448 2961 return z;
13d88034
A
2962}
2963
2bfd4448
A
2964
2965/***********************************************************************
2966* _malloc_internal
2967* _calloc_internal
2968* _realloc_internal
2969* _strdup_internal
2970* _free_internal
2971* Convenience functions for the internal malloc zone.
2972**********************************************************************/
2973__private_extern__ void *_malloc_internal(size_t size)
2974{
2975 return malloc_zone_malloc(_objc_internal_zone(), size);
2976}
2977
2978__private_extern__ void *_calloc_internal(size_t count, size_t size)
2979{
2980 return malloc_zone_calloc(_objc_internal_zone(), count, size);
2981}
2982
2983__private_extern__ void *_realloc_internal(void *ptr, size_t size)
2984{
2985 return malloc_zone_realloc(_objc_internal_zone(), ptr, size);
2986}
2987
2988__private_extern__ char *_strdup_internal(const char *str)
2989{
2990 size_t len = strlen(str);
2991 char *dup = malloc_zone_malloc(_objc_internal_zone(), len + 1);
2992 memcpy(dup, str, len + 1);
2993 return dup;
2994}
2995
2996__private_extern__ void _free_internal(void *ptr)
2997{
2998 malloc_zone_free(_objc_internal_zone(), ptr);
2999}
3000
3001
3002
13d88034 3003/***********************************************************************
41c8faa5
A
3004* cache collection.
3005**********************************************************************/
13d88034
A
3006
3007static unsigned long _get_pc_for_thread (mach_port_t thread)
3008#ifdef hppa
3009{
41c8faa5
A
3010 struct hp_pa_frame_thread_state state;
3011 unsigned int count = HPPA_FRAME_THREAD_STATE_COUNT;
390d5862
A
3012 kern_return_t okay = thread_get_state (thread, HPPA_FRAME_THREAD_STATE, (thread_state_t)&state, &count);
3013 return (okay == KERN_SUCCESS) ? state.ts_pcoq_front : PC_SENTINAL;
13d88034
A
3014}
3015#elif defined(sparc)
3016{
41c8faa5
A
3017 struct sparc_thread_state_regs state;
3018 unsigned int count = SPARC_THREAD_STATE_REGS_COUNT;
390d5862
A
3019 kern_return_t okay = thread_get_state (thread, SPARC_THREAD_STATE_REGS, (thread_state_t)&state, &count);
3020 return (okay == KERN_SUCCESS) ? state.regs.r_pc : PC_SENTINAL;
13d88034
A
3021}
3022#elif defined(__i386__) || defined(i386)
3023{
41c8faa5
A
3024 i386_thread_state_t state;
3025 unsigned int count = i386_THREAD_STATE_COUNT;
390d5862
A
3026 kern_return_t okay = thread_get_state (thread, i386_THREAD_STATE, (thread_state_t)&state, &count);
3027 return (okay == KERN_SUCCESS) ? state.eip : PC_SENTINAL;
13d88034
A
3028}
3029#elif defined(m68k)
3030{
41c8faa5
A
3031 struct m68k_thread_state_regs state;
3032 unsigned int count = M68K_THREAD_STATE_REGS_COUNT;
390d5862
A
3033 kern_return_t okay = thread_get_state (thread, M68K_THREAD_STATE_REGS, (thread_state_t)&state, &count);
3034 return (okay == KERN_SUCCESS) ? state.pc : PC_SENTINAL;
13d88034
A
3035}
3036#elif defined(__ppc__) || defined(ppc)
3037{
41c8faa5
A
3038 struct ppc_thread_state state;
3039 unsigned int count = PPC_THREAD_STATE_COUNT;
390d5862
A
3040 kern_return_t okay = thread_get_state (thread, PPC_THREAD_STATE, (thread_state_t)&state, &count);
3041 return (okay == KERN_SUCCESS) ? state.srr0 : PC_SENTINAL;
41c8faa5 3042}
13d88034
A
3043#else
3044{
41c8faa5 3045#error _get_pc_for_thread () not implemented for this architecture
13d88034
A
3046}
3047#endif
3048
3049/***********************************************************************
41c8faa5 3050* _collecting_in_critical.
1f20c7a7
A
3051* Returns TRUE if some thread is currently executing a cache-reading
3052* function. Collection of cache garbage is not allowed when a cache-
3053* reading function is in progress because it might still be using
3054* the garbage memory.
41c8faa5 3055**********************************************************************/
13d88034
A
3056OBJC_EXPORT unsigned long objc_entryPoints[];
3057OBJC_EXPORT unsigned long objc_exitPoints[];
3058
3059static int _collecting_in_critical (void)
3060{
41c8faa5
A
3061 thread_act_port_array_t threads;
3062 unsigned number;
3063 unsigned count;
3064 kern_return_t ret;
3065 int result;
1f20c7a7 3066
41c8faa5
A
3067 mach_port_t mythread = pthread_mach_thread_np(pthread_self());
3068
3069 // Get a list of all the threads in the current task
3070 ret = task_threads (mach_task_self (), &threads, &number);
3071 if (ret != KERN_SUCCESS)
3072 {
390d5862 3073 _objc_fatal("task_thread failed (result %d)\n", ret);
41c8faa5
A
3074 }
3075
3076 // Check whether any thread is in the cache lookup code
1f20c7a7
A
3077 result = FALSE;
3078 for (count = 0; count < number; count++)
41c8faa5 3079 {
1f20c7a7
A
3080 int region;
3081 unsigned long pc;
41c8faa5
A
3082
3083 // Don't bother checking ourselves
3084 if (threads[count] == mythread)
3085 continue;
3086
3087 // Find out where thread is executing
3088 pc = _get_pc_for_thread (threads[count]);
3089
390d5862
A
3090 // Check for bad status, and if so, assume the worse (can't collect)
3091 if (pc == PC_SENTINAL)
3092 {
3093 result = TRUE;
3094 goto done;
3095 }
3096
41c8faa5 3097 // Check whether it is in the cache lookup code
1f20c7a7 3098 for (region = 0; objc_entryPoints[region] != 0; region++)
41c8faa5
A
3099 {
3100 if ((pc >= objc_entryPoints[region]) &&
1f20c7a7
A
3101 (pc <= objc_exitPoints[region]))
3102 {
3103 result = TRUE;
3104 goto done;
3105 }
41c8faa5
A
3106 }
3107 }
1f20c7a7
A
3108
3109 done:
41c8faa5
A
3110 // Deallocate the port rights for the threads
3111 for (count = 0; count < number; count++) {
3112 mach_port_deallocate(mach_task_self (), threads[count]);
3113 }
3114
3115 // Deallocate the thread list
3116 vm_deallocate (mach_task_self (), (vm_address_t) threads, sizeof(threads) * number);
3117
3118 // Return our finding
3119 return result;
3120}
3121
3122/***********************************************************************
3123* _garbage_make_room. Ensure that there is enough room for at least
3124* one more ref in the garbage.
3125**********************************************************************/
13d88034
A
3126
3127// amount of memory represented by all refs in the garbage
3128static int garbage_byte_size = 0;
3129
3130// do not empty the garbage until garbage_byte_size gets at least this big
3131static int garbage_threshold = 1024;
3132
3133// table of refs to free
3134static void **garbage_refs = 0;
3135
3136// current number of refs in garbage_refs
3137static int garbage_count = 0;
3138
3139// capacity of current garbage_refs
3140static int garbage_max = 0;
3141
3142// capacity of initial garbage_refs
3143enum {
41c8faa5 3144 INIT_GARBAGE_COUNT = 128
13d88034
A
3145};
3146
3147static void _garbage_make_room (void)
3148{
41c8faa5
A
3149 static int first = 1;
3150 volatile void * tempGarbage;
3151
3152 // Create the collection table the first time it is needed
3153 if (first)
3154 {
3155 first = 0;
2bfd4448 3156 garbage_refs = _malloc_internal(INIT_GARBAGE_COUNT * sizeof(void *));
41c8faa5
A
3157 garbage_max = INIT_GARBAGE_COUNT;
3158 }
3159
3160 // Double the table if it is full
3161 else if (garbage_count == garbage_max)
3162 {
2bfd4448 3163 tempGarbage = _realloc_internal(garbage_refs, garbage_max * 2 * sizeof(void *));
41c8faa5
A
3164 garbage_refs = (void **) tempGarbage;
3165 garbage_max *= 2;
3166 }
3167}
3168
3169/***********************************************************************
3170* _cache_collect_free. Add the specified malloc'd memory to the list
3171* of them to free at some later point.
2bfd4448
A
3172* size is used for the collection threshold. It does not have to be
3173* precisely the block's size.
1f20c7a7 3174* Cache locks: cacheUpdateLock must be held by the caller.
41c8faa5 3175**********************************************************************/
2bfd4448 3176static void _cache_collect_free(void *data, size_t size, BOOL tryCollect)
41c8faa5
A
3177{
3178 static char *report_garbage = (char *)0xffffffff;
3179
3180 if ((char *)0xffffffff == report_garbage) {
3181 // Check whether to log our activity
3182 report_garbage = getenv ("OBJC_REPORT_GARBAGE");
3183 }
3184
41c8faa5
A
3185 // Insert new element in garbage list
3186 // Note that we do this even if we end up free'ing everything
3187 _garbage_make_room ();
2bfd4448 3188 garbage_byte_size += size;
41c8faa5
A
3189 garbage_refs[garbage_count++] = data;
3190
3191 // Log our progress
3192 if (tryCollect && report_garbage)
3193 _objc_inform ("total of %d bytes of garbage ...", garbage_byte_size);
3194
3195 // Done if caller says not to empty or the garbage is not full
3196 if (!tryCollect || (garbage_byte_size < garbage_threshold))
3197 {
41c8faa5 3198 if (tryCollect && report_garbage)
1f20c7a7 3199 _objc_inform ("couldn't collect cache garbage: below threshold\n");
41c8faa5
A
3200
3201 return;
3202 }
3203
1f20c7a7
A
3204 // tryCollect is guaranteed to be true after this point
3205
3206 // Synchronize garbage collection with objc_msgSend and other cache readers
3207 if (!_collecting_in_critical ()) {
3208 // No cache readers in progress - garbage is now deletable
3209
3210 // Log our progress
3211 if (report_garbage)
3212 _objc_inform ("collecting!\n");
3213
3214 // Dispose all refs now in the garbage
2bfd4448
A
3215 while (garbage_count--) {
3216 if (cache_allocator_is_block(garbage_refs[garbage_count])) {
3217 cache_allocator_free(garbage_refs[garbage_count]);
3218 } else {
3219 free(garbage_refs[garbage_count]);
3220 }
3221 }
3222
3223 // Clear the garbage count and total size indicator
3224 garbage_count = 0;
1f20c7a7
A
3225 garbage_byte_size = 0;
3226 }
3227 else {
3228 // objc_msgSend (or other cache reader) is currently looking in the
3229 // cache and might still be using some garbage.
3230 if (report_garbage) {
3231 _objc_inform ("couldn't collect cache garbage: objc_msgSend in progress\n");
41c8faa5 3232 }
41c8faa5 3233 }
13d88034 3234}
13d88034
A
3235
3236
2bfd4448
A
3237
3238/***********************************************************************
3239* Custom method cache allocator.
3240* Method cache block sizes are 2^slots+2 words, which is a pessimal
3241* case for the system allocator. It wastes 504 bytes per cache block
3242* with 128 or more slots, which adds up to tens of KB for an AppKit process.
3243* To save memory, the custom cache allocator below is used.
3244*
3245* The cache allocator uses 128 KB allocation regions. Few processes will
3246* require a second region. Within a region, allocation is address-ordered
3247* first fit.
3248*
3249* The cache allocator uses a quantum of 520.
3250* Cache block ideal sizes: 520, 1032, 2056, 4104
3251* Cache allocator sizes: 520, 1040, 2080, 4160
3252*
3253* Because all blocks are known to be genuine method caches, the ordinary
3254* cache->mask and cache->occupied fields are used as block headers.
3255* No out-of-band headers are maintained. The number of blocks will
3256* almost always be fewer than 200, so for simplicity there is no free
3257* list or other optimization.
3258*
3259* Block in use: mask != 0, occupied != -1 (mask indicates block size)
3260* Block free: mask != 0, occupied == -1 (mask is precisely block size)
3261*
3262* No cache allocator functions take any locks. Instead, the caller
3263* must hold the cacheUpdateLock.
3264**********************************************************************/
3265
3266typedef struct cache_allocator_block {
3267 unsigned int size;
3268 unsigned int state;
3269 struct cache_allocator_block *nextFree;
3270} cache_allocator_block;
3271
3272typedef struct cache_allocator_region {
3273 cache_allocator_block *start;
3274 cache_allocator_block *end; // first non-block address
3275 cache_allocator_block *freeList;
3276 struct cache_allocator_region *next;
3277} cache_allocator_region;
3278
3279static cache_allocator_region *cacheRegion = NULL;
3280
3281
3282static unsigned int cache_allocator_mask_for_size(size_t size)
3283{
3284 return (size - sizeof(struct objc_cache)) / sizeof(Method);
3285}
3286
3287static size_t cache_allocator_size_for_mask(unsigned int mask)
3288{
3289 size_t requested = sizeof(struct objc_cache) + TABLE_SIZE(mask+1);
3290 size_t actual = CACHE_QUANTUM;
3291 while (actual < requested) actual += CACHE_QUANTUM;
3292 return actual;
3293}
3294
3295/***********************************************************************
3296* cache_allocator_add_region
3297* Allocates and returns a new region that can hold at least size
3298* bytes of large method caches.
3299* The actual size will be rounded up to a CACHE_QUANTUM boundary,
3300* with a minimum of CACHE_REGION_SIZE.
3301* The new region is lowest-priority for new allocations. Callers that
3302* know the other regions are already full should allocate directly
3303* into the returned region.
3304**********************************************************************/
3305static cache_allocator_region *cache_allocator_add_region(size_t size)
3306{
3307 vm_address_t addr;
3308 cache_allocator_block *b;
3309 cache_allocator_region **rgnP;
3310 cache_allocator_region *newRegion =
3311 _calloc_internal(1, sizeof(cache_allocator_region));
3312
3313 // Round size up to quantum boundary, and apply the minimum size.
3314 size += CACHE_QUANTUM - (size % CACHE_QUANTUM);
3315 if (size < CACHE_REGION_SIZE) size = CACHE_REGION_SIZE;
3316
3317 // Allocate the region
3318 addr = 0;
3319 vm_allocate(mach_task_self(), &addr, size, 1);
3320 newRegion->start = (cache_allocator_block *)addr;
3321 newRegion->end = (cache_allocator_block *)(addr + size);
3322
3323 // Mark the first block: free and covers the entire region
3324 b = newRegion->start;
3325 b->size = size;
3326 b->state = (unsigned int)-1;
3327 b->nextFree = NULL;
3328 newRegion->freeList = b;
3329
3330 // Add to end of the linked list of regions.
3331 // Other regions should be re-used before this one is touched.
3332 newRegion->next = NULL;
3333 rgnP = &cacheRegion;
3334 while (*rgnP) {
3335 rgnP = &(**rgnP).next;
3336 }
3337 *rgnP = newRegion;
3338
3339 return newRegion;
3340}
3341
3342
3343/***********************************************************************
3344* cache_allocator_coalesce
3345* Attempts to coalesce a free block with the single free block following
3346* it in the free list, if any.
3347**********************************************************************/
3348static void cache_allocator_coalesce(cache_allocator_block *block)
3349{
3350 if (block->size + (uintptr_t)block == (uintptr_t)block->nextFree) {
3351 block->size += block->nextFree->size;
3352 block->nextFree = block->nextFree->nextFree;
3353 }
3354}
3355
3356
3357/***********************************************************************
3358* cache_region_calloc
3359* Attempt to allocate a size-byte block in the given region.
3360* Allocation is first-fit. The free list is already fully coalesced.
3361* Returns NULL if there is not enough room in the region for the block.
3362**********************************************************************/
3363static void *cache_region_calloc(cache_allocator_region *rgn, size_t size)
3364{
3365 cache_allocator_block **blockP;
3366 unsigned int mask;
3367
3368 // Save mask for allocated block, then round size
3369 // up to CACHE_QUANTUM boundary
3370 mask = cache_allocator_mask_for_size(size);
3371 size = cache_allocator_size_for_mask(mask);
3372
3373 // Search the free list for a sufficiently large free block.
3374
3375 for (blockP = &rgn->freeList;
3376 *blockP != NULL;
3377 blockP = &(**blockP).nextFree)
3378 {
3379 cache_allocator_block *block = *blockP;
3380 if (block->size < size) continue; // not big enough
3381
3382 // block is now big enough. Allocate from it.
3383
3384 // Slice off unneeded fragment of block, if any,
3385 // and reconnect the free list around block.
3386 if (block->size - size >= CACHE_QUANTUM) {
3387 cache_allocator_block *leftover =
3388 (cache_allocator_block *)(size + (uintptr_t)block);
3389 leftover->size = block->size - size;
3390 leftover->state = (unsigned int)-1;
3391 leftover->nextFree = block->nextFree;
3392 *blockP = leftover;
3393 } else {
3394 *blockP = block->nextFree;
3395 }
3396
3397 // block is now exactly the right size.
3398
3399 bzero(block, size);
3400 block->size = mask; // Cache->mask
3401 block->state = 0; // Cache->occupied
3402
3403 return block;
3404 }
3405
3406 // No room in this region.
3407 return NULL;
3408}
3409
3410
3411/***********************************************************************
3412* cache_allocator_calloc
3413* Custom allocator for large method caches (128+ slots)
3414* The returned cache block already has cache->mask set.
3415* cache->occupied and the cache contents are zero.
3416* Cache locks: cacheUpdateLock must be held by the caller
3417**********************************************************************/
3418static void *cache_allocator_calloc(size_t size)
3419{
3420 cache_allocator_region *rgn;
3421
3422 for (rgn = cacheRegion; rgn != NULL; rgn = rgn->next) {
3423 void *p = cache_region_calloc(rgn, size);
3424 if (p) {
3425 return p;
3426 }
3427 }
3428
3429 // No regions or all regions full - make a region and try one more time
3430 // In the unlikely case of a cache over 256KB, it will get its own region.
3431 return cache_region_calloc(cache_allocator_add_region(size), size);
3432}
3433
3434
3435/***********************************************************************
3436* cache_allocator_region_for_block
3437* Returns the cache allocator region that ptr points into, or NULL.
3438**********************************************************************/
3439static cache_allocator_region *cache_allocator_region_for_block(cache_allocator_block *block)
3440{
3441 cache_allocator_region *rgn;
3442 for (rgn = cacheRegion; rgn != NULL; rgn = rgn->next) {
3443 if (block >= rgn->start && block < rgn->end) return rgn;
3444 }
3445 return NULL;
3446}
3447
3448
3449/***********************************************************************
3450* cache_allocator_is_block
3451* If ptr is a live block from the cache allocator, return YES
3452* If ptr is a block from some other allocator, return NO.
3453* If ptr is a dead block from the cache allocator, result is undefined.
3454* Cache locks: cacheUpdateLock must be held by the caller
3455**********************************************************************/
3456static BOOL cache_allocator_is_block(void *ptr)
3457{
3458 return (cache_allocator_region_for_block((cache_allocator_block *)ptr) != NULL);
3459}
3460
3461/***********************************************************************
3462* cache_allocator_free
3463* Frees a block allocated by the cache allocator.
3464* Cache locks: cacheUpdateLock must be held by the caller.
3465**********************************************************************/
3466static void cache_allocator_free(void *ptr)
3467{
3468 cache_allocator_block *dead = (cache_allocator_block *)ptr;
3469 cache_allocator_block *cur;
3470 cache_allocator_region *rgn;
3471
3472 if (! (rgn = cache_allocator_region_for_block(ptr))) {
3473 // free of non-pointer
3474 _objc_inform("cache_allocator_free of non-pointer %p", ptr);
3475 return;
3476 }
3477
3478 dead->size = cache_allocator_size_for_mask(dead->size);
3479 dead->state = (unsigned int)-1;
3480
3481 if (!rgn->freeList || rgn->freeList > dead) {
3482 // dead block belongs at front of free list
3483 dead->nextFree = rgn->freeList;
3484 rgn->freeList = dead;
3485 cache_allocator_coalesce(dead);
3486 return;
3487 }
3488
3489 // dead block belongs in the middle or end of free list
3490 for (cur = rgn->freeList; cur != NULL; cur = cur->nextFree) {
3491 cache_allocator_block *ahead = cur->nextFree;
3492
3493 if (!ahead || ahead > dead) {
3494 // cur and ahead straddle dead, OR dead belongs at end of free list
3495 cur->nextFree = dead;
3496 dead->nextFree = ahead;
3497
3498 // coalesce into dead first in case both succeed
3499 cache_allocator_coalesce(dead);
3500 cache_allocator_coalesce(cur);
3501 return;
3502 }
3503 }
3504
3505 // uh-oh
3506 _objc_inform("cache_allocator_free of non-pointer %p", ptr);
3507}
3508
3509
13d88034 3510/***********************************************************************
41c8faa5
A
3511* _cache_print.
3512**********************************************************************/
13d88034
A
3513static void _cache_print (Cache cache)
3514{
41c8faa5
A
3515 unsigned int index;
3516 unsigned int count;
3517
3518 count = cache->mask + 1;
3519 for (index = 0; index < count; index += 1)
3520 if (CACHE_BUCKET_VALID(cache->buckets[index]))
3521 {
3522 if (CACHE_BUCKET_IMP(cache->buckets[index]) == &_objc_msgForward)
3523 printf ("does not recognize: \n");
3524 printf ("%s\n", (const char *) CACHE_BUCKET_NAME(cache->buckets[index]));
3525 }
13d88034
A
3526}
3527
3528/***********************************************************************
41c8faa5
A
3529* _class_printMethodCaches.
3530**********************************************************************/
13d88034
A
3531void _class_printMethodCaches (Class cls)
3532{
41c8faa5
A
3533 if (((struct objc_class *)cls)->cache == &emptyCache)
3534 printf ("no instance-method cache for class %s\n", ((struct objc_class *)cls)->name);
3535
3536 else
3537 {
3538 printf ("instance-method cache for class %s:\n", ((struct objc_class *)cls)->name);
3539 _cache_print (((struct objc_class *)cls)->cache);
3540 }
3541
3542 if (((struct objc_class * )((struct objc_class * )cls)->isa)->cache == &emptyCache)
3543 printf ("no class-method cache for class %s\n", ((struct objc_class *)cls)->name);
3544
3545 else
3546 {
3547 printf ("class-method cache for class %s:\n", ((struct objc_class *)cls)->name);
3548 _cache_print (((struct objc_class * )((struct objc_class * )cls)->isa)->cache);
3549 }
3550}
3551
3552/***********************************************************************
3553* log2.
3554**********************************************************************/
13d88034
A
3555static unsigned int log2 (unsigned int x)
3556{
41c8faa5
A
3557 unsigned int log;
3558
3559 log = 0;
3560 while (x >>= 1)
3561 log += 1;
3562
3563 return log;
3564}
3565
3566/***********************************************************************
3567* _class_printDuplicateCacheEntries.
3568**********************************************************************/
3569void _class_printDuplicateCacheEntries (BOOL detail)
3570{
3571 NXHashTable * class_hash;
3572 NXHashState state;
3573 struct objc_class * cls;
3574 unsigned int duplicates;
3575 unsigned int index1;
3576 unsigned int index2;
3577 unsigned int mask;
3578 unsigned int count;
3579 unsigned int isMeta;
3580 Cache cache;
3581
3582
3583 printf ("Checking for duplicate cache entries \n");
3584
3585 // Outermost loop - iterate over all classes
3586 class_hash = objc_getClasses ();
3587 state = NXInitHashState (class_hash);
3588 duplicates = 0;
3589 while (NXNextHashState (class_hash, &state, (void **) &cls))
3590 {
3591 // Control loop - do given class' cache, then its isa's cache
3592 for (isMeta = 0; isMeta <= 1; isMeta += 1)
3593 {
3594 // Select cache of interest and make sure it exists
3595 cache = isMeta ? cls->isa->cache : ((struct objc_class *)cls)->cache;
3596 if (cache == &emptyCache)
3597 continue;
3598
3599 // Middle loop - check each entry in the given cache
3600 mask = cache->mask;
3601 count = mask + 1;
3602 for (index1 = 0; index1 < count; index1 += 1)
3603 {
3604 // Skip invalid entry
3605 if (!CACHE_BUCKET_VALID(cache->buckets[index1]))
3606 continue;
3607
3608 // Inner loop - check that given entry matches no later entry
3609 for (index2 = index1 + 1; index2 < count; index2 += 1)
3610 {
3611 // Skip invalid entry
3612 if (!CACHE_BUCKET_VALID(cache->buckets[index2]))
3613 continue;
3614
3615 // Check for duplication by method name comparison
3616 if (strcmp ((char *) CACHE_BUCKET_NAME(cache->buckets[index1]),
3617 (char *) CACHE_BUCKET_NAME(cache->buckets[index2])) == 0)
3618 {
3619 if (detail)
3620 printf ("%s %s\n", ((struct objc_class *)cls)->name, (char *) CACHE_BUCKET_NAME(cache->buckets[index1]));
3621 duplicates += 1;
3622 break;
3623 }
3624 }
3625 }
3626 }
3627 }
3628
3629 // Log the findings
3630 printf ("duplicates = %d\n", duplicates);
3631 printf ("total cache fills = %d\n", totalCacheFills);
3632}
3633
3634/***********************************************************************
3635* PrintCacheHeader.
3636**********************************************************************/
13d88034
A
3637static void PrintCacheHeader (void)
3638{
3639#ifdef OBJC_INSTRUMENTED
41c8faa5
A
3640 printf ("Cache Cache Slots Avg Max AvgS MaxS AvgS MaxS TotalD AvgD MaxD TotalD AvgD MaxD TotD AvgD MaxD\n");
3641 printf ("Size Count Used Used Used Hit Hit Miss Miss Hits Prbs Prbs Misses Prbs Prbs Flsh Flsh Flsh\n");
3642 printf ("----- ----- ----- ----- ---- ---- ---- ---- ---- ------- ---- ---- ------- ---- ---- ---- ---- ----\n");
13d88034 3643#else
41c8faa5
A
3644 printf ("Cache Cache Slots Avg Max AvgS MaxS AvgS MaxS\n");
3645 printf ("Size Count Used Used Used Hit Hit Miss Miss\n");
3646 printf ("----- ----- ----- ----- ---- ---- ---- ---- ----\n");
13d88034
A
3647#endif
3648}
3649
3650/***********************************************************************
41c8faa5
A
3651* PrintCacheInfo.
3652**********************************************************************/
13d88034 3653static void PrintCacheInfo (unsigned int cacheSize,
41c8faa5
A
3654 unsigned int cacheCount,
3655 unsigned int slotsUsed,
3656 float avgUsed,
3657 unsigned int maxUsed,
3658 float avgSHit,
3659 unsigned int maxSHit,
3660 float avgSMiss,
3661 unsigned int maxSMiss
13d88034 3662#ifdef OBJC_INSTRUMENTED
41c8faa5
A
3663 , unsigned int totDHits,
3664 float avgDHit,
3665 unsigned int maxDHit,
3666 unsigned int totDMisses,
3667 float avgDMiss,
3668 unsigned int maxDMiss,
3669 unsigned int totDFlsh,
3670 float avgDFlsh,
3671 unsigned int maxDFlsh
13d88034 3672#endif
41c8faa5 3673 )
13d88034
A
3674{
3675#ifdef OBJC_INSTRUMENTED
41c8faa5 3676 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",
13d88034 3677#else
41c8faa5 3678 printf ("%5u %5u %5u %5.1f %4u %4.1f %4u %4.1f %4u\n",
13d88034 3679#endif
41c8faa5 3680 cacheSize, cacheCount, slotsUsed, avgUsed, maxUsed, avgSHit, maxSHit, avgSMiss, maxSMiss
13d88034 3681#ifdef OBJC_INSTRUMENTED
41c8faa5 3682 , totDHits, avgDHit, maxDHit, totDMisses, avgDMiss, maxDMiss, totDFlsh, avgDFlsh, maxDFlsh
13d88034 3683#endif
41c8faa5
A
3684 );
3685
13d88034
A
3686}
3687
3688#ifdef OBJC_INSTRUMENTED
3689/***********************************************************************
41c8faa5
A
3690* PrintCacheHistogram. Show the non-zero entries from the specified
3691* cache histogram.
3692**********************************************************************/
13d88034 3693static void PrintCacheHistogram (char * title,
41c8faa5
A
3694 unsigned int * firstEntry,
3695 unsigned int entryCount)
3696{
3697 unsigned int index;
3698 unsigned int * thisEntry;
3699
3700 printf ("%s\n", title);
3701 printf (" Probes Tally\n");
3702 printf (" ------ -----\n");
3703 for (index = 0, thisEntry = firstEntry;
3704 index < entryCount;
3705 index += 1, thisEntry += 1)
3706 {
3707 if (*thisEntry == 0)
3708 continue;
3709
3710 printf (" %6d %5d\n", index, *thisEntry);
3711 }
13d88034
A
3712}
3713#endif
3714
3715/***********************************************************************
41c8faa5
A
3716* _class_printMethodCacheStatistics.
3717**********************************************************************/
13d88034
A
3718
3719#define MAX_LOG2_SIZE 32
3720#define MAX_CHAIN_SIZE 100
3721
3722void _class_printMethodCacheStatistics (void)
3723{
41c8faa5
A
3724 unsigned int isMeta;
3725 unsigned int index;
3726 NXHashTable * class_hash;
3727 NXHashState state;
3728 struct objc_class * cls;
3729 unsigned int totalChain;
3730 unsigned int totalMissChain;
3731 unsigned int maxChain;
3732 unsigned int maxMissChain;
3733 unsigned int classCount;
3734 unsigned int negativeEntryCount;
3735 unsigned int cacheExpandCount;
3736 unsigned int cacheCountBySize[2][MAX_LOG2_SIZE] = {{0}};
3737 unsigned int totalEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};
3738 unsigned int maxEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};
3739 unsigned int totalChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3740 unsigned int totalMissChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3741 unsigned int totalMaxChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3742 unsigned int totalMaxMissChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3743 unsigned int maxChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3744 unsigned int maxMissChainBySize[2][MAX_LOG2_SIZE] = {{0}};
3745 unsigned int chainCount[MAX_CHAIN_SIZE] = {0};
3746 unsigned int missChainCount[MAX_CHAIN_SIZE] = {0};
13d88034 3747#ifdef OBJC_INSTRUMENTED
41c8faa5
A
3748 unsigned int hitCountBySize[2][MAX_LOG2_SIZE] = {{0}};
3749 unsigned int hitProbesBySize[2][MAX_LOG2_SIZE] = {{0}};
3750 unsigned int maxHitProbesBySize[2][MAX_LOG2_SIZE] = {{0}};
3751 unsigned int missCountBySize[2][MAX_LOG2_SIZE] = {{0}};
3752 unsigned int missProbesBySize[2][MAX_LOG2_SIZE] = {{0}};
3753 unsigned int maxMissProbesBySize[2][MAX_LOG2_SIZE] = {{0}};
3754 unsigned int flushCountBySize[2][MAX_LOG2_SIZE] = {{0}};
3755 unsigned int flushedEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};
3756 unsigned int maxFlushedEntriesBySize[2][MAX_LOG2_SIZE] = {{0}};
13d88034
A
3757#endif
3758
41c8faa5
A
3759 printf ("Printing cache statistics\n");
3760
3761 // Outermost loop - iterate over all classes
3762 class_hash = objc_getClasses ();
3763 state = NXInitHashState (class_hash);
3764 classCount = 0;
3765 negativeEntryCount = 0;
3766 cacheExpandCount = 0;
3767 while (NXNextHashState (class_hash, &state, (void **) &cls))
3768 {
3769 // Tally classes
3770 classCount += 1;
3771
3772 // Control loop - do given class' cache, then its isa's cache
3773 for (isMeta = 0; isMeta <= 1; isMeta += 1)
3774 {
3775 Cache cache;
3776 unsigned int mask;
3777 unsigned int log2Size;
3778 unsigned int entryCount;
3779
3780 // Select cache of interest
3781 cache = isMeta ? cls->isa->cache : ((struct objc_class *)cls)->cache;
3782
3783 // Ignore empty cache... should we?
3784 if (cache == &emptyCache)
3785 continue;
3786
3787 // Middle loop - do each entry in the given cache
3788 mask = cache->mask;
3789 entryCount = 0;
3790 totalChain = 0;
3791 totalMissChain = 0;
3792 maxChain = 0;
3793 maxMissChain = 0;
3794 for (index = 0; index < mask + 1; index += 1)
3795 {
3796 Method * buckets;
3797 Method method;
3798 uarith_t hash;
3799 uarith_t methodChain;
3800 uarith_t methodMissChain;
3801 uarith_t index2;
3802
3803 // If entry is invalid, the only item of
3804 // interest is that future insert hashes
3805 // to this entry can use it directly.
3806 buckets = cache->buckets;
3807 if (!CACHE_BUCKET_VALID(buckets[index]))
3808 {
3809 missChainCount[0] += 1;
3810 continue;
3811 }
3812
3813 method = buckets[index];
3814
3815 // Tally valid entries
3816 entryCount += 1;
3817
3818 // Tally "forward::" entries
3819 if (CACHE_BUCKET_IMP(method) == &_objc_msgForward)
3820 negativeEntryCount += 1;
3821
3822 // Calculate search distance (chain length) for this method
1f20c7a7
A
3823 // The chain may wrap around to the beginning of the table.
3824 hash = CACHE_HASH(CACHE_BUCKET_NAME(method), mask);
3825 if (index >= hash) methodChain = index - hash;
3826 else methodChain = (mask+1) + index - hash;
41c8faa5
A
3827
3828 // Tally chains of this length
3829 if (methodChain < MAX_CHAIN_SIZE)
3830 chainCount[methodChain] += 1;
3831
3832 // Keep sum of all chain lengths
3833 totalChain += methodChain;
3834
3835 // Record greatest chain length
3836 if (methodChain > maxChain)
3837 maxChain = methodChain;
3838
3839 // Calculate search distance for miss that hashes here
3840 index2 = index;
3841 while (CACHE_BUCKET_VALID(buckets[index2]))
3842 {
3843 index2 += 1;
3844 index2 &= mask;
3845 }
3846 methodMissChain = ((index2 - index) & mask);
3847
3848 // Tally miss chains of this length
3849 if (methodMissChain < MAX_CHAIN_SIZE)
3850 missChainCount[methodMissChain] += 1;
3851
3852 // Keep sum of all miss chain lengths in this class
3853 totalMissChain += methodMissChain;
3854
3855 // Record greatest miss chain length
3856 if (methodMissChain > maxMissChain)
3857 maxMissChain = methodMissChain;
3858 }
3859
3860 // Factor this cache into statistics about caches of the same
3861 // type and size (all caches are a power of two in size)
3862 log2Size = log2 (mask + 1);
3863 cacheCountBySize[isMeta][log2Size] += 1;
3864 totalEntriesBySize[isMeta][log2Size] += entryCount;
3865 if (entryCount > maxEntriesBySize[isMeta][log2Size])
3866 maxEntriesBySize[isMeta][log2Size] = entryCount;
3867 totalChainBySize[isMeta][log2Size] += totalChain;
3868 totalMissChainBySize[isMeta][log2Size] += totalMissChain;
3869 totalMaxChainBySize[isMeta][log2Size] += maxChain;
3870 totalMaxMissChainBySize[isMeta][log2Size] += maxMissChain;
3871 if (maxChain > maxChainBySize[isMeta][log2Size])
3872 maxChainBySize[isMeta][log2Size] = maxChain;
3873 if (maxMissChain > maxMissChainBySize[isMeta][log2Size])
3874 maxMissChainBySize[isMeta][log2Size] = maxMissChain;
13d88034 3875#ifdef OBJC_INSTRUMENTED
41c8faa5
A
3876 {
3877 CacheInstrumentation * cacheData;
3878
3879 cacheData = CACHE_INSTRUMENTATION(cache);
3880 hitCountBySize[isMeta][log2Size] += cacheData->hitCount;
3881 hitProbesBySize[isMeta][log2Size] += cacheData->hitProbes;
3882 if (cacheData->maxHitProbes > maxHitProbesBySize[isMeta][log2Size])
3883 maxHitProbesBySize[isMeta][log2Size] = cacheData->maxHitProbes;
3884 missCountBySize[isMeta][log2Size] += cacheData->missCount;
3885 missProbesBySize[isMeta][log2Size] += cacheData->missProbes;
3886 if (cacheData->maxMissProbes > maxMissProbesBySize[isMeta][log2Size])
3887 maxMissProbesBySize[isMeta][log2Size] = cacheData->maxMissProbes;
3888 flushCountBySize[isMeta][log2Size] += cacheData->flushCount;
3889 flushedEntriesBySize[isMeta][log2Size] += cacheData->flushedEntries;
3890 if (cacheData->maxFlushedEntries > maxFlushedEntriesBySize[isMeta][log2Size])
3891 maxFlushedEntriesBySize[isMeta][log2Size] = cacheData->maxFlushedEntries;
3892 }
13d88034 3893#endif
41c8faa5
A
3894 // Caches start with a power of two number of entries, and grow by doubling, so
3895 // we can calculate the number of times this cache has expanded
3896 if (isMeta)
3897 cacheExpandCount += log2Size - INIT_META_CACHE_SIZE_LOG2;
3898 else
3899 cacheExpandCount += log2Size - INIT_CACHE_SIZE_LOG2;
3900
3901 }
3902 }
3903
3904 {
3905 unsigned int cacheCountByType[2] = {0};
3906 unsigned int totalCacheCount = 0;
3907 unsigned int totalEntries = 0;
3908 unsigned int maxEntries = 0;
3909 unsigned int totalSlots = 0;
13d88034 3910#ifdef OBJC_INSTRUMENTED
41c8faa5
A
3911 unsigned int totalHitCount = 0;
3912 unsigned int totalHitProbes = 0;
3913 unsigned int maxHitProbes = 0;
3914 unsigned int totalMissCount = 0;
3915 unsigned int totalMissProbes = 0;
3916 unsigned int maxMissProbes = 0;
3917 unsigned int totalFlushCount = 0;
3918 unsigned int totalFlushedEntries = 0;
3919 unsigned int maxFlushedEntries = 0;
13d88034 3920#endif
41c8faa5
A
3921
3922 totalChain = 0;
3923 maxChain = 0;
3924 totalMissChain = 0;
3925 maxMissChain = 0;
3926
3927 // Sum information over all caches
3928 for (isMeta = 0; isMeta <= 1; isMeta += 1)
3929 {
3930 for (index = 0; index < MAX_LOG2_SIZE; index += 1)
3931 {
3932 cacheCountByType[isMeta] += cacheCountBySize[isMeta][index];
3933 totalEntries += totalEntriesBySize[isMeta][index];
3934 totalSlots += cacheCountBySize[isMeta][index] * (1 << index);
3935 totalChain += totalChainBySize[isMeta][index];
3936 if (maxEntriesBySize[isMeta][index] > maxEntries)
3937 maxEntries = maxEntriesBySize[isMeta][index];
3938 if (maxChainBySize[isMeta][index] > maxChain)
3939 maxChain = maxChainBySize[isMeta][index];
3940 totalMissChain += totalMissChainBySize[isMeta][index];
3941 if (maxMissChainBySize[isMeta][index] > maxMissChain)
3942 maxMissChain = maxMissChainBySize[isMeta][index];
13d88034 3943#ifdef OBJC_INSTRUMENTED
41c8faa5
A
3944 totalHitCount += hitCountBySize[isMeta][index];
3945 totalHitProbes += hitProbesBySize[isMeta][index];
3946 if (maxHitProbesBySize[isMeta][index] > maxHitProbes)
3947 maxHitProbes = maxHitProbesBySize[isMeta][index];
3948 totalMissCount += missCountBySize[isMeta][index];
3949 totalMissProbes += missProbesBySize[isMeta][index];
3950 if (maxMissProbesBySize[isMeta][index] > maxMissProbes)
3951 maxMissProbes = maxMissProbesBySize[isMeta][index];
3952 totalFlushCount += flushCountBySize[isMeta][index];
3953 totalFlushedEntries += flushedEntriesBySize[isMeta][index];
3954 if (maxFlushedEntriesBySize[isMeta][index] > maxFlushedEntries)
3955 maxFlushedEntries = maxFlushedEntriesBySize[isMeta][index];
13d88034 3956#endif
41c8faa5
A
3957 }
3958
3959 totalCacheCount += cacheCountByType[isMeta];
3960 }
3961
3962 // Log our findings
3963 printf ("There are %u classes\n", classCount);
3964
3965 for (isMeta = 0; isMeta <= 1; isMeta += 1)
3966 {
3967 // Number of this type of class
3968 printf ("\nThere are %u %s-method caches, broken down by size (slot count):\n",
3969 cacheCountByType[isMeta],
3970 isMeta ? "class" : "instance");
3971
3972 // Print header
3973 PrintCacheHeader ();
3974
3975 // Keep format consistent even if there are caches of this kind
3976 if (cacheCountByType[isMeta] == 0)
3977 {
3978 printf ("(none)\n");
3979 continue;
3980 }
3981
3982 // Usage information by cache size
3983 for (index = 0; index < MAX_LOG2_SIZE; index += 1)
3984 {
3985 unsigned int cacheCount;
3986 unsigned int cacheSlotCount;
3987 unsigned int cacheEntryCount;
3988
3989 // Get number of caches of this type and size
3990 cacheCount = cacheCountBySize[isMeta][index];
3991 if (cacheCount == 0)
3992 continue;
3993
3994 // Get the cache slot count and the total number of valid entries
3995 cacheSlotCount = (1 << index);
3996 cacheEntryCount = totalEntriesBySize[isMeta][index];
3997
3998 // Give the analysis
3999 PrintCacheInfo (cacheSlotCount,
4000 cacheCount,
4001 cacheEntryCount,
4002 (float) cacheEntryCount / (float) cacheCount,
4003 maxEntriesBySize[isMeta][index],
4004 (float) totalChainBySize[isMeta][index] / (float) cacheEntryCount,
4005 maxChainBySize[isMeta][index],
4006 (float) totalMissChainBySize[isMeta][index] / (float) (cacheCount * cacheSlotCount),
4007 maxMissChainBySize[isMeta][index]
13d88034 4008#ifdef OBJC_INSTRUMENTED
41c8faa5
A
4009 , hitCountBySize[isMeta][index],
4010 hitCountBySize[isMeta][index] ?
4011 (float) hitProbesBySize[isMeta][index] / (float) hitCountBySize[isMeta][index] : 0.0,
4012 maxHitProbesBySize[isMeta][index],
4013 missCountBySize[isMeta][index],
4014 missCountBySize[isMeta][index] ?
4015 (float) missProbesBySize[isMeta][index] / (float) missCountBySize[isMeta][index] : 0.0,
4016 maxMissProbesBySize[isMeta][index],
4017 flushCountBySize[isMeta][index],
4018 flushCountBySize[isMeta][index] ?
4019 (float) flushedEntriesBySize[isMeta][index] / (float) flushCountBySize[isMeta][index] : 0.0,
4020 maxFlushedEntriesBySize[isMeta][index]
13d88034 4021#endif
41c8faa5
A
4022 );
4023 }
4024 }
4025
4026 // Give overall numbers
4027 printf ("\nCumulative:\n");
4028 PrintCacheHeader ();
4029 PrintCacheInfo (totalSlots,
4030 totalCacheCount,
4031 totalEntries,
4032 (float) totalEntries / (float) totalCacheCount,
4033 maxEntries,
4034 (float) totalChain / (float) totalEntries,
4035 maxChain,
4036 (float) totalMissChain / (float) totalSlots,
4037 maxMissChain
13d88034 4038#ifdef OBJC_INSTRUMENTED
41c8faa5
A
4039 , totalHitCount,
4040 totalHitCount ?
4041 (float) totalHitProbes / (float) totalHitCount : 0.0,
4042 maxHitProbes,
4043 totalMissCount,
4044 totalMissCount ?
4045 (float) totalMissProbes / (float) totalMissCount : 0.0,
4046 maxMissProbes,
4047 totalFlushCount,
4048 totalFlushCount ?
4049 (float) totalFlushedEntries / (float) totalFlushCount : 0.0,
4050 maxFlushedEntries
13d88034 4051#endif
41c8faa5 4052 );
13d88034 4053
41c8faa5
A
4054 printf ("\nNumber of \"forward::\" entries: %d\n", negativeEntryCount);
4055 printf ("Number of cache expansions: %d\n", cacheExpandCount);
13d88034 4056#ifdef OBJC_INSTRUMENTED
41c8faa5
A
4057 printf ("flush_caches: total calls total visits average visits max visits total classes visits/class\n");
4058 printf (" ----------- ------------ -------------- ---------- ------------- -------------\n");
4059 printf (" linear %11u %12u %14.1f %10u %13u %12.2f\n",
4060 LinearFlushCachesCount,
4061 LinearFlushCachesVisitedCount,
4062 LinearFlushCachesCount ?
4063 (float) LinearFlushCachesVisitedCount / (float) LinearFlushCachesCount : 0.0,
4064 MaxLinearFlushCachesVisitedCount,
4065 LinearFlushCachesVisitedCount,
4066 1.0);
4067 printf (" nonlinear %11u %12u %14.1f %10u %13u %12.2f\n",
4068 NonlinearFlushCachesCount,
4069 NonlinearFlushCachesVisitedCount,
4070 NonlinearFlushCachesCount ?
4071 (float) NonlinearFlushCachesVisitedCount / (float) NonlinearFlushCachesCount : 0.0,
4072 MaxNonlinearFlushCachesVisitedCount,
4073 NonlinearFlushCachesClassCount,
4074 NonlinearFlushCachesClassCount ?
4075 (float) NonlinearFlushCachesVisitedCount / (float) NonlinearFlushCachesClassCount : 0.0);
4076 printf (" ideal %11u %12u %14.1f %10u %13u %12.2f\n",
4077 LinearFlushCachesCount + NonlinearFlushCachesCount,
4078 IdealFlushCachesCount,
4079 LinearFlushCachesCount + NonlinearFlushCachesCount ?
4080 (float) IdealFlushCachesCount / (float) (LinearFlushCachesCount + NonlinearFlushCachesCount) : 0.0,
4081 MaxIdealFlushCachesCount,
4082 LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount,
4083 LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount ?
4084 (float) IdealFlushCachesCount / (float) (LinearFlushCachesVisitedCount + NonlinearFlushCachesClassCount) : 0.0);
4085
4086 PrintCacheHistogram ("\nCache hit histogram:", &CacheHitHistogram[0], CACHE_HISTOGRAM_SIZE);
4087 PrintCacheHistogram ("\nCache miss histogram:", &CacheMissHistogram[0], CACHE_HISTOGRAM_SIZE);
13d88034
A
4088#endif
4089
4090#if 0
41c8faa5
A
4091 printf ("\nLookup chains:");
4092 for (index = 0; index < MAX_CHAIN_SIZE; index += 1)
4093 {
4094 if (chainCount[index] != 0)
4095 printf (" %u:%u", index, chainCount[index]);
4096 }
4097
4098 printf ("\nMiss chains:");
4099 for (index = 0; index < MAX_CHAIN_SIZE; index += 1)
4100 {
4101 if (missChainCount[index] != 0)
4102 printf (" %u:%u", index, missChainCount[index]);
4103 }
4104
4105 printf ("\nTotal memory usage for cache data structures: %lu bytes\n",
4106 totalCacheCount * (sizeof(struct objc_cache) - sizeof(Method)) +
4107 totalSlots * sizeof(Method) +
4108 negativeEntryCount * sizeof(struct objc_method));
13d88034 4109#endif
41c8faa5 4110 }
13d88034
A
4111}
4112
4113/***********************************************************************
41c8faa5
A
4114* checkUniqueness.
4115**********************************************************************/
13d88034 4116void checkUniqueness (SEL s1,
41c8faa5 4117 SEL s2)
13d88034 4118{
41c8faa5
A
4119 if (s1 == s2)
4120 return;
4121
4122 if (s1 && s2 && (strcmp ((const char *) s1, (const char *) s2) == 0))
4123 _objc_inform ("%p != %p but !strcmp (%s, %s)\n", s1, s2, (char *) s1, (char *) s2);
13d88034
A
4124}
4125