2  * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.
 
   4  * @APPLE_LICENSE_HEADER_START@
 
   6  * This file contains Original Code and/or Modifications of Original Code
 
   7  * as defined in and that are subject to the Apple Public Source License
 
   8  * Version 2.0 (the 'License'). You may not use this file except in
 
   9  * compliance with the License. Please obtain a copy of the License at
 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this
 
  13  * The Original Code and all software distributed under the License are
 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 
  18  * Please see the License for the specific language governing rights and
 
  19  * limitations under the License.
 
  21  * @APPLE_LICENSE_HEADER_END@
 
  23 /***********************************************************************
 
  25 *       Copyright 1988-1997, Apple Computer, Inc.
 
  27 **********************************************************************/
 
  30 /***********************************************************************
 
  31  * Lazy method list arrays and method list locking  (2004-10-19)
 
  33  * cls->methodLists may be in one of three forms:
 
  34  * 1. nil: The class has no methods.
 
  35  * 2. non-nil, with CLS_NO_METHOD_ARRAY set: cls->methodLists points 
 
  36  *    to a single method list, which is the class's only method list.
 
  37  * 3. non-nil, with CLS_NO_METHOD_ARRAY clear: cls->methodLists points to 
 
  38  *    an array of method list pointers. The end of the array's block 
 
  39  *    is set to -1. If the actual number of method lists is smaller 
 
  40  *    than that, the rest of the array is nil.
 
  42  * Attaching categories and adding and removing classes may change 
 
  43  * the form of the class list. In addition, individual method lists 
 
  44  * may be reallocated when fixed up.
 
  46  * Classes are initially read as #1 or #2. If a category is attached 
 
  47  * or other methods added, the class is changed to #3. Once in form #3, 
 
  48  * the class is never downgraded to #1 or #2, even if methods are removed.
 
  49  * Classes added with objc_addClass are initially either #1 or #3.
 
  51  * Accessing and manipulating a class's method lists are synchronized, 
 
  52  * to prevent races when one thread restructures the list. However, 
 
  53  * if the class is not yet in use (i.e. not in class_hash), then the 
 
  54  * thread loading the class may access its method lists without locking.
 
  56  * The following functions acquire methodListLock:
 
  57  * class_getInstanceMethod
 
  58  * class_getClassMethod
 
  59  * class_nextMethodList
 
  62  * class_respondsToMethod
 
  63  * _class_lookupMethodAndLoadCache
 
  64  * lookupMethodInClassAndLoadCache
 
  65  * _objc_add_category_flush_caches
 
  67  * The following functions don't acquire methodListLock because they 
 
  68  * only access method lists during class load and unload:
 
  69  * _objc_register_category
 
  70  * _resolve_categories_for_class (calls _objc_add_category)
 
  71  * add_class_to_loadable_list
 
  73  * _objc_remove_classes_in_image
 
  75  * The following functions use method lists without holding methodListLock.
 
  76  * The caller must either hold methodListLock, or be loading the class.
 
  77  * _getMethod (called by class_getInstanceMethod, class_getClassMethod, 
 
  78  *   and class_respondsToMethod)
 
  79  * _findMethodInClass (called by _class_lookupMethodAndLoadCache, 
 
  80  *   lookupMethodInClassAndLoadCache, _getMethod)
 
  81  * _findMethodInList (called by _findMethodInClass)
 
  82  * nextMethodList (called by _findMethodInClass and class_nextMethodList
 
  83  * fixupSelectorsInMethodList (called by nextMethodList)
 
  84  * _objc_add_category (called by _objc_add_category_flush_caches, 
 
  85  *   resolve_categories_for_class and _objc_register_category)
 
  86  * _objc_insertMethods (called by class_addMethods and _objc_add_category)
 
  87  * _objc_removeMethods (called by class_removeMethods)
 
  88  * _objcTweakMethodListPointerForClass (called by _objc_insertMethods)
 
  89  * get_base_method_list (called by add_class_to_loadable_list)
 
  90  * lookupNamedMethodInMethodList (called by add_class_to_loadable_list)
 
  91  ***********************************************************************/
 
  93 /***********************************************************************
 
  94  * Thread-safety of class info bits  (2004-10-19)
 
  96  * Some class info bits are used to store mutable runtime state. 
 
  97  * Modifications of the info bits at particular times need to be 
 
  98  * synchronized to prevent races.
 
 100  * Three thread-safe modification functions are provided:
 
 101  * cls->setInfo()     // atomically sets some bits
 
 102  * cls->clearInfo()   // atomically clears some bits
 
 103  * cls->changeInfo()  // atomically sets some bits and clears others
 
 104  * These replace CLS_SETINFO() for the multithreaded cases.
 
 106  * Three modification windows are defined:
 
 108  * - class construction or image load (before +load) in one thread
 
 109  * - multi-threaded messaging and method caches
 
 111  * Info bit modification at compile time and class construction do not 
 
 112  *   need to be locked, because only one thread is manipulating the class.
 
 113  * Info bit modification during messaging needs to be locked, because 
 
 114  *   there may be other threads simultaneously messaging or otherwise 
 
 115  *   manipulating the class.
 
 117  * Modification windows for each flag:
 
 119  * CLS_CLASS: compile-time and class load
 
 120  * CLS_META: compile-time and class load
 
 121  * CLS_INITIALIZED: +initialize
 
 122  * CLS_POSING: messaging
 
 123  * CLS_MAPPED: compile-time
 
 124  * CLS_FLUSH_CACHE: class load and messaging
 
 125  * CLS_GROW_CACHE: messaging
 
 126  * CLS_NEED_BIND: unused
 
 127  * CLS_METHOD_ARRAY: unused
 
 128  * CLS_JAVA_HYBRID: JavaBridge only
 
 129  * CLS_JAVA_CLASS: JavaBridge only
 
 130  * CLS_INITIALIZING: messaging
 
 131  * CLS_FROM_BUNDLE: class load
 
 132  * CLS_HAS_CXX_STRUCTORS: compile-time and class load
 
 133  * CLS_NO_METHOD_ARRAY: class load and messaging
 
 134  * CLS_HAS_LOAD_METHOD: class load
 
 136  * CLS_INITIALIZED and CLS_INITIALIZING have additional thread-safety 
 
 137  * constraints to support thread-safe +initialize. See "Thread safety 
 
 138  * during class initialization" for details.
 
 140  * CLS_JAVA_HYBRID and CLS_JAVA_CLASS are set immediately after JavaBridge 
 
 141  * calls objc_addClass(). The JavaBridge does not use an atomic update, 
 
 142  * but the modification counts as "class construction" unless some other 
 
 143  * thread quickly finds the class via the class list. This race is 
 
 144  * small and unlikely in well-behaved code.
 
 146  * Most info bits that may be modified during messaging are also never 
 
 147  * read without a lock. There is no general read lock for the info bits.
 
 148  * CLS_INITIALIZED: classInitLock
 
 149  * CLS_FLUSH_CACHE: cacheUpdateLock
 
 150  * CLS_GROW_CACHE: cacheUpdateLock
 
 151  * CLS_NO_METHOD_ARRAY: methodListLock
 
 152  * CLS_INITIALIZING: classInitLock
 
 153  ***********************************************************************/
 
 155 /***********************************************************************
 
 157 **********************************************************************/
 
 159 #include "objc-private.h"
 
 160 #include "objc-abi.h"
 
 161 #include <objc/message.h>
 
 163 #include <os/linker_set.h>
 
 166 /***********************************************************************
 
 167 * Information about multi-thread support:
 
 169 * Since we do not lock many operations which walk the superclass, method
 
 170 * and ivar chains, these chains must remain intact once a class is published
 
 171 * by inserting it into the class hashtable.  All modifications must be
 
 172 * atomic so that someone walking these chains will always geta valid
 
 174 ***********************************************************************/
 
 178 /***********************************************************************
 
 180 * Locking: None. If you add locking, tell gdb (rdar://7516456).
 
 181 **********************************************************************/
 
 182 Class object_getClass(id obj)
 
 184     if (obj) return obj->getIsa();
 
 189 /***********************************************************************
 
 191 **********************************************************************/
 
 192 Class object_setClass(id obj, Class cls)
 
 194     if (!obj) return nil;
 
 196     // Prevent a deadlock between the weak reference machinery
 
 197     // and the +initialize machinery by ensuring that no 
 
 198     // weakly-referenced object has an un-+initialized isa.
 
 199     // Unresolved future classes are not so protected.
 
 200     if (!cls->isFuture()  &&  !cls->isInitialized()) {
 
 201         // use lookUpImpOrNilTryCache to indirectly provoke +initialize
 
 202         // to avoid duplicating the code to actually send +initialize
 
 203         lookUpImpOrNilTryCache(nil, @selector(initialize), cls, LOOKUP_INITIALIZE);
 
 206     return obj->changeIsa(cls);
 
 210 /***********************************************************************
 
 212 **********************************************************************/
 
 213 BOOL object_isClass(id obj)
 
 216     return obj->isClass();
 
 220 /***********************************************************************
 
 221 * object_getClassName.
 
 222 **********************************************************************/
 
 223 const char *object_getClassName(id obj)
 
 225     return class_getName(obj ? obj->getIsa() : nil);
 
 229 /***********************************************************************
 
 230  * object_getMethodImplementation.
 
 231  **********************************************************************/
 
 232 IMP object_getMethodImplementation(id obj, SEL name)
 
 234     Class cls = (obj ? obj->getIsa() : nil);
 
 235     return class_getMethodImplementation(cls, name);
 
 239 /***********************************************************************
 
 240  * object_getMethodImplementation_stret.
 
 241  **********************************************************************/
 
 243 IMP object_getMethodImplementation_stret(id obj, SEL name)
 
 245     Class cls = (obj ? obj->getIsa() : nil);
 
 246     return class_getMethodImplementation_stret(cls, name);
 
 251 static bool isScanned(ptrdiff_t ivar_offset, const uint8_t *layout) 
 
 253     if (!layout) return NO;
 
 255     ptrdiff_t index = 0, ivar_index = ivar_offset / sizeof(void*);
 
 257     while ((byte = *layout++)) {
 
 258         unsigned skips = (byte >> 4);
 
 259         unsigned scans = (byte & 0x0F);
 
 261         if (index > ivar_index) return NO;
 
 263         if (index > ivar_index) return YES;
 
 269 /***********************************************************************
 
 271 * Given an object and an ivar in it, look up some data about that ivar:
 
 273 * - its memory management behavior
 
 274 * The ivar is assumed to be word-aligned and of of object type.
 
 275 **********************************************************************/
 
 277 _class_lookUpIvar(Class cls, Ivar ivar, ptrdiff_t& ivarOffset, 
 
 278                   objc_ivar_memory_management_t& memoryManagement)
 
 280     ivarOffset = ivar_getOffset(ivar);
 
 282     // Look for ARC variables and ARC-style weak.
 
 284     // Preflight the hasAutomaticIvars check
 
 285     // because _class_getClassForIvar() may need to take locks.
 
 286     bool hasAutomaticIvars = NO;
 
 287     for (Class c = cls; c; c = c->getSuperclass()) {
 
 288         if (c->hasAutomaticIvars()) {
 
 289             hasAutomaticIvars = YES;
 
 294     if (hasAutomaticIvars) {
 
 295         Class ivarCls = _class_getClassForIvar(cls, ivar);
 
 296         if (ivarCls->hasAutomaticIvars()) {
 
 297             // ARC layout bitmaps encode the class's own ivars only.
 
 298             // Use alignedInstanceStart() because unaligned bytes at the start
 
 299             // of this class's ivars are not represented in the layout bitmap.
 
 300             ptrdiff_t localOffset = 
 
 301                 ivarOffset - ivarCls->alignedInstanceStart();
 
 303             if (isScanned(localOffset, class_getIvarLayout(ivarCls))) {
 
 304                 memoryManagement = objc_ivar_memoryStrong;
 
 308             if (isScanned(localOffset, class_getWeakIvarLayout(ivarCls))) {
 
 309                 memoryManagement = objc_ivar_memoryWeak;
 
 313             // Unretained is only for true ARC classes.
 
 314             if (ivarCls->isARC()) {
 
 315                 memoryManagement = objc_ivar_memoryUnretained;
 
 321     memoryManagement = objc_ivar_memoryUnknown;
 
 325 /***********************************************************************
 
 326 * _class_getIvarMemoryManagement
 
 327 * SPI for KVO and others to decide what memory management to use 
 
 328 * when setting instance variables directly.
 
 329 **********************************************************************/
 
 330 objc_ivar_memory_management_t 
 
 331 _class_getIvarMemoryManagement(Class cls, Ivar ivar)
 
 334     objc_ivar_memory_management_t memoryManagement;
 
 335     _class_lookUpIvar(cls, ivar, offset, memoryManagement);
 
 336     return memoryManagement;
 
 341 void _object_setIvar(id obj, Ivar ivar, id value, bool assumeStrong)
 
 343     if (!ivar || obj->isTaggedPointerOrNil()) return;
 
 346     objc_ivar_memory_management_t memoryManagement;
 
 347     _class_lookUpIvar(obj->ISA(), ivar, offset, memoryManagement);
 
 349     if (memoryManagement == objc_ivar_memoryUnknown) {
 
 350         if (assumeStrong) memoryManagement = objc_ivar_memoryStrong;
 
 351         else memoryManagement = objc_ivar_memoryUnretained;
 
 354     id *location = (id *)((char *)obj + offset);
 
 356     switch (memoryManagement) {
 
 357     case objc_ivar_memoryWeak:       objc_storeWeak(location, value); break;
 
 358     case objc_ivar_memoryStrong:     objc_storeStrong(location, value); break;
 
 359     case objc_ivar_memoryUnretained: *location = value; break;
 
 360     case objc_ivar_memoryUnknown:    _objc_fatal("impossible");
 
 364 void object_setIvar(id obj, Ivar ivar, id value)
 
 366     return _object_setIvar(obj, ivar, value, false /*not strong default*/);
 
 369 void object_setIvarWithStrongDefault(id obj, Ivar ivar, id value)
 
 371     return _object_setIvar(obj, ivar, value, true /*strong default*/);
 
 375 id object_getIvar(id obj, Ivar ivar)
 
 377     if (!ivar || obj->isTaggedPointerOrNil()) return nil;
 
 380     objc_ivar_memory_management_t memoryManagement;
 
 381     _class_lookUpIvar(obj->ISA(), ivar, offset, memoryManagement);
 
 383     id *location = (id *)((char *)obj + offset);
 
 385     if (memoryManagement == objc_ivar_memoryWeak) {
 
 386         return objc_loadWeak(location);
 
 394 Ivar _object_setInstanceVariable(id obj, const char *name, void *value, 
 
 399     if (name && !obj->isTaggedPointerOrNil()) {
 
 400         if ((ivar = _class_getVariable(obj->ISA(), name))) {
 
 401             _object_setIvar(obj, ivar, (id)value, assumeStrong);
 
 407 Ivar object_setInstanceVariable(id obj, const char *name, void *value)
 
 409     return _object_setInstanceVariable(obj, name, value, false);
 
 412 Ivar object_setInstanceVariableWithStrongDefault(id obj, const char *name, 
 
 415     return _object_setInstanceVariable(obj, name, value, true);
 
 419 Ivar object_getInstanceVariable(id obj, const char *name, void **value)
 
 421     if (name && !obj->isTaggedPointerOrNil()) {
 
 423         if ((ivar = class_getInstanceVariable(obj->ISA(), name))) {
 
 424             if (value) *value = (void *)object_getIvar(obj, ivar);
 
 428     if (value) *value = nil;
 
 433 /***********************************************************************
 
 434 * object_cxxDestructFromClass.
 
 435 * Call C++ destructors on obj, starting with cls's 
 
 436 *   dtor method (if any) followed by superclasses' dtors (if any), 
 
 437 *   stopping at cls's dtor (if any).
 
 438 * Uses methodListLock and cacheUpdateLock. The caller must hold neither.
 
 439 **********************************************************************/
 
 440 static void object_cxxDestructFromClass(id obj, Class cls)
 
 444     // Call cls's dtor first, then superclasses's dtors.
 
 446     for ( ; cls; cls = cls->getSuperclass()) {
 
 447         if (!cls->hasCxxDtor()) return; 
 
 449             lookupMethodInClassAndLoadCache(cls, SEL_cxx_destruct);
 
 450         if (dtor != (void(*)(id))_objc_msgForward_impcache) {
 
 452                 _objc_inform("CXX: calling C++ destructors for class %s", 
 
 453                              cls->nameForLogging());
 
 461 /***********************************************************************
 
 462 * object_cxxDestruct.
 
 463 * Call C++ destructors on obj, if any.
 
 464 * Uses methodListLock and cacheUpdateLock. The caller must hold neither.
 
 465 **********************************************************************/
 
 466 void object_cxxDestruct(id obj)
 
 468     if (obj->isTaggedPointerOrNil()) return;
 
 469     object_cxxDestructFromClass(obj, obj->ISA());
 
 473 /***********************************************************************
 
 474 * object_cxxConstructFromClass.
 
 475 * Recursively call C++ constructors on obj, starting with base class's 
 
 476 *   ctor method (if any) followed by subclasses' ctors (if any), stopping 
 
 477 *   at cls's ctor (if any).
 
 478 * Does not check cls->hasCxxCtor(). The caller should preflight that.
 
 479 * Returns self if construction succeeded.
 
 480 * Returns nil if some constructor threw an exception. The exception is 
 
 481 *   caught and discarded. Any partial construction is destructed.
 
 482 * Uses methodListLock and cacheUpdateLock. The caller must hold neither.
 
 484 * .cxx_construct returns id. This really means:
 
 485 * return self: construction succeeded
 
 486 * return nil:  construction failed because a C++ constructor threw an exception
 
 487 **********************************************************************/
 
 489 object_cxxConstructFromClass(id obj, Class cls, int flags)
 
 491     ASSERT(cls->hasCxxCtor());  // required for performance, not correctness
 
 496     supercls = cls->getSuperclass();
 
 498     // Call superclasses' ctors first, if any.
 
 499     if (supercls  &&  supercls->hasCxxCtor()) {
 
 500         bool ok = object_cxxConstructFromClass(obj, supercls, flags);
 
 501         if (slowpath(!ok)) return nil;  // some superclass's ctor failed - give up
 
 504     // Find this class's ctor, if any.
 
 505     ctor = (id(*)(id))lookupMethodInClassAndLoadCache(cls, SEL_cxx_construct);
 
 506     if (ctor == (id(*)(id))_objc_msgForward_impcache) return obj;  // no ctor - ok
 
 508     // Call this class's ctor.
 
 510         _objc_inform("CXX: calling C++ constructors for class %s", 
 
 511                      cls->nameForLogging());
 
 513     if (fastpath((*ctor)(obj))) return obj;  // ctor called and succeeded - ok
 
 515     supercls = cls->getSuperclass(); // this reload avoids a spill on the stack
 
 517     // This class's ctor was called and failed.
 
 518     // Call superclasses's dtors to clean up.
 
 519     if (supercls) object_cxxDestructFromClass(obj, supercls);
 
 520     if (flags & OBJECT_CONSTRUCT_FREE_ONFAILURE) free(obj);
 
 521     if (flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
 
 522         return _objc_callBadAllocHandler(cls);
 
 528 /***********************************************************************
 
 530 * Fix up ARC strong and ARC-style weak variables 
 
 531 * after oldObject was memcpy'd to newObject.
 
 532 **********************************************************************/
 
 533 void fixupCopiedIvars(id newObject, id oldObject)
 
 535     for (Class cls = oldObject->ISA(); cls; cls = cls->getSuperclass()) {
 
 536         if (cls->hasAutomaticIvars()) {
 
 537             // Use alignedInstanceStart() because unaligned bytes at the start
 
 538             // of this class's ivars are not represented in the layout bitmap.
 
 539             size_t instanceStart = cls->alignedInstanceStart();
 
 541             const uint8_t *strongLayout = class_getIvarLayout(cls);
 
 543                 id *newPtr = (id *)((char*)newObject + instanceStart);
 
 545                 while ((byte = *strongLayout++)) {
 
 546                     unsigned skips = (byte >> 4);
 
 547                     unsigned scans = (byte & 0x0F);
 
 550                         // ensure strong references are properly retained.
 
 551                         id value = *newPtr++;
 
 552                         if (value) objc_retain(value);
 
 557             const uint8_t *weakLayout = class_getWeakIvarLayout(cls);
 
 558             // fix up weak references if any.
 
 560                 id *newPtr = (id *)((char*)newObject + instanceStart), *oldPtr = (id *)((char*)oldObject + instanceStart);
 
 562                 while ((byte = *weakLayout++)) {
 
 563                     unsigned skips = (byte >> 4);
 
 564                     unsigned weaks = (byte & 0x0F);
 
 565                     newPtr += skips, oldPtr += skips;
 
 567                         objc_copyWeak(newPtr, oldPtr);
 
 578 /***********************************************************************
 
 579 * class_getClassMethod.  Return the class method for the specified
 
 580 * class and selector.
 
 581 **********************************************************************/
 
 582 Method class_getClassMethod(Class cls, SEL sel)
 
 584     if (!cls  ||  !sel) return nil;
 
 586     return class_getInstanceMethod(cls->getMeta(), sel);
 
 590 /***********************************************************************
 
 591 * class_getInstanceVariable.  Return the named instance variable.
 
 592 **********************************************************************/
 
 593 Ivar class_getInstanceVariable(Class cls, const char *name)
 
 595     if (!cls  ||  !name) return nil;
 
 597     return _class_getVariable(cls, name);
 
 601 /***********************************************************************
 
 602 * class_getClassVariable.  Return the named class variable.
 
 603 **********************************************************************/
 
 604 Ivar class_getClassVariable(Class cls, const char *name)
 
 606     if (!cls) return nil;
 
 608     return class_getInstanceVariable(cls->ISA(), name);
 
 612 /***********************************************************************
 
 613 * gdb_objc_class_changed
 
 614 * Tell gdb that a class changed. Currently used for OBJC2 ivar layouts only
 
 615 * Does nothing; gdb sets a breakpoint on it.
 
 616 **********************************************************************/
 
 618     void gdb_objc_class_changed(Class cls, unsigned long changes, const char *classname)
 
 622 /***********************************************************************
 
 623 * class_respondsToSelector.
 
 624 **********************************************************************/
 
 625 BOOL class_respondsToMethod(Class cls, SEL sel)
 
 627     OBJC_WARN_DEPRECATED;
 
 629     return class_respondsToSelector(cls, sel);
 
 633 BOOL class_respondsToSelector(Class cls, SEL sel)
 
 635     return class_respondsToSelector_inst(nil, sel, cls);
 
 639 // inst is an instance of cls or a subclass thereof, or nil if none is known.
 
 640 // Non-nil inst is faster in some cases. See lookUpImpOrForward() for details.
 
 641 NEVER_INLINE __attribute__((flatten)) BOOL
 
 642 class_respondsToSelector_inst(id inst, SEL sel, Class cls)
 
 644     // Avoids +initialize because it historically did so.
 
 645     // We're not returning a callable IMP anyway.
 
 646     return sel && cls && lookUpImpOrNilTryCache(inst, sel, cls, LOOKUP_RESOLVER);
 
 650 /***********************************************************************
 
 651 * class_getMethodImplementation.
 
 652 * Returns the IMP that would be invoked if [obj sel] were sent, 
 
 653 * where obj is an instance of class cls.
 
 654 **********************************************************************/
 
 655 IMP class_lookupMethod(Class cls, SEL sel)
 
 657     OBJC_WARN_DEPRECATED;
 
 659     // No one responds to zero!
 
 661         __objc_error(cls, "invalid selector (null)");
 
 664     return class_getMethodImplementation(cls, sel);
 
 667 __attribute__((flatten))
 
 668 IMP class_getMethodImplementation(Class cls, SEL sel)
 
 672     if (!cls  ||  !sel) return nil;
 
 674     lockdebug_assert_no_locks_locked_except({ &loadMethodLock });
 
 676     imp = lookUpImpOrNilTryCache(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER);
 
 678     // Translate forwarding function to C-callable external version
 
 680         return _objc_msgForward;
 
 687 IMP class_getMethodImplementation_stret(Class cls, SEL sel)
 
 689     IMP imp = class_getMethodImplementation(cls, sel);
 
 691     // Translate forwarding function to struct-returning version
 
 692     if (imp == (IMP)&_objc_msgForward /* not _internal! */) {
 
 693         return (IMP)&_objc_msgForward_stret;
 
 700 /***********************************************************************
 
 701 * instrumentObjcMessageSends
 
 702 **********************************************************************/
 
 703 // Define this everywhere even if it isn't used to simplify fork() safety code.
 
 704 spinlock_t objcMsgLogLock;
 
 706 #if !SUPPORT_MESSAGE_LOGGING
 
 708 void    instrumentObjcMessageSends(BOOL flag)
 
 714 bool objcMsgLogEnabled = false;
 
 715 static int objcMsgLogFD = -1;
 
 717 bool logMessageSend(bool isClassMethod,
 
 718                     const char *objectsClass,
 
 719                     const char *implementingClass,
 
 724     // Create/open the log file
 
 725     if (objcMsgLogFD == (-1))
 
 727         snprintf (buf, sizeof(buf), "/tmp/msgSends-%d", (int) getpid ());
 
 728         objcMsgLogFD = secure_open (buf, O_WRONLY | O_CREAT, geteuid());
 
 729         if (objcMsgLogFD < 0) {
 
 730             // no log file - disable logging
 
 731             objcMsgLogEnabled = false;
 
 737     // Make the log entry
 
 738     snprintf(buf, sizeof(buf), "%c %s %s %s\n",
 
 739             isClassMethod ? '+' : '-',
 
 742             sel_getName(selector));
 
 744     objcMsgLogLock.lock();
 
 745     write (objcMsgLogFD, buf, strlen(buf));
 
 746     objcMsgLogLock.unlock();
 
 748     // Tell caller to not cache the method
 
 752 void instrumentObjcMessageSends(BOOL flag)
 
 757     if (objcMsgLogEnabled == enable)
 
 760     // If enabling, flush all method caches so we get some traces
 
 762         _objc_flush_caches(Nil);
 
 765     if (objcMsgLogFD != -1)
 
 766         fsync (objcMsgLogFD);
 
 768     objcMsgLogEnabled = enable;
 
 771 // SUPPORT_MESSAGE_LOGGING
 
 775 Class _calloc_class(size_t size)
 
 777     return (Class) calloc(1, size);
 
 780 Class class_getSuperclass(Class cls)
 
 782     if (!cls) return nil;
 
 783     return cls->getSuperclass();
 
 786 BOOL class_isMetaClass(Class cls)
 
 789     return cls->isMetaClass();
 
 793 size_t class_getInstanceSize(Class cls)
 
 796     return cls->alignedInstanceSize();
 
 800 /***********************************************************************
 
 801 * method_getNumberOfArguments.
 
 802 **********************************************************************/
 
 803 unsigned int method_getNumberOfArguments(Method m)
 
 806     return encoding_getNumberOfArguments(method_getTypeEncoding(m));
 
 810 void method_getReturnType(Method m, char *dst, size_t dst_len)
 
 812     encoding_getReturnType(method_getTypeEncoding(m), dst, dst_len);
 
 816 char * method_copyReturnType(Method m)
 
 818     return encoding_copyReturnType(method_getTypeEncoding(m));
 
 822 void method_getArgumentType(Method m, unsigned int index, 
 
 823                             char *dst, size_t dst_len)
 
 825     encoding_getArgumentType(method_getTypeEncoding(m),
 
 826                              index, dst, dst_len);
 
 830 char * method_copyArgumentType(Method m, unsigned int index)
 
 832     return encoding_copyArgumentType(method_getTypeEncoding(m), index);
 
 835 /***********************************************************************
 
 836 * _class_createInstancesFromZone
 
 837 * Batch-allocating version of _class_createInstanceFromZone.
 
 838 * Attempts to allocate num_requested objects, each with extraBytes.
 
 839 * Returns the number of allocated objects (possibly zero), with 
 
 840 * the allocated pointers in *results.
 
 841 **********************************************************************/
 
 843 _class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone, 
 
 844                                id *results, unsigned num_requested)
 
 846     unsigned num_allocated;
 
 849     size_t size = cls->instanceSize(extraBytes);
 
 852         malloc_zone_batch_malloc((malloc_zone_t *)(zone ? zone : malloc_default_zone()), 
 
 853                                  size, (void**)results, num_requested);
 
 854     for (unsigned i = 0; i < num_allocated; i++) {
 
 855         bzero(results[i], size);
 
 858     // Construct each object, and delete any that fail construction.
 
 861     bool ctor = cls->hasCxxCtor();
 
 862     for (unsigned i = 0; i < num_allocated; i++) {
 
 864         obj->initIsa(cls);    // fixme allow nonpointer
 
 866             obj = object_cxxConstructFromClass(obj, cls,
 
 867                                                OBJECT_CONSTRUCT_FREE_ONFAILURE);
 
 870             results[i-shift] = obj;
 
 876     return num_allocated - shift;    
 
 880 /***********************************************************************
 
 881 * inform_duplicate. Complain about duplicate class implementations.
 
 882 **********************************************************************/
 
 884 inform_duplicate(const char *name, Class oldCls, Class newCls)
 
 887     (DebugDuplicateClasses ? _objc_fatal : _objc_inform)
 
 888         ("Class %s is implemented in two different images.", name);
 
 890     const header_info *oldHeader = _headerForClass(oldCls);
 
 891     const header_info *newHeader = _headerForClass(newCls);
 
 892     const char *oldName = oldHeader ? oldHeader->fname() : "??";
 
 893     const char *newName = newHeader ? newHeader->fname() : "??";
 
 894     const objc_duplicate_class **_dupi = NULL;
 
 896     LINKER_SET_FOREACH(_dupi, const objc_duplicate_class **, "__objc_dupclass") {
 
 897         const objc_duplicate_class *dupi = *_dupi;
 
 899         if (strcmp(dupi->name, name) == 0) {
 
 904     (DebugDuplicateClasses ? _objc_fatal : _objc_inform)
 
 905         ("Class %s is implemented in both %s (%p) and %s (%p). "
 
 906          "One of the two will be used. Which one is undefined.",
 
 907          name, oldName, oldCls, newName, newCls);
 
 913 copyPropertyAttributeString(const objc_property_attribute_t *attrs,
 
 918     if (count == 0) return strdup("");
 
 921     // debug build: sanitize input
 
 922     for (i = 0; i < count; i++) {
 
 923         ASSERT(attrs[i].name);
 
 924         ASSERT(strlen(attrs[i].name) > 0);
 
 925         ASSERT(! strchr(attrs[i].name, ','));
 
 926         ASSERT(! strchr(attrs[i].name, '"'));
 
 927         if (attrs[i].value) ASSERT(! strchr(attrs[i].value, ','));
 
 932     for (i = 0; i < count; i++) {
 
 933         if (attrs[i].value) {
 
 934             size_t namelen = strlen(attrs[i].name);
 
 935             if (namelen > 1) namelen += 2;  // long names get quoted
 
 936             len += namelen + strlen(attrs[i].value) + 1;
 
 940     result = (char *)malloc(len + 1);
 
 942     for (i = 0; i < count; i++) {
 
 943         if (attrs[i].value) {
 
 944             size_t namelen = strlen(attrs[i].name);
 
 946                 s += sprintf(s, "\"%s\"%s,", attrs[i].name, attrs[i].value);
 
 948                 s += sprintf(s, "%s%s,", attrs[i].name, attrs[i].value);
 
 953     // remove trailing ',' if any
 
 954     if (s > result) s[-1] = '\0';
 
 960   Property attribute string format:
 
 962   - Comma-separated name-value pairs. 
 
 963   - Name and value may not contain ,
 
 964   - Name may not contain "
 
 966   - Name is single char, value follows
 
 967   - OR Name is double-quoted string of 2+ chars, value follows
 
 971     attribute-string: name-value-pair (',' name-value-pair)*
 
 972     name-value-pair:  unquoted-name optional-value
 
 973     name-value-pair:  quoted-name optional-value
 
 975     quoted-name:      '"' [^",]{2,} '"'
 
 976     optional-value:   [^,]*
 
 980 iteratePropertyAttributes(const char *attrs, 
 
 981                           bool (*fn)(unsigned int index, 
 
 982                                      void *ctx1, void *ctx2, 
 
 983                                      const char *name, size_t nlen, 
 
 984                                      const char *value, size_t vlen), 
 
 985                           void *ctx1, void *ctx2)
 
 987     if (!attrs) return 0;
 
 990     const char *attrsend = attrs + strlen(attrs);
 
 992     unsigned int attrcount = 0;
 
 995         // Find the next comma-separated attribute
 
 996         const char *start = attrs;
 
 997         const char *end = start + strcspn(attrs, ",");
 
 999         // Move attrs past this attribute and the comma (if any)
 
1000         attrs = *end ? end+1 : end;
 
1002         assert(attrs <= attrsend);
 
1003         assert(start <= attrsend);
 
1004         assert(end <= attrsend);
 
1006         // Skip empty attribute
 
1007         if (start == end) continue;
 
1009         // Process one non-empty comma-free attribute [start,end)
 
1010         const char *nameStart;
 
1011         const char *nameEnd;
 
1013         ASSERT(start < end);
 
1015         if (*start != '\"') {
 
1016             // single-char short name
 
1022             // double-quoted long name
 
1023             nameStart = start+1;
 
1024             nameEnd = nameStart + strcspn(nameStart, "\",");
 
1025             start++;                       // leading quote
 
1026             start += nameEnd - nameStart;  // name
 
1027             if (*start == '\"') start++;   // trailing quote, if any
 
1030         // Process one possibly-empty comma-free attribute value [start,end)
 
1031         const char *valueStart;
 
1032         const char *valueEnd;
 
1034         ASSERT(start <= end);
 
1039         bool more = (*fn)(attrcount, ctx1, ctx2, 
 
1040                           nameStart, nameEnd-nameStart, 
 
1041                           valueStart, valueEnd-valueStart);
 
1051 copyOneAttribute(unsigned int index, void *ctxa, void *ctxs, 
 
1052                  const char *name, size_t nlen, const char *value, size_t vlen)
 
1054     objc_property_attribute_t **ap = (objc_property_attribute_t**)ctxa;
 
1055     char **sp = (char **)ctxs;
 
1057     objc_property_attribute_t *a = *ap;
 
1061     memcpy(s, name, nlen);
 
1066     memcpy(s, value, vlen);
 
1079 objc_property_attribute_t *
 
1080 copyPropertyAttributeList(const char *attrs, unsigned int *outCount)
 
1083         if (outCount) *outCount = 0;
 
1088     //   number of commas plus 1 for the attributes (upper bound)
 
1089     //   plus another attribute for the attribute array terminator
 
1090     //   plus strlen(attrs) for name/value string data (upper bound)
 
1091     //   plus count*2 for the name/value string terminators (upper bound)
 
1092     unsigned int attrcount = 1;
 
1094     for (s = attrs; s && *s; s++) {
 
1095         if (*s == ',') attrcount++;
 
1099         attrcount * sizeof(objc_property_attribute_t) + 
 
1100         sizeof(objc_property_attribute_t) + 
 
1103     objc_property_attribute_t *result = (objc_property_attribute_t *) 
 
1106     objc_property_attribute_t *ra = result;
 
1107     char *rs = (char *)(ra+attrcount+1);
 
1109     attrcount = iteratePropertyAttributes(attrs, copyOneAttribute, &ra, &rs);
 
1111     ASSERT((uint8_t *)(ra+1) <= (uint8_t *)result+size);
 
1112     ASSERT((uint8_t *)rs <= (uint8_t *)result+size);
 
1114     if (attrcount == 0) {
 
1119     if (outCount) *outCount = attrcount;
 
1125 findOneAttribute(unsigned int index, void *ctxa, void *ctxs, 
 
1126                  const char *name, size_t nlen, const char *value, size_t vlen)
 
1128     const char *query = (char *)ctxa;
 
1129     char **resultp = (char **)ctxs;
 
1131     if (strlen(query) == nlen  &&  0 == strncmp(name, query, nlen)) {
 
1132         char *result = (char *)calloc(vlen+1, 1);
 
1133         memcpy(result, value, vlen);
 
1134         result[vlen] = '\0';
 
1142 char *copyPropertyAttributeValue(const char *attrs, const char *name)
 
1146     iteratePropertyAttributes(attrs, findOneAttribute, (void*)name, &result);