/** Implementation of NSObject for GNUStep Copyright (C) 1994-2017 Free Software Foundation, Inc. Written by: Andrew Kachites McCallum Date: August 1994 This file is part of the GNUstep Base Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110 USA. NSObject class reference $Date$ $Revision$ */ /* On some versions of mingw we need to work around bad function declarations * by defining them away and doing the declarations ourself later. */ #ifndef _WIN64 #define InterlockedIncrement BadInterlockedIncrement #define InterlockedDecrement BadInterlockedDecrement #endif #import "common.h" #include #import "Foundation/NSMethodSignature.h" #import "Foundation/NSInvocation.h" #import "Foundation/NSLock.h" #import "Foundation/NSAutoreleasePool.h" #import "Foundation/NSArray.h" #import "Foundation/NSException.h" #import "Foundation/NSHashTable.h" #import "Foundation/NSPortCoder.h" #import "Foundation/NSDistantObject.h" #import "Foundation/NSThread.h" #import "Foundation/NSNotification.h" #import "Foundation/NSMapTable.h" #import "Foundation/NSUserDefaults.h" #import "GNUstepBase/GSLocale.h" #ifdef HAVE_LOCALE_H #include #endif #ifdef HAVE_MALLOC_H #include #endif #import "GSPThread.h" #if defined(HAVE_SYS_SIGNAL_H) # include #elif defined(HAVE_SIGNAL_H) # include #endif #if __GNUC__ >= 4 #if defined(__FreeBSD__) #include #endif #endif // __GNUC__ #define IN_NSOBJECT_M 1 #import "GSPrivate.h" #ifdef __GNUSTEP_RUNTIME__ #include #include #ifdef OBJC_CAP_ARC #include #endif #endif /* platforms which do not support weak */ #if (__GNUC__ == 3) && defined (__WIN32) #define WEAK_ATTRIBUTE #undef SUPPORT_WEAK #else /* all platforms which support weak */ #define WEAK_ATTRIBUTE __attribute__((weak)) #define SUPPORT_WEAK 1 #endif /* When this is `YES', every call to release/autorelease, checks to make sure isn't being set up to release itself too many times. This does not need mutex protection. */ static BOOL double_release_check_enabled = NO; /* The Class responsible for handling autorelease's. This does not need mutex protection, since it is simply a pointer that gets read and set. */ static id autorelease_class = nil; static SEL autorelease_sel; static IMP autorelease_imp; static SEL finalize_sel; static IMP finalize_imp; static Class NSConstantStringClass; @class NSDataMalloc; @class NSMutableDataMalloc; GS_ROOT_CLASS @interface NSZombie { Class isa; } - (Class) class; - (void) forwardInvocation: (NSInvocation*)anInvocation; - (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector; @end @interface GSContentAccessingProxy : NSProxy { NSObject *object; } - (id) initWithObject: (id)anObject; @end /* allocationLock is needed when for protecting the map table of zombie * information and if atomic operations are not available. */ static pthread_mutex_t allocationLock = PTHREAD_MUTEX_INITIALIZER; BOOL NSZombieEnabled = NO; BOOL NSDeallocateZombies = NO; @class NSZombie; static Class zombieClass = Nil; static NSMapTable *zombieMap = 0; #ifndef OBJC_CAP_ARC static void GSMakeZombie(NSObject *o, Class c) { object_setClass(o, zombieClass); if (0 != zombieMap) { pthread_mutex_lock(&allocationLock); if (0 != zombieMap) { NSMapInsert(zombieMap, (void*)o, (void*)c); } pthread_mutex_unlock(&allocationLock); } } #endif static void GSLogZombie(id o, SEL sel) { Class c = 0; if (0 != zombieMap) { pthread_mutex_lock(&allocationLock); if (0 != zombieMap) { c = NSMapGet(zombieMap, (void*)o); } pthread_mutex_unlock(&allocationLock); } if (c == 0) { NSLog(@"*** -[??? %@]: message sent to deallocated instance %p", NSStringFromSelector(sel), o); } else { NSLog(@"*** -[%@ %@]: message sent to deallocated instance %p", c, NSStringFromSelector(sel), o); } if (GSPrivateEnvironmentFlag("CRASH_ON_ZOMBIE", NO) == YES) { abort(); } } /* * Reference count and memory management * Reference counts for object are stored * with the object. * The zone in which an object has been * allocated is stored with the object. */ /* Now, if we are on a platform where we know how to do atomic * read, increment, and decrement, then we define the GSATOMICREAD * macro and macros or functions to increment/decrement. * The presence of the GSATOMICREAD macro is used later to determine * whether to attempt atomic operations or to use locking for the * retain/release mechanism. * The GSAtomicIncrement() and GSAtomicDecrement() functions take a * pointer to a 32bit integer as an argument, increment/decrement the * value pointed to, and return the result. */ #ifdef GSATOMICREAD #undef GSATOMICREAD #endif /* Traditionally, GNUstep has been using a 32bit reference count in front * of the object. The automatic reference counting implementation in * libobjc2 uses an intptr_t instead, so NSObject will only be compatible * with ARC if either of the following apply: * * a) sizeof(intptr_t) == sizeof(int32_t) * b) we can provide atomic operations on pointer sized values, allowing * us to extend the refcount to intptr_t. */ #ifdef GS_ARC_COMPATIBLE #undef GS_ARC_COMPATIBLE #endif #if defined(__llvm__) || (defined(USE_ATOMIC_BUILTINS) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))) /* Use the GCC atomic operations with recent GCC versions */ typedef intptr_t volatile *gsatomic_t; typedef intptr_t gsrefcount_t; #define GSATOMICREAD(X) (*(X)) #define GSAtomicIncrement(X) __sync_add_and_fetch(X, 1) #define GSAtomicDecrement(X) __sync_sub_and_fetch(X, 1) #define GS_ARC_COMPATIBLE 1 #elif defined(_WIN32) /* Set up atomic read, increment and decrement for mswindows */ typedef int32_t volatile *gsatomic_t; typedef int32_t gsrefcount_t; #ifndef _WIN64 #undef InterlockedIncrement #undef InterlockedDecrement LONG WINAPI InterlockedIncrement(LONG volatile *); LONG WINAPI InterlockedDecrement(LONG volatile *); #endif #define GSATOMICREAD(X) (*(X)) #define GSAtomicIncrement(X) InterlockedIncrement(X) #define GSAtomicDecrement(X) InterlockedDecrement(X) #elif defined(__linux__) && (defined(__i386__) || defined(__x86_64__)) /* Set up atomic read, increment and decrement for intel style linux */ typedef int32_t volatile *gsatomic_t; typedef int32_t gsrefcount_t; #define GSATOMICREAD(X) (*(X)) static __inline__ int32_t GSAtomicIncrement(gsatomic_t X) { register int32_t tmp; __asm__ __volatile__ ( "movl $1, %0\n" "lock xaddl %0, %1" :"=r" (tmp), "=m" (*X) :"r" (tmp), "m" (*X) :"memory" ); return tmp + 1; } static __inline__ int32_t GSAtomicDecrement(gsatomic_t X) { register int32_t tmp; __asm__ __volatile__ ( "movl $1, %0\n" "negl %0\n" "lock xaddl %0, %1" :"=r" (tmp), "=m" (*X) :"r" (tmp), "m" (*X) :"memory" ); return tmp - 1; } #elif defined(__PPC__) || defined(__POWERPC__) typedef int32_t volatile *gsatomic_t; typedef int32_t gsrefcount_t; #define GSATOMICREAD(X) (*(X)) static __inline__ int32_t GSAtomicIncrement(gsatomic_t X) { int32_t tmp; __asm__ __volatile__ ( "0:" "lwarx %0,0,%1 \n" "addic %0,%0,1 \n" "stwcx. %0,0,%1 \n" "bne- 0b \n" :"=&r" (tmp) :"r" (X) :"cc", "memory"); return tmp; } static __inline__ int32_t GSAtomicDecrement(gsatomic_t X) { int32_t tmp; __asm__ __volatile__ ( "0:" "lwarx %0,0,%1 \n" "addic %0,%0,-1 \n" "stwcx. %0,0,%1 \n" "bne- 0b \n" :"=&r" (tmp) :"r" (X) :"cc", "memory"); return tmp; } #elif defined(__m68k__) typedef int32_t volatile *gsatomic_t; typedef int32_t gsrefcount_t; #define GSATOMICREAD(X) (*(X)) static __inline__ int32_t GSAtomicIncrement(gsatomic_t X) { __asm__ __volatile__ ( "addq%.l %#1, %0" :"=m" (*X)); return *X; } static __inline__ int32_t GSAtomicDecrement(gsatomic_t X) { __asm__ __volatile__ ( "subq%.l %#1, %0" :"=m" (*X)); return *X; } #elif defined(__mips__) typedef int32_t volatile *gsatomic_t; typedef int32_t gsrefcount_t; #define GSATOMICREAD(X) (*(X)) static __inline__ int32_t GSAtomicIncrement(gsatomic_t X) { int32_t tmp; __asm__ __volatile__ ( #if !defined(__mips64) " .set mips2 \n" #endif "0: ll %0, %1 \n" " addiu %0, 1 \n" " sc %0, %1 \n" " beqz %0, 0b \n" :"=&r" (tmp), "=m" (*X)); return tmp; } static __inline__ int32_t GSAtomicDecrement(gsatomic_t X) { int32_t tmp; __asm__ __volatile__ ( #if !defined(__mips64) " .set mips2 \n" #endif "0: ll %0, %1 \n" " addiu %0, -1 \n" " sc %0, %1 \n" " beqz %0, 0b \n" :"=&r" (tmp), "=m" (*X)); return tmp; } #endif #if !defined(GSATOMICREAD) typedef int gsrefcount_t; // No atomics, use a simple integer /* Having just one allocationLock for all leads to lock contention * if there are lots of threads doing lots of retain/release calls. * To alleviate this, instead of a single * allocationLock for all objects, we divide the object space into * chunks, each with its own lock. The chunk is selected by shifting * off the low-order ALIGNBITS of the object's pointer (these bits * are presumably always zero) and take * the low-order LOCKBITS of the result to index into a table of locks. */ #define LOCKBITS 5 #define LOCKCOUNT (1<> ALIGNBITS) & LOCKMASK); return &allocationLocks[i]; } #endif #ifndef GS_ARC_COMPATIBLE /* * If we haven't previously declared that we can work in fast-ARC mode, * check whether a point is 32bit (4 bytes) wide, which also enables ARC * integration. */ # if __SIZEOF_POINTER__ == 4 # define GS_ARC_COMPATIBLE 1 # endif #endif #if defined(__GNUC__) && __GNUC__ < 4 #define __builtin_offsetof(s, f) (uintptr_t)(&(((s*)0)->f)) #endif #define alignof(type) __builtin_offsetof(struct { const char c; type member; }, member) /* * Define a structure to hold information that is held locally * (before the start) in each object. */ typedef struct obj_layout_unpadded { gsrefcount_t retained; } unp; #define UNP sizeof(unp) /* GCC provides a defined value for the largest alignment required on a * machine, and we must lay objects out to that alignment. * For compilers that don't define it, we try to pick a likely value. */ #ifndef __BIGGEST_ALIGNMENT__ #define __BIGGEST_ALIGNMENT__ (SIZEOF_VOIDP * 2) #endif /* * Now do the REAL version - using the other version to determine * what padding (if any) is required to get the alignment of the * structure correct. */ struct obj_layout { char padding[__BIGGEST_ALIGNMENT__ - ((UNP % __BIGGEST_ALIGNMENT__) ? (UNP % __BIGGEST_ALIGNMENT__) : __BIGGEST_ALIGNMENT__)]; gsrefcount_t retained; }; typedef struct obj_layout *obj; /* * These symbols are provided by newer versions of the GNUstep Objective-C * runtime. When linked against an older version, we will use our internal * versions. */ WEAK_ATTRIBUTE BOOL objc_release_fast_no_destroy_np(id anObject); WEAK_ATTRIBUTE void objc_release_fast_np(id anObject); WEAK_ATTRIBUTE size_t object_getRetainCount_np(id anObject); WEAK_ATTRIBUTE id objc_retain_fast_np(id anObject); static BOOL objc_release_fast_no_destroy_internal(id anObject) { if (double_release_check_enabled) { NSUInteger release_count; NSUInteger retain_count = [anObject retainCount]; release_count = [autorelease_class autoreleaseCountForObject: anObject]; if (release_count >= retain_count) [NSException raise: NSGenericException format: @"Release would release object too many times."]; } { #if defined(GSATOMICREAD) gsrefcount_t result; result = GSAtomicDecrement((gsatomic_t)&(((obj)anObject)[-1].retained)); if (result < 0) { if (result != -1) { [NSException raise: NSInternalInconsistencyException format: @"NSDecrementExtraRefCount() decremented too far"]; } /* The counter has become negative so it must have been zero. * We reset it and return YES ... in a correctly operating * process we know we can safely reset back to zero without * worrying about atomicity, since there can be no other * thread accessing the object (or its reference count would * have been greater than zero) */ (((obj)anObject)[-1].retained) = 0; # ifdef OBJC_CAP_ARC objc_delete_weak_refs(anObject); # endif return YES; } #else /* GSATOMICREAD */ pthread_mutex_t *theLock = GSAllocationLockForObject(anObject); pthread_mutex_lock(theLock); if (((obj)anObject)[-1].retained == 0) { # ifdef OBJC_CAP_ARC objc_delete_weak_refs(anObject); # endif pthread_mutex_unlock(theLock); return YES; } else { ((obj)anObject)[-1].retained--; pthread_mutex_unlock(theLock); return NO; } #endif /* GSATOMICREAD */ } return NO; } static BOOL release_fast_no_destroy(id anObject) { #ifdef SUPPORT_WEAK if (objc_release_fast_no_destroy_np) { return objc_release_fast_no_destroy_np(anObject); } else #endif { return objc_release_fast_no_destroy_internal(anObject); } } static void objc_release_fast_np_internal(id anObject) { if (release_fast_no_destroy(anObject)) { [anObject dealloc]; } } static void release_fast(id anObject) { #ifdef SUPPORT_WEAK if (objc_release_fast_np) { objc_release_fast_np(anObject); } else #endif { objc_release_fast_np_internal(anObject); } } /** * Examines the extra reference count for the object and, if non-zero * decrements it, otherwise leaves it unchanged.
* Returns a flag to say whether the count was zero * (and hence whether the extra reference count was decremented).
*/ inline BOOL NSDecrementExtraRefCountWasZero(id anObject) { return release_fast_no_destroy(anObject); } size_t object_getRetainCount_np_internal(id anObject) { return ((obj)anObject)[-1].retained + 1; } size_t getRetainCount(id anObject) { #ifdef SUPPORT_WEAK if (object_getRetainCount_np) { return object_getRetainCount_np(anObject); } else #endif { return object_getRetainCount_np_internal(anObject); } } /** * Return the extra reference count of anObject (a value in the range * from 0 to the maximum unsigned integer value minus one).
* The retain count for an object is this value plus one. */ inline NSUInteger NSExtraRefCount(id anObject) { return getRetainCount(anObject) - 1; } /** * Increments the extra reference count for anObject.
* The GNUstep version raises an exception if the reference count * would be incremented to too large a value.
* This is used by the [NSObject-retain] method. */ static id objc_retain_fast_np_internal(id anObject) { BOOL tooFar = NO; #if defined(GSATOMICREAD) /* I've seen comments saying that some platforms only support up to * 24 bits in atomic locking, so raise an exception if we try to * go beyond 0xfffffe. */ if (GSAtomicIncrement((gsatomic_t)&(((obj)anObject)[-1].retained)) > 0xfffffe) { tooFar = YES; } #else /* GSATOMICREAD */ pthread_mutex_t *theLock = GSAllocationLockForObject(anObject); pthread_mutex_lock(theLock); if (((obj)anObject)[-1].retained > 0xfffffe) { tooFar = YES; } else { ((obj)anObject)[-1].retained++; } pthread_mutex_unlock(theLock); #endif /* GSATOMICREAD */ if (YES == tooFar) { static NSHashTable *overrun = nil; /* We store this instance in a hash table so that we will only raise * an exception for it once (and can therefore expect to log the instance * as part of the exception derscription without recursion). * NB. The hash table does not retain the object, so the code in the * lock protected region below should be safe anyway. */ [gnustep_global_lock lock]; if (nil == overrun) { overrun = NSCreateHashTable(NSNonRetainedObjectHashCallBacks, 0); } if (0 == NSHashGet(overrun, anObject)) { NSHashInsert(overrun, anObject); } else { tooFar = NO; } [gnustep_global_lock lock]; if (YES == tooFar) { NSString *base; base = [NSString stringWithFormat: @"<%s: %p>", class_getName([anObject class]), anObject]; [NSException raise: NSInternalInconsistencyException format: @"NSIncrementExtraRefCount() asked to increment too far" @" for %@ - %@", base, anObject]; } } return anObject; } static id retain_fast(id anObject) { #ifdef SUPPORT_WEAK if (objc_retain_fast_np) { return objc_retain_fast_np(anObject); } else #endif { return objc_retain_fast_np_internal(anObject); } } /** * Increments the extra reference count for anObject.
* The GNUstep version raises an exception if the reference count * would be incremented to too large a value.
* This is used by the [NSObject-retain] method. */ inline void NSIncrementExtraRefCount(id anObject) { retain_fast(anObject); } #ifndef NDEBUG #define AADD(c, o) GSDebugAllocationAdd(c, o) #define AREM(c, o) GSDebugAllocationRemove(c, o) #else #define AADD(c, o) #define AREM(c, o) #endif #ifndef OBJC_CAP_ARC static SEL cxx_construct, cxx_destruct; /** * Calls the C++ constructors for this object, starting with the ones declared * in aClass. The compiler generates two methods on Objective-C++ classes that * static instances of C++ classes as ivars. These are -.cxx_construct and * -.cxx_destruct. The -.cxx_construct methods must be called in order from * the root class to all subclasses, to ensure that subclass ivars are * initialised after superclass ones. This must be done in reverse for * destruction. * * This function first calls itself recursively on the superclass, to get the * IMP for the constructor function in the superclass. It then compares the * construct method for this class with the one that's already been called, * and calls it if it's new. */ static IMP callCXXConstructors(Class aClass, id anObject) { IMP constructor = 0; if (class_respondsToSelector(aClass, cxx_construct)) { IMP calledConstructor = callCXXConstructors(class_getSuperclass(aClass), anObject); constructor = class_getMethodImplementation(aClass, cxx_construct); if (calledConstructor != constructor) { constructor(anObject, cxx_construct); } } return constructor; } #endif /* * Now do conditional compilation of memory allocation functions * depending on what information (if any) we are storing before * the start of each object. */ // FIXME rewrite object allocation to use class_createInstance when we // are using libobjc2. inline id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone) { id new; #ifdef OBJC_CAP_ARC if ((new = class_createInstance(aClass, extraBytes)) != nil) { AADD(aClass, new); } #else int size; NSCAssert((!class_isMetaClass(aClass)), @"Bad class for new object"); size = class_getInstanceSize(aClass) + extraBytes + sizeof(struct obj_layout); if (zone == 0) { zone = NSDefaultMallocZone(); } new = NSZoneMalloc(zone, size); if (new != nil) { memset (new, 0, size); new = (id)&((obj)new)[1]; object_setClass(new, aClass); AADD(aClass, new); } /* Don't bother doing this in a thread-safe way, because the cost of locking * will be a lot more than the cost of doing the same call in two threads. * The returned selector will persist and the runtime will ensure that both * calls return the same selector, so we don't need to bother doing it * ourselves. */ if (0 == cxx_construct) { cxx_construct = sel_registerName(".cxx_construct"); cxx_destruct = sel_registerName(".cxx_destruct"); } callCXXConstructors(aClass, new); #endif return new; } inline void NSDeallocateObject(id anObject) { Class aClass = object_getClass(anObject); if ((anObject != nil) && !class_isMetaClass(aClass)) { #ifndef OBJC_CAP_ARC obj o = &((obj)anObject)[-1]; NSZone *z = NSZoneFromPointer(o); #endif /* Call the default finalizer to handle C++ destructors. */ (*finalize_imp)(anObject, finalize_sel); AREM(aClass, (id)anObject); if (NSZombieEnabled == YES) { #ifdef OBJC_CAP_ARC if (0 != zombieMap) { pthread_mutex_lock(&allocationLock); if (0 != zombieMap) { NSMapInsert(zombieMap, (void*)anObject, (void*)aClass); } pthread_mutex_unlock(&allocationLock); } if (NSDeallocateZombies == YES) { object_dispose(anObject); } else { object_setClass(anObject, zombieClass); } #else GSMakeZombie(anObject, aClass); if (NSDeallocateZombies == YES) { NSZoneFree(z, o); } #endif } else { #ifdef OBJC_CAP_ARC object_dispose(anObject); #else object_setClass((id)anObject, (Class)(void*)0xdeadface); NSZoneFree(z, o); #endif } } return; } BOOL NSShouldRetainWithZone (NSObject *anObject, NSZone *requestedZone) { return (!requestedZone || requestedZone == NSDefaultMallocZone() || [anObject zone] == requestedZone); } /** *

* NSObject is the root class (a root class is * a class with no superclass) of the GNUstep base library * class hierarchy, so all classes normally inherit from * NSObject. There is an exception though: * NSProxy (which is used for remote messaging) * does not inherit from NSObject. *

*

* Unless you are really sure of what you are doing, all * your own classes should inherit (directly or indirectly) * from NSObject (or in special cases from * NSProxy). NSObject provides * the basic common functionality shared by all GNUstep * classes and objects. *

*

* The essential methods which must be implemented by all * classes for their instances to be usable within GNUstep * are declared in a separate protocol, which is the * NSObject protocol. Both * NSObject and NSProxy conform to * this protocol, which means all objects in a GNUstep * application will conform to this protocol (btw, if you * don't find a method of NSObject you are * looking for in this documentation, make sure you also * look into the documentation for the NSObject * protocol). *

*

* Theoretically, in special cases you might need to * implement a new root class. If you do, you need to make * sure that your root class conforms (at least) to the * NSObject protocol, otherwise it will not * interact correctly with the GNUstep framework. Said * that, I must note that I have never seen a case in which * a new root class is needed. *

*

* NSObject is a root class, which implies that * instance methods of NSObject are treated in * a special way by the Objective-C runtime. This is an * exception to the normal way messaging works with class * and instance methods: if the Objective-C runtime can't * find a class method for a class object, as a last resort * it looks for an instance method of the root class with * the same name, and executes it if it finds it. This * means that instance methods of the root class (such as * NSObject) can be performed by class objects * which inherit from that root class ! This can only * happen if the class doesn't have a class method with the * same name, otherwise that method - of course - takes the * precedence. Because of this exception, * NSObject's instance methods are written in * such a way that they work both on NSObject's * instances and on class objects. *

*/ @implementation NSObject #if defined(GS_ARC_COMPATIBLE) - (void)_ARCCompliantRetainRelease {} #endif /** * Semi-private function in libobjc2 that initialises the classes used for * blocks. */ extern BOOL objc_create_block_classes_as_subclasses_of(Class super); #ifdef OBJC_CAP_ARC static id gs_weak_load(id obj) { return [obj retainCount] > 0 ? obj : nil; } #endif + (void) load { #ifdef OBJC_CAP_ARC _objc_weak_load = gs_weak_load; #endif objc_create_block_classes_as_subclasses_of(self); } + (void) initialize { if (self == [NSObject class]) { #ifdef _WIN32 { // See libgnustep-base-entry.m extern void gnustep_base_socket_init(void); gnustep_base_socket_init(); } #else /* _WIN32 */ #ifdef SIGPIPE /* * If SIGPIPE is not handled or ignored, we will abort on any attempt * to write to a pipe/socket that has been closed by the other end! * We therefore need to ignore the signal if nothing else is already * handling it. */ #ifdef HAVE_SIGACTION { struct sigaction act; if (sigaction(SIGPIPE, 0, &act) == 0) { if (act.sa_handler == SIG_DFL) { // Not ignored or handled ... so we ignore it. act.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &act, 0) != 0) { fprintf(stderr, "Unable to ignore SIGPIPE\n"); } } } else { fprintf(stderr, "Unable to retrieve information about SIGPIPE\n"); } } #else /* HAVE_SIGACTION */ { void (*handler)(NSInteger); handler = signal(SIGPIPE, SIG_IGN); if (handler != SIG_DFL) { signal(SIGPIPE, handler); } } #endif /* HAVE_SIGACTION */ #endif /* SIGPIPE */ #endif /* _WIN32 */ finalize_sel = @selector(finalize); finalize_imp = class_getMethodImplementation(self, finalize_sel); #if defined(__FreeBSD__) && defined(__i386__) // Manipulate the FPU to add the exception mask. (Fixes SIGFPE // problems on *BSD) // Note this only works on x86 # if defined(FE_INVALID) fedisableexcept(FE_INVALID); # else { volatile short cw; __asm__ volatile ("fstcw (%0)" : : "g" (&cw)); cw |= 1; /* Mask 'invalid' exception */ __asm__ volatile ("fldcw (%0)" : : "g" (&cw)); } # endif #endif /* Initialize the locks for allocation when atomic * operations are not available. */ #if !defined(GSATOMICREAD) { NSUInteger i; for (i = 0; i < LOCKCOUNT; i++) { pthread_mutex_init(&allocationLocks[i], NULL); } } #endif /* Create the global lock. * NB. Ths is one of the first things we do ... setting up a new lock * must not call any other Objective-C classes and must not involve * any use of the autorelease system. */ gnustep_global_lock = [GSUntracedRecursiveLock new]; /* Behavior debugging ... enable with environment variable if needed. */ GSObjCBehaviorDebug(GSPrivateEnvironmentFlag("GNUSTEP_BEHAVIOR_DEBUG", GSObjCBehaviorDebug(-1))); /* See if we should cleanup at process exit. */ if (YES == GSPrivateEnvironmentFlag("GNUSTEP_SHOULD_CLEAN_UP", NO)) { [self setShouldCleanUp: YES]; [self registerAtExit: @selector(_atExit)]; } /* Set up the autorelease system ... we must do this before using any * other class whose +initialize might autorelease something. */ autorelease_class = [NSAutoreleasePool class]; autorelease_sel = @selector(addObject:); autorelease_imp = [autorelease_class methodForSelector: autorelease_sel]; /* Make sure the constant string class works and set up well-known * string constants etc. */ NSConstantStringClass = [NSString constantStringClass]; GSPrivateBuildStrings(); /* Now that the string class (and autorelease) is set up, we can set * the name of the lock to a string value safely. */ [gnustep_global_lock setName: @"gnustep_global_lock"]; /* Determine zombie management flags and set up a map to store * information about zombie objects. */ NSZombieEnabled = GSPrivateEnvironmentFlag("NSZombieEnabled", NO); NSDeallocateZombies = GSPrivateEnvironmentFlag("NSDeallocateZombies", NO); zombieMap = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, NSNonOwnedPointerMapValueCallBacks, 0); /* We need to cache the zombie class. * We can't call +class because NSZombie doesn't have that method. * We can't use NSClassFromString() because that would use an NSString * object, and that class hasn't been initialized yet ... */ zombieClass = objc_lookUpClass("NSZombie"); } return; } + (void) _atExit { NSMapTable *m = nil; pthread_mutex_lock(&allocationLock); m = zombieMap; zombieMap = nil; pthread_mutex_unlock(&allocationLock); DESTROY(m); } /** * Allocates a new instance of the receiver from the default * zone, by invoking +allocWithZone: with * NSDefaultMallocZone() as the zone argument.
* Returns the created instance. */ + (id) alloc { return [self allocWithZone: NSDefaultMallocZone()]; } /** * This is the basic method to create a new instance. It * allocates a new instance of the receiver from the specified * memory zone. *

* Memory for an instance of the receiver is allocated; a * pointer to this newly created instance is returned. All * instance variables are set to 0. No initialization of the * instance is performed apart from setup to be an instance of * the correct class: it is your responsibility to initialize the * instance by calling an appropriate init * method. If you are not using the garbage collector, it is * also your responsibility to make sure the returned * instance is destroyed when you finish using it, by calling * the release method to destroy the instance * directly, or by using autorelease and * autorelease pools. *

*

* You do not normally need to override this method in * subclasses, unless you are implementing a class which for * some reasons silently allocates instances of another class * (this is typically needed to implement class clusters and * similar design schemes). *

*

* If you have turned on debugging of object allocation (by * calling the GSDebugAllocationActive * function), this method will also update the various * debugging counts and monitors of allocated objects, which * you can access using the GSDebugAllocation... * functions. *

*/ + (id) allocWithZone: (NSZone*)z { return NSAllocateObject(self, 0, z); } /** * Returns the receiver. */ + (id) copyWithZone: (NSZone*)z { return self; } /** *

* This method is a short-hand for alloc followed by init, that is, *

*

* NSObject *object = [NSObject new]; *

* is exactly the same as *

* NSObject *object = [[NSObject alloc] init]; *

*

* This is a general convention: all new... * methods are supposed to return a newly allocated and * initialized instance, as would be generated by an * alloc method followed by a corresponding * init... method. Please note that if you are * not using a garbage collector, this means that instances * generated by the new... methods are not * autoreleased, that is, you are responsible for releasing * (autoreleasing) the instances yourself. So when you use * new you typically do something like: *

*

* * NSMutableArray *array = AUTORELEASE ([NSMutableArray new]); * *

*

* You do not normally need to override new in * subclasses, because if you override init (and * optionally allocWithZone: if you really * need), new will automatically use your * subclass methods. *

*

* You might need instead to define new new... * methods specific to your subclass to match any * init... specific to your subclass. For * example, if your subclass defines an instance method *

*

* initWithName: *

*

* it might be handy for you to have a class method *

*

* newWithName: *

*

* which combines alloc and * initWithName:. You would implement it as follows: *

*

* * + (id) newWithName: (NSString *)aName * { * return [[self alloc] initWithName: aName]; * } * *

*/ + (id) new { return [[self alloc] init]; } /** * Returns the class of which the receiver is an instance.
* The default implementation returns the actual class that the * receiver is an instance of.
* NB. When NSZombie is enabled (see NSDebug.h) this is changed * to be the NSZombie class upon object deallocation. */ - (Class) class { return object_getClass(self); } /** * Returns the name of the class of the receiving object by using * the NSStringFromClass() function.
* This is a MacOS-X addition for apple scripting, which is also * generally useful. */ - (NSString*) className { return NSStringFromClass([self class]); } /** * Creates and returns a copy of the receiver by calling -copyWithZone: * passing NSDefaultMallocZone() */ - (id) copy { return [(id)self copyWithZone: NSDefaultMallocZone()]; } /** * Deallocates the receiver by calling NSDeallocateObject() with self * as the argument.
*

* You should normally call the superclass implementation of this method * when you override it in a subclass, or the memory occupied by your * object will not be released. *

*

* NSObject's implementation of this method * destroys the receiver, by returning the memory allocated * to the receiver to the system. After this method has been * called on an instance, you must not refer the instance in * any way, because it does not exist any longer. If you do, * it is a bug and your program might even crash with a * segmentation fault. *

*

* If you have turned on the debugging facilities for * instance allocation, NSObject's * implementation of this method will also update the various * counts and monitors of allocated instances (see the * GSDebugAllocation... functions for more * info). *

*

* Normally you are supposed to manage the memory taken by * objects by using the high level interface provided by the * retain, release and * autorelease methods (or better by the * corresponding macros RETAIN, * RELEASE and AUTORELEASE), and by * autorelease pools and such; whenever the * release/autorelease mechanism determines that an object is * no longer needed (which happens when its retain count * reaches 0), it will call the dealloc method * to actually deallocate the object. This means that normally, * you should not need to call dealloc directly as * the gnustep base library automatically calls it for you when * the retain count of an object reaches 0. *

*

* Because the dealloc method will be called * when an instance is being destroyed, if instances of your * subclass use objects or resources (as it happens for most * useful classes), you must override dealloc in * subclasses to release all objects and resources which are * used by the instance, otherwise these objects and * resources would be leaked. In the subclass * implementation, you should first release all your subclass * specific objects and resources, and then invoke super's * implementation (which will do the same, and so on up in * the class hierarchy to NSObject's * implementation, which finally destroys the object). Here * is an example of the implementation of * dealloc for a subclass whose instances have a * single instance variable name which needs to * be released when an instance is deallocated: *

*

* * - (void) dealloc * { * RELEASE (name); * [super dealloc]; * } * *

*

* dealloc might contain code to release not * only objects, but also other resources, such as open * files, network connections, raw memory allocated in other * ways, etc. *

*

* If you have allocated the memory using a non-standard mechanism, you * will not call the superclass (NSObject) implementation of the method * as you will need to handle the deallocation specially.
* In some circumstances, an object may wish to prevent itself from * being deallocated, it can do this simply be refraining from calling * the superclass implementation. *

*/ - (void) dealloc { NSDeallocateObject(self); } - (void) finalize { #ifndef OBJC_CAP_ARC Class destructorClass = Nil; IMP destructor = 0; /* * We're pretending to be the Objective-C runtime here, so we have to do some * unsafe things (i.e. access the class directly, and not via the * object_getClass() so that hidden classes get their destructors called. If * the runtime supports small objects (those embedded in a pointer), then we * must use object_getClass() for them, because they do not have an isa * pointer (but can not have a hidden class interposed). */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-objc-pointer-introspection" #pragma clang diagnostic ignored "-Wdeprecated-objc-isa-usage" #endif #ifdef OBJC_SMALL_OBJECT_MASK if (((NSUInteger)self & OBJC_SMALL_OBJECT_MASK) == 0) { destructorClass = isa; // Potentially hidden class } else { destructorClass = object_getClass(self); // Small object } #else destructorClass = isa; #endif #ifdef __clang__ #pragma clang diagnostic pop #endif /* C++ destructors must be called in the opposite order to their * creators, so start at the leaf class and then go up the tree until we * get to the root class. As a small optimisation, we don't bother * visiting any classes that don't have an implementation of this method * (including one inherited from a superclass). * * Care must be taken not to call inherited .cxx_destruct methods. */ while (class_respondsToSelector(destructorClass, cxx_destruct)) { IMP newDestructor; newDestructor = class_getMethodImplementation(destructorClass, cxx_destruct); destructorClass = class_getSuperclass(destructorClass); if (newDestructor != destructor) { newDestructor(self, cxx_destruct); destructor = newDestructor; } } return; #endif } /** * This method is an anachronism. Do not use it. */ - (id) free { [NSException raise: NSGenericException format: @"Use `dealloc' instead of `free' for %@.", self]; return nil; } /** * Initialises the receiver ... the NSObject implementation simply returns self. */ - (id) init { return self; } /** * Creates and returns a mutable copy of the receiver by calling * -mutableCopyWithZone: passing NSDefaultMallocZone(). */ - (id) mutableCopy { return [(id)self mutableCopyWithZone: NSDefaultMallocZone()]; } /** * Returns the super class from which the receiver was derived. */ + (Class) superclass { return class_getSuperclass(self); } /** * Returns the super class from which the receivers class was derived. */ - (Class) superclass { return class_getSuperclass(object_getClass(self)); } /** * Returns a flag to say if instances of the receiver class will * respond to the specified selector. This ignores situations * where a subclass implements -forwardInvocation: to respond to * selectors not normally handled ... in these cases the subclass * may override this method to handle it. *
If given a null selector, raises NSInvalidArgumentException when * in MacOS-X compatibility more, or returns NO otherwise. */ + (BOOL) instancesRespondToSelector: (SEL)aSelector { if (aSelector == 0) { if (GSPrivateDefaultsFlag(GSMacOSXCompatible)) { [NSException raise: NSInvalidArgumentException format: @"%@ null selector given", NSStringFromSelector(_cmd)]; } return NO; } if (class_respondsToSelector(self, aSelector)) { return YES; } if (class_isMetaClass(self)) { /* It seems convoluted to attempt to access the class from the metaclass just to call +resolveClassMethod: in this rare case. */ return NO; } else { return [self resolveInstanceMethod: aSelector]; } } /** * Returns a flag to say whether the receiving class conforms to aProtocol */ + (BOOL) conformsToProtocol: (Protocol*)aProtocol { #ifdef __GNU_LIBOBJC__ Class c; /* Iterate over the current class and all the superclasses. */ for (c = self; c != Nil; c = class_getSuperclass (c)) { if (class_conformsToProtocol(c, aProtocol)) { return YES; } } return NO; #else /* libobjc2 and ObjectiveC2/ have an implementation of class_conformsToProtocol() which automatically looks up the protocol in superclasses (unlike the Apple and GNU Objective-C runtime ones). */ return class_conformsToProtocol(self, aProtocol); #endif } /** * Returns a flag to say whether the class of the receiver conforms * to aProtocol. */ - (BOOL) conformsToProtocol: (Protocol*)aProtocol { return [[self class] conformsToProtocol: aProtocol]; } /** * Returns a pointer to the C function implementing the method used * to respond to messages with aSelector by instances of the receiving * class. *
Raises NSInvalidArgumentException if given a null selector. */ + (IMP) instanceMethodForSelector: (SEL)aSelector { if (aSelector == 0) [NSException raise: NSInvalidArgumentException format: @"%@ null selector given", NSStringFromSelector(_cmd)]; /* * Since 'self' is an class, class_getMethodImplementation() will get * the instance method. */ return class_getMethodImplementation((Class)self, aSelector); } /** * Returns a pointer to the C function implementing the method used * to respond to messages with aSelector. *
Raises NSInvalidArgumentException if given a null selector. */ - (IMP) methodForSelector: (SEL)aSelector { if (aSelector == 0) [NSException raise: NSInvalidArgumentException format: @"%@ null selector given", NSStringFromSelector(_cmd)]; /* The Apple runtime API would do: * return class_getMethodImplementation(object_getClass(self), aSelector); * but this cannot ask self for information about any method reached by * forwarding, so the returned forwarding function would ge a generic one * rather than one aware of hardware issues with returning structures * and floating points. We therefore prefer the GNU API which is able to * use forwarding callbacks to get better type information. */ return objc_msg_lookup(self, aSelector); } /** * Returns a pointer to the C function implementing the method used * to respond to messages with aSelector which are sent to instances * of the receiving class. *
Raises NSInvalidArgumentException if given a null selector. */ + (NSMethodSignature*) instanceMethodSignatureForSelector: (SEL)aSelector { struct objc_method *mth; if (aSelector == 0) [NSException raise: NSInvalidArgumentException format: @"%@ null selector given", NSStringFromSelector(_cmd)]; mth = GSGetMethod(self, aSelector, YES, YES); if (0 == mth) return nil; return [NSMethodSignature signatureWithObjCTypes: method_getTypeEncoding(mth)]; } /** * Returns the method signature describing how the receiver would handle * a message with aSelector. *
Returns nil if given a null selector. */ - (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector { const char *types = NULL; Class c; unsigned int count; Protocol **protocols; if (0 == aSelector) { return nil; } c = object_getClass(self); /* Do a fast lookup to see if the method is implemented at all. If it isn't, * we can give up without doing a very expensive linear search through every * method list in the class hierarchy. */ if (!class_respondsToSelector(c, aSelector)) { return nil; // Method not implemented } /* If there are protocols that this class conforms to, * the method may be listed in a protocol with more * detailed type information than in the class itself * and we must therefore use the information from the * protocol. * This is because protocols also carry information * used by the Distributed Objects system, which the * runtime does not maintain in classes. */ protocols = class_copyProtocolList(c, &count); if (NULL != protocols) { struct objc_method_description mth; int i; for (i = 0 ; i < count ; i++) { mth = GSProtocolGetMethodDescriptionRecursive(protocols[i], aSelector, YES, YES); if (NULL == mth.types) { // Search for class method mth = GSProtocolGetMethodDescriptionRecursive(protocols[i], aSelector, YES, NO); // FIXME: We should probably search optional methods here too. } if (NULL != mth.types) { break; } } free(protocols); } if (types == 0) { #ifdef __GNUSTEP_RUNTIME__ struct objc_slot *objc_get_slot(Class cls, SEL selector); struct objc_slot *slot = objc_get_slot(object_getClass(self), aSelector); types = slot->types; #else struct objc_method *mth; if (GSObjCIsInstance(self)) { mth = GSGetMethod(object_getClass(self), aSelector, YES, YES); } else { mth = GSGetMethod((Class)self, aSelector, NO, YES); } types = method_getTypeEncoding (mth); #endif } if (types == 0) { return nil; } return [NSMethodSignature signatureWithObjCTypes: types]; } /** * Returns a string describing the receiver. The default implementation * gives the class and memory location of the receiver. */ - (NSString*) description { return [NSString stringWithFormat: @"<%s: %p>", class_getName([self class]), self]; } /** * Returns a string describing the receiving class. The default implementation * gives the name of the class by calling NSStringFromClass(). */ + (NSString*) description { return NSStringFromClass(self); } /** * Sets up the ObjC runtime so that the receiver is used wherever code * calls for aClassObject to be used. */ + (void) poseAsClass: (Class)aClassObject { [NSException raise: NSInternalInconsistencyException format: @"Class posing is not supported"]; } /** * Raises an invalid argument exception providing information about * the receivers inability to handle aSelector. */ - (void) doesNotRecognizeSelector: (SEL)aSelector { [NSException raise: NSInvalidArgumentException format: @"%s(%s) does not recognize %s", GSClassNameFromObject(self), GSObjCIsInstance(self) ? "instance" : "class", aSelector ? sel_getName(aSelector) : "(null)"]; } /** * This method is called automatically to handle a message sent to * the receiver for which the receivers class has no method.
* The default implementation calls -doesNotRecognizeSelector: */ - (void) forwardInvocation: (NSInvocation*)anInvocation { id target = [self forwardingTargetForSelector: [anInvocation selector]]; if (nil != target) { [anInvocation invokeWithTarget: target]; return; } [self doesNotRecognizeSelector: [anInvocation selector]]; return; } /** * Called after the receiver has been created by decoding some sort * of archive. Returns self. Subclasses may override this to perform * some special initialisation upon being decoded. */ - (id) awakeAfterUsingCoder: (NSCoder*)aDecoder { return self; } // FIXME - should this be added (as in OS X) now that we have NSKeyedArchiver? // - (Class) classForKeyedArchiver // { // return [self classForArchiver]; // } /** * Override to substitute class when an instance is being archived by an * [NSArchiver]. Default implementation returns -classForCoder. */ - (Class) classForArchiver { return [self classForCoder]; } /** * Override to substitute class when an instance is being serialized by an * [NSCoder]. Default implementation returns [self class] (no * substitution). */ - (Class) classForCoder { return [self class]; } // FIXME - should this be added (as in OS X) now that we have NSKeyedArchiver? // - (id) replacementObjectForKeyedArchiver: (NSKeyedArchiver *)keyedArchiver // { // return [self replacementObjectForCoder: (NSArchiver *)keyedArchiver]; // } /** * Override to substitute another object for this instance when being archived * by given [NSArchiver]. Default implementation returns * -replacementObjectForCoder:. */ - (id) replacementObjectForArchiver: (NSArchiver*)anArchiver { return [self replacementObjectForCoder: (NSCoder*)anArchiver]; } /** * Override to substitute another object for this instance when being * serialized by given [NSCoder]. Default implementation returns * self. */ - (id) replacementObjectForCoder: (NSCoder*)anEncoder { return self; } /* NSObject protocol */ /** * Adds the receiver to the current autorelease pool, so that it will be * sent a -release message when the pool is destroyed.
* Returns the receiver.
* In GNUstep, the [NSObject+enableDoubleReleaseCheck:] method may be used * to turn on checking for retain/release errors in this method. */ - (id) autorelease { if (double_release_check_enabled) { NSUInteger release_count; NSUInteger retain_count = [self retainCount]; release_count = [autorelease_class autoreleaseCountForObject:self]; if (release_count > retain_count) [NSException raise: NSGenericException format: @"Autorelease would release object too many times.\n" @"%"PRIuPTR" release(s) versus %"PRIuPTR" retain(s)", release_count, retain_count]; } (*autorelease_imp)(autorelease_class, autorelease_sel, self); return self; } /** * Dummy method returning the receiver. */ + (id) autorelease { return self; } /** * Returns the receiver. */ + (Class) class { return self; } /** * Returns the hash of the receiver. Subclasses should ensure that their * implementations of this method obey the rule that if the -isEqual: method * returns YES for two instances of the class, the -hash method returns the * same value for both instances.
* The default implementation returns a value based on the address * of the instance. */ - (NSUInteger) hash { /* * malloc() must return pointers aligned to point to any data type */ #define MAXALIGN (__alignof__(_Complex long double)) static int shift = MAXALIGN==16 ? 4 : (MAXALIGN==8 ? 3 : 2); /* We shift left to lose any zero bits produced by the * alignment of the object in memory. */ return (NSUInteger)((uintptr_t)self >> shift); } /** * Tests anObject and the receiver for equality. The default implementation * considers two objects to be equal only if they are the same object * (ie occupy the same memory location).
* If a subclass overrides this method, it should also override the -hash * method so that if two objects are equal they both have the same hash. */ - (BOOL) isEqual: (id)anObject { return (self == anObject); } /** * Returns YES if aClass is the NSObject class */ + (BOOL) isKindOfClass: (Class)aClass { if (aClass == [NSObject class]) return YES; return NO; } /** * Returns YES if the class of the receiver is either the same as aClass * or is derived from (a subclass of) aClass. */ - (BOOL) isKindOfClass: (Class)aClass { Class class = object_getClass(self); return GSObjCIsKindOf(class, aClass); } /** * Returns YES if aClass is the same as the receiving class. */ + (BOOL) isMemberOfClass: (Class)aClass { return (self == aClass) ? YES : NO; } /** * Returns YES if the class of the receiver is aClass */ - (BOOL) isMemberOfClass: (Class)aClass { return ([self class] == aClass) ? YES : NO; } /** * Returns a flag to differentiate between 'true' objects, and objects * which are proxies for other objects (ie they forward messages to the * other objects).
* The default implementation returns NO. */ - (BOOL) isProxy { return NO; } /** * Returns YES if the receiver is aClass or a subclass of aClass. */ + (BOOL) isSubclassOfClass: (Class)aClass { return GSObjCIsKindOf(self, aClass); } /** * Causes the receiver to execute the method implementation corresponding * to aSelector and returns the result.
* The method must be one which takes no arguments and returns an object. *
Raises NSInvalidArgumentException if given a null selector. */ - (id) performSelector: (SEL)aSelector { IMP msg; if (aSelector == 0) [NSException raise: NSInvalidArgumentException format: @"%@ null selector given", NSStringFromSelector(_cmd)]; /* The Apple runtime API would do: * msg = class_getMethodImplementation(object_getClass(self), aSelector); * but this cannot ask self for information about any method reached by * forwarding, so the returned forwarding function would ge a generic one * rather than one aware of hardware issues with returning structures * and floating points. We therefore prefer the GNU API which is able to * use forwarding callbacks to get better type information. */ msg = objc_msg_lookup(self, aSelector); if (!msg) { [NSException raise: NSGenericException format: @"invalid selector '%s' passed to %s", sel_getName(aSelector), sel_getName(_cmd)]; return nil; } return (*msg)(self, aSelector); } /** * Causes the receiver to execute the method implementation corresponding * to aSelector and returns the result.
* The method must be one which takes one argument and returns an object. *
Raises NSInvalidArgumentException if given a null selector. */ - (id) performSelector: (SEL)aSelector withObject: (id)anObject { IMP msg; if (aSelector == 0) [NSException raise: NSInvalidArgumentException format: @"%@ null selector given", NSStringFromSelector(_cmd)]; /* The Apple runtime API would do: * msg = class_getMethodImplementation(object_getClass(self), aSelector); * but this cannot ask self for information about any method reached by * forwarding, so the returned forwarding function would be a generic one * rather than one aware of hardware issues with returning structures * and floating points. We therefore prefer the GNU API which is able to * use forwarding callbacks to get better type information. */ msg = objc_msg_lookup(self, aSelector); if (!msg) { [NSException raise: NSGenericException format: @"invalid selector '%s' passed to %s", sel_getName(aSelector), sel_getName(_cmd)]; return nil; } return (*msg)(self, aSelector, anObject); } /** * Causes the receiver to execute the method implementation corresponding * to aSelector and returns the result.
* The method must be one which takes two arguments and returns an object. *
Raises NSInvalidArgumentException if given a null selector. */ - (id) performSelector: (SEL)aSelector withObject: (id) object1 withObject: (id) object2 { IMP msg; if (aSelector == 0) [NSException raise: NSInvalidArgumentException format: @"%@ null selector given", NSStringFromSelector(_cmd)]; /* The Apple runtime API would do: * msg = class_getMethodImplementation(object_getClass(self), aSelector); * but this cannot ask self for information about any method reached by * forwarding, so the returned forwarding function would ge a generic one * rather than one aware of hardware issues with returning structures * and floating points. We therefore prefer the GNU API which is able to * use forwarding callbacks to get better type information. */ msg = objc_msg_lookup(self, aSelector); if (!msg) { [NSException raise: NSGenericException format: @"invalid selector '%s' passed to %s", sel_getName(aSelector), sel_getName(_cmd)]; return nil; } return (*msg)(self, aSelector, object1, object2); } /** * Decrements the retain count for the receiver if greater than zero, * otherwise calls the dealloc method instead.
* The default implementation calls the NSDecrementExtraRefCountWasZero() * function to test the extra reference count for the receiver (and * decrement it if non-zero) - if the extra reference count is zero then * the retain count is one, and the dealloc method is called.
* In GNUstep, the [NSObject+enableDoubleReleaseCheck:] method may be used * to turn on checking for ratain/release errors in this method. */ - (oneway void) release { release_fast(self); } /** * The class implementation of the release method is a dummy method * having no effect. It is present so that class objects can be stored * in containers (such as NSArray) which will send them retain and * release messages. */ + (oneway void) release { return; } /** * Returns a flag to say if the receiver will * respond to the specified selector. This ignores situations * where a subclass implements -forwardInvocation: to respond to * selectors not normally handled ... in these cases the subclass * may override this method to handle it. *
If given a null selector, raises NSInvalidArgumentException when * in MacOS-X compatibility more, or returns NO otherwise. */ - (BOOL) respondsToSelector: (SEL)aSelector { Class cls = object_getClass(self); if (aSelector == 0) { if (GSPrivateDefaultsFlag(GSMacOSXCompatible)) { [NSException raise: NSInvalidArgumentException format: @"%@ null selector given", NSStringFromSelector(_cmd)]; } return NO; } if (class_respondsToSelector(cls, aSelector)) { return YES; } if (class_isMetaClass(cls)) { return [(Class)self resolveClassMethod: aSelector]; } else { return [cls resolveInstanceMethod: aSelector]; } } /** * Increments the reference count and returns the receiver.
* The default implementation does this by calling NSIncrementExtraRefCount() */ - (id) retain { return retain_fast(self); } /** * The class implementation of the retain method is a dummy method * having no effect. It is present so that class objects can be stored * in containers (such as NSArray) which will send them retain and * release messages. */ + (id) retain { return self; } /** * Returns the reference count for the receiver. Each instance has an * implicit reference count of 1, and has an 'extra reference count' * returned by the NSExtraRefCount() function, so the value returned by * this method is always greater than zero.
* By convention, objects which should (or can) never be deallocated * return the maximum unsigned integer value. */ - (NSUInteger) retainCount { return getRetainCount(self); } /** * The class implementation of the retainCount method always returns * the maximum unsigned integer value, as classes can not be deallocated * the retain count mechanism is a dummy system for them. */ + (NSUInteger) retainCount { return UINT_MAX; } /** * Returns the receiver. */ - (id) self { return self; } /** * Returns the memory allocation zone in which the receiver is located. */ - (NSZone*) zone { return NSZoneFromPointer(self); } + (NSZone *) zone { return NSDefaultMallocZone(); } /** * Called to encode the instance variables of the receiver to aCoder.
* Subclasses should call the superclass method at the start of their * own implementation. */ - (void) encodeWithCoder: (NSCoder*)aCoder { return; } /** * Called to intialise instance variables of the receiver from aDecoder.
* Subclasses should call the superclass method at the start of their * own implementation. */ - (id) initWithCoder: (NSCoder*)aDecoder { return self; } + (BOOL) resolveClassMethod: (SEL)name { return NO; } + (BOOL) resolveInstanceMethod: (SEL)name { return NO; } /** * Sets the version number of the receiving class. Should be nonnegative. */ + (id) setVersion: (NSInteger)aVersion { if (aVersion < 0) [NSException raise: NSInvalidArgumentException format: @"%s +setVersion: may not set a negative version", GSClassNameFromObject(self)]; class_setVersion(self, aVersion); return self; } /** * Returns the version number of the receiving class. This will default to * a number assigned by the Objective C compiler if [NSObject -setVersion] has * not been called. */ + (NSInteger) version { return class_getVersion(self); } - (id) autoContentAccessingProxy { return AUTORELEASE([[GSContentAccessingProxy alloc] initWithObject: self]); } - (id) forwardingTargetForSelector:(SEL)aSelector { return nil; } @end /** * Methods for compatibility with the NEXTSTEP (pre-OpenStep) 'Object' class. */ @implementation NSObject (NEXTSTEP) /* NEXTSTEP Object class compatibility */ /** * Logs a message. Deprecated. Use NSLog() in new code. */ - (id) error: (const char *)aString, ... { #define FMT "error: %s (%s)\n%s\n" char fmt[(strlen((char*)FMT)+strlen((char*)GSClassNameFromObject(self)) +((aString!=NULL)?strlen((char*)aString):0)+8)]; va_list ap; snprintf(fmt, sizeof(fmt), FMT, GSClassNameFromObject(self), GSObjCIsInstance(self) ? "instance" : "class", (aString != NULL) ? aString : ""); va_start(ap, aString); vfprintf (stderr, fmt, ap); abort (); va_end(ap); #undef FMT return nil; } /* - (const char *) name { return GSClassNameFromObject(self); } */ - (BOOL) isKindOf: (Class)aClassObject { return [self isKindOfClass: aClassObject]; } - (BOOL) isMemberOf: (Class)aClassObject { return [self isMemberOfClass: aClassObject]; } + (BOOL) instancesRespondTo: (SEL)aSel { return [self instancesRespondToSelector: aSel]; } - (BOOL) respondsTo: (SEL)aSel { return [self respondsToSelector: aSel]; } + (BOOL) conformsTo: (Protocol*)aProtocol { return [self conformsToProtocol: aProtocol]; } - (BOOL) conformsTo: (Protocol*)aProtocol { return [self conformsToProtocol: aProtocol]; } + (IMP) instanceMethodFor: (SEL)aSel { return [self instanceMethodForSelector:aSel]; } - (IMP) methodFor: (SEL)aSel { return [self methodForSelector: aSel]; } + (id) poseAs: (Class)aClassObject { [self poseAsClass: aClassObject]; return self; } - (id) doesNotRecognize: (SEL)aSel { [NSException raise: NSGenericException format: @"%s(%s) does not recognize %s", GSClassNameFromObject(self), GSObjCIsInstance(self) ? "instance" : "class", aSel ? sel_getName(aSel) : "(null)"]; return nil; } - (id) perform: (SEL)sel with: (id)anObject { return [self performSelector: sel withObject: anObject]; } - (id) perform: (SEL)sel with: (id)anObject with: (id)anotherObject { return [self performSelector: sel withObject: anObject withObject: anotherObject]; } @end /** * Some non-standard extensions mainly needed for backwards compatibility * and internal utility reasons. */ @implementation NSObject (GNUstep) /** * Enables runtime checking of retain/release/autorelease operations.
*

Whenever either -autorelease or -release is called, the contents of any * autorelease pools will be checked to see if there are more outstanding * release operations than the objects retain count. In which case an * exception is raised to say that the object is released too many times. *

*

Beware, since this feature entails examining all active * autorelease pools every time an object is released or autoreleased, it * can cause a massive performance degradation ... it should only be enabled * for debugging. *

*

* When you are having memory allocation problems, it may make more sense * to look at the memory allocation debugging functions documented in * NSDebug.h, or use the NSZombie features. *

*/ + (void) enableDoubleReleaseCheck: (BOOL)enable { double_release_check_enabled = enable; } /** * The default (NSObject) implementation of this method simply calls * the -description method and discards the locale * information. */ - (NSString*) descriptionWithLocale: (id)aLocale { return [self description]; } + (NSString*) descriptionWithLocale: (id)aLocale { return [self description]; } /** * The default (NSObject) implementation of this method simply calls * the -descriptionWithLocale: method and discards the * level information. */ - (NSString*) descriptionWithLocale: (id)aLocale indent: (NSUInteger)level { return [self descriptionWithLocale: aLocale]; } + (NSString*) descriptionWithLocale: (id)aLocale indent: (NSUInteger)level { return [self descriptionWithLocale: aLocale]; } - (BOOL) _dealloc { return YES; } - (BOOL) isMetaClass { return NO; } - (BOOL) isClass { return class_isMetaClass(object_getClass(self)); } - (BOOL) isMemberOfClassNamed: (const char*)aClassName { return ((aClassName!=NULL) &&!strcmp(class_getName(object_getClass(self)), aClassName)); } + (struct objc_method_description *) descriptionForInstanceMethod: (SEL)aSel { if (aSel == 0) [NSException raise: NSInvalidArgumentException format: @"%@ null selector given", NSStringFromSelector(_cmd)]; return ((struct objc_method_description *) GSGetMethod(self, aSel, YES, YES)); } - (struct objc_method_description *) descriptionForMethod: (SEL)aSel { if (aSel == 0) [NSException raise: NSInvalidArgumentException format: @"%@ null selector given", NSStringFromSelector(_cmd)]; return ((struct objc_method_description *) GSGetMethod((GSObjCIsInstance(self) ? object_getClass(self) : (Class)self), aSel, GSObjCIsInstance(self), YES)); } + (NSInteger) streamVersion: (void*)aStream { GSOnceMLog(@"[NSObject+streamVersion:] is deprecated ... do not use"); return class_getVersion (self); } - (id) read: (void*)aStream { GSOnceMLog(@"[NSObject-read:] is deprecated ... do not use"); return self; } - (id) write: (void*)aStream { GSOnceMLog(@"[NSObject-write:] is deprecated ... do not use"); return self; } - (id) awake { GSOnceMLog(@"[NSObject-awake] is deprecated ... do not use"); return self; } @end @implementation NSZombie - (Class) class { return object_getClass(self); } - (Class) originalClass { Class c = Nil; if (0 != zombieMap) { pthread_mutex_lock(&allocationLock); if (0 != zombieMap) { c = NSMapGet(zombieMap, (void*)self); } pthread_mutex_unlock(&allocationLock); } return c; } - (void) forwardInvocation: (NSInvocation*)anInvocation { NSUInteger size = [[anInvocation methodSignature] methodReturnLength]; unsigned char v[size]; memset(v, '\0', size); GSLogZombie(self, [anInvocation selector]); [anInvocation setReturnValue: (void*)v]; return; } - (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector { Class c; if (0 == aSelector) { return nil; } pthread_mutex_lock(&allocationLock); c = zombieMap ? NSMapGet(zombieMap, (void*)self) : Nil; pthread_mutex_unlock(&allocationLock); return [c instanceMethodSignatureForSelector: aSelector]; } @end @implementation GSContentAccessingProxy - (void) dealloc { [object endContentAccess]; [super dealloc]; } - (void) finalize { [object endContentAccess]; } - (id) forwardingTargetForSelector: (SEL)aSelector { return object; } /* Support for legacy runtimes... */ - (void) forwardInvocation: (NSInvocation*)anInvocation { [anInvocation invokeWithTarget: object]; } - (id) initWithObject: (id)anObject { ASSIGN(object, anObject); [object beginContentAccess]; return self; } - (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector { return [object methodSignatureForSelector: aSelector]; } @end NSUInteger GSPrivateMemorySize(NSObject *self, NSHashTable *exclude) { if (0 == NSHashGet(exclude, self)) { NSHashInsert(exclude, self); return class_getInstanceSize(object_getClass(self)); } return 0; } @implementation NSObject (MemoryFootprint) + (NSUInteger) contentSizeOf: (NSObject*)obj excluding: (NSHashTable*)exclude { Class cls = object_getClass(obj); NSUInteger size = 0; while (cls != Nil) { unsigned count; Ivar *vars; if (0 != (vars = class_copyIvarList(cls, &count))) { while (count-- > 0) { const char *type = ivar_getTypeEncoding(vars[count]); type = GSSkipTypeQualifierAndLayoutInfo(type); if ('@' == *type) { NSObject *content = object_getIvar(obj, vars[count]); if (content != nil) { size += [content sizeInBytesExcluding: exclude]; } } } free(vars); } cls = class_getSuperclass(cls); } return size; } + (NSUInteger) sizeInBytes { return 0; } + (NSUInteger) sizeInBytesExcluding: (NSHashTable*)exclude { return 0; } + (NSUInteger) sizeOfContentExcluding: (NSHashTable*)exclude { return 0; } - (NSUInteger) sizeInBytes { NSUInteger bytes; NSHashTable *exclude; exclude = NSCreateHashTable(NSNonOwnedPointerHashCallBacks, 0); bytes = [self sizeInBytesExcluding: exclude]; NSFreeHashTable(exclude); return bytes; } - (NSUInteger) sizeInBytesExcluding: (NSHashTable*)exclude { if (0 == NSHashGet(exclude, self)) { NSUInteger size = [self sizeOfInstance]; NSHashInsert(exclude, self); if (size > 0) { size += [self sizeOfContentExcluding: exclude]; } return size; } return 0; } - (NSUInteger) sizeOfContentExcluding: (NSHashTable*)exclude { return 0; } - (NSUInteger) sizeOfInstance { NSUInteger size; #if GS_SIZEOF_VOIDP > 4 NSUInteger u = (NSUInteger)self; if (u & 0x07) { return 0; // Small object has no size } #endif #if HAVE_MALLOC_USABLE_SIZE size = malloc_usable_size((void*)self - sizeof(intptr_t)); #else size = class_getInstanceSize(object_getClass(self)); #endif return size; } @end