Cleanup ... avoid accessing the 'isa' variable directly.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@32247 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2011-02-20 16:21:43 +00:00
parent 4531875573
commit 313cf13c67
19 changed files with 150 additions and 123 deletions

View file

@ -1,3 +1,27 @@
2011-02-20 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSMethodSignature.m:
* Source/GSArray.m:
* Source/NSKeyValueObserving.m:
* Source/GSPrivate.h:
* Source/GSDictionary.m:
* Source/NSURLProtocol.m:
* Source/NSURL.m:
* Source/NSObject.m:
* Source/NSDecimalNumber.m:
* Source/Additions/GSObjCRuntime.m:
* Source/Additions/GSInsensitiveDictionary.m:
* Source/Additions/GSLock.m:
* Source/GSSet.m:
* Source/GSString.m:
* Source/NSConnection.m:
* Source/NSData.m:
* Headers/Additions/GNUstepBase/GSObjCRuntime.h:
Expose class pointer swizzling function in GSObjCRuntime.
Replace direct references to 'isa' pointer with objc_getClass() and
objcSetClass() calls (or occasionally calls to the -class method if
it seems more appropriate).
2011-02-20 Fred Kiefer <FredKiefer@gmx.de>
* Source/NSNumberFormatter.m (-init): Only check the formatter in

View file

@ -416,6 +416,15 @@ GSObjCAllSubclassesOfClass(Class cls);
GS_EXPORT NSArray *
GSObjCDirectSubclassesOfClass(Class cls);
/** Function to change the class of the specified instance to newClass.
* This handles memory debugging issues in GNUstep-base and also
* deals with class finalisation issues in a garbage collecting
* environment, so you should use this function rather than attempting
* to swizzle class pointers directly.
*/
GS_EXPORT void
GSClassSwizzle(id instance, Class newClass);
#if GS_API_VERSION(GS_API_ANY,011500)
GS_EXPORT const char *

View file

@ -372,13 +372,7 @@ static SEL objSel;
- (id) makeImmutableCopyOnFail: (BOOL)force
{
#if !defined(NDEBUG) && defined(GNUSTEP_BASE_LIBRARY)
GSDebugAllocationRemove(isa, self);
#endif
isa = [_GSInsensitiveDictionary class];
#if !defined(NDEBUG) && defined(GNUSTEP_BASE_LIBRARY)
GSDebugAllocationAdd(isa, self);
#endif
GSClassSwizzle(self, [_GSInsensitiveDictionary class]);
return self;
}

View file

@ -54,7 +54,7 @@
- (void) _becomeThreaded: (NSNotification*)n
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
isa = [NSLock class];
object_setClass(self, [NSLock class]);
if (locked == YES)
{
if ([self tryLock] == NO)
@ -196,7 +196,7 @@
- (void) _becomeThreaded: (NSNotification*)n
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
isa = [NSRecursiveLock class];
object_setClass(self, [NSRecursiveLock class]);
while (counter-- > 0)
{
if ([self tryLock] == NO)

View file

@ -1961,3 +1961,68 @@ GSPrintf (FILE *fptr, NSString* format, ...)
RELEASE(arp);
return ok;
}
#if defined(GNUSTEP_BASE_LIBRARY)
# if GS_WITH_GC
static BOOL
GSIsFinalizable(Class c)
{
static IMP finalizeIMP = 0;
if (0 == finalizeIMP)
{
finalizeIMP = [NSObject instanceMethodForSelector: @selector(finalize)];
}
if (class_getMethodImplementation(c, @selector(finalize)) != finalizeIMP)
return YES;
return NO;
}
# endif /* GS_WITH_GC */
#endif /* defined(GNUSTEP_BASE_LIBRARY) */
void
GSClassSwizzle(id instance, Class newClass)
{
Class oldClass = object_getClass(instance);
#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
if (oldClass != newClass)
{
#if defined(GNUSTEP_BASE_LIBRARY)
# if GS_WITH_GC
/* We only do allocation counting for objects that can be
* finalised - for other objects we have no way of decrementing
* the count when the object is collected.
*/
if (GSIsFinalizable(oldClass))
{
/* Already finalizable, so we just need to do any allocation
* accounting.
*/
AREM(oldClass, instance);
AADD(newClass, instance);
}
else if (GSIsFinalizable(newClass))
{
/* New class is finalizable, so we must register the instance
* for finalisation and do allocation acounting for it.
*/
AADD(newClass, instance);
GC_REGISTER_FINALIZER (instance, GSFinalize, NULL, NULL, NULL);
}
# else
AREM(oldClass, instance);
AADD(newClass, instance);
# endif /* GS_WITH_GC */
#endif /* defined(GNUSTEP_BASE_LIBRARY) */
object_setClass(instance, newClass);
}
}

View file

@ -635,13 +635,7 @@ static Class GSInlineArrayClass;
- (id) makeImmutableCopyOnFail: (BOOL)force
{
#ifndef NDEBUG
GSDebugAllocationRemove(isa, self);
#endif
isa = [GSArray class];
#ifndef NDEBUG
GSDebugAllocationAdd(isa, self);
#endif
GSClassSwizzle(self, [GSArray class]);
return self;
}

View file

@ -394,13 +394,7 @@ static SEL objSel;
- (id) makeImmutableCopyOnFail: (BOOL)force
{
#ifndef NDEBUG
GSDebugAllocationRemove(isa, self);
#endif
isa = [GSDictionary class];
#ifndef NDEBUG
GSDebugAllocationAdd(isa, self);
#endif
GSClassSwizzle(self, [GSDictionary class]);
return self;
}

View file

@ -531,12 +531,6 @@ GSPrivateUnloadModule(FILE *errorStream,
- (void) protect;
@end
/* Function to safely change the class of an object by 'isa' swizzling
* wile maintaining allocation accounting and finalization in a GC world.
*/
void
GSPrivateSwizzle(id o, Class c) GS_ATTRIB_PRIVATE;
BOOL
GSPrivateIsCollectable(const void *ptr) GS_ATTRIB_PRIVATE;

View file

@ -657,13 +657,7 @@ static Class mutableSetClass;
- (id) makeImmutableCopyOnFail: (BOOL)force
{
#ifndef NDEBUG
GSDebugAllocationRemove(isa, self);
#endif
isa = [GSSet class];
#ifndef NDEBUG
GSDebugAllocationAdd(isa, self);
#endif
GSClassSwizzle(self, [GSSet class]);
return self;
}

View file

@ -4311,20 +4311,14 @@ NSAssert(_flags.owned == 1 && _zone != 0, NSInternalInconsistencyException);
- (id) makeImmutableCopyOnFail: (BOOL)force
{
NSAssert(_flags.owned == 1 && _zone != 0, NSInternalInconsistencyException);
#ifndef NDEBUG
GSDebugAllocationRemove(isa, self);
#endif
if (_flags.wide == 1)
{
isa = [GSUnicodeBufferString class];
GSClassSwizzle(self, [GSUnicodeBufferString class]);
}
else
{
isa = [GSCBufferString class];
GSClassSwizzle(self, [GSCBufferString class]);
}
#ifndef NDEBUG
GSDebugAllocationAdd(isa, self);
#endif
return self;
}

View file

@ -3046,7 +3046,7 @@ static NSLock *cached_proxies_gate = nil;
/* xxx We should make sure that TARGET is a valid object. */
/* Not actually a Proxy, but we avoid the warnings "id" would have made. */
m = GSGetMethod(((NSDistantObject*)o)->isa, sel, YES, YES);
m = GSGetMethod(object_getClass(o), sel, YES, YES);
/* Perhaps I need to be more careful in the line above to get the
version of the method types that has the type qualifiers in it.
Search the protocols list. */
@ -3883,9 +3883,10 @@ static NSLock *cached_proxies_gate = nil;
/* Don't assert (IisValid); */
NSParameterAssert(aTarget > 0);
NSParameterAssert(aProxy==nil || aProxy->isa == distantObjectClass);
NSParameterAssert(aProxy==nil || [aProxy connectionForProxy] == self);
NSParameterAssert(aProxy==nil || aTarget == aProxy->_handle);
NSParameterAssert(aProxy == nil
|| object_getClass(aProxy) == distantObjectClass);
NSParameterAssert(aProxy == nil || [aProxy connectionForProxy] == self);
NSParameterAssert(aProxy == nil || aTarget == aProxy->_handle);
M_LOCK(IrefGate);
node = GSIMapNodeForKey(IremoteProxies, (GSIMapKey)aTarget);

View file

@ -2942,12 +2942,12 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
}
if (shouldFree == NO)
{
GSPrivateSwizzle(self, dataStatic);
GSClassSwizzle(self, dataStatic);
}
#if GS_WITH_GC
else if (aBuffer != 0 && GSPrivateIsCollectable(aBuffer) == NO)
{
GSPrivateSwizzle(self, dataFinalized);
GSClassSwizzle(self, dataFinalized);
}
#endif
bytes = aBuffer;
@ -3245,7 +3245,7 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
#if GS_WITH_GC
if (shouldFree == YES && GSPrivateIsCollectable(aBuffer) == NO)
{
GSPrivateSwizzle(self, mutableDataFinalized);
GSClassSwizzle(self, mutableDataFinalized);
}
#endif
self = [self initWithCapacity: 0];

View file

@ -742,7 +742,7 @@ static NSDecimalNumber *one;
- (NSDecimalNumber*) decimalNumberByAdding: (NSDecimalNumber*)decimalNumber
{
return [self decimalNumberByAdding: decimalNumber
withBehavior: [isa defaultBehavior]];
withBehavior: [[self class] defaultBehavior]];
}
- (NSDecimalNumber*) decimalNumberByAdding: (NSDecimalNumber*)decimalNumber
@ -771,7 +771,7 @@ static NSDecimalNumber *one;
- (NSDecimalNumber*) decimalNumberBySubtracting: (NSDecimalNumber*)decimalNumber
{
return [self decimalNumberBySubtracting: decimalNumber
withBehavior: [isa defaultBehavior]];
withBehavior: [[self class] defaultBehavior]];
}
- (NSDecimalNumber*) decimalNumberBySubtracting: (NSDecimalNumber*)decimalNumber
@ -801,7 +801,7 @@ static NSDecimalNumber *one;
(NSDecimalNumber*)decimalNumber
{
return [self decimalNumberByMultiplyingBy: decimalNumber
withBehavior: [isa defaultBehavior]];
withBehavior: [[self class] defaultBehavior]];
}
- (NSDecimalNumber*) decimalNumberByMultiplyingBy:
@ -831,7 +831,7 @@ static NSDecimalNumber *one;
- (NSDecimalNumber*) decimalNumberByDividingBy: (NSDecimalNumber*)decimalNumber
{
return [self decimalNumberByDividingBy: decimalNumber
withBehavior: [isa defaultBehavior]];
withBehavior: [[self class] defaultBehavior]];
}
- (NSDecimalNumber*) decimalNumberByDividingBy: (NSDecimalNumber*)decimalNumber
@ -860,7 +860,7 @@ static NSDecimalNumber *one;
- (NSDecimalNumber*) decimalNumberByMultiplyingByPowerOf10: (short)power
{
return [self decimalNumberByMultiplyingByPowerOf10: power
withBehavior: [isa defaultBehavior]];
withBehavior: [[self class] defaultBehavior]];
}
- (NSDecimalNumber*) decimalNumberByMultiplyingByPowerOf10: (short)power
@ -889,7 +889,7 @@ static NSDecimalNumber *one;
- (NSDecimalNumber*) decimalNumberByRaisingToPower: (NSUInteger)power
{
return [self decimalNumberByRaisingToPower: power
withBehavior: [isa defaultBehavior]];
withBehavior: [[self class] defaultBehavior]];
}
- (NSDecimalNumber*) decimalNumberByRaisingToPower: (NSUInteger)power
@ -932,20 +932,20 @@ static NSDecimalNumber *one;
leftOperand: (NSDecimalNumber*)leftOperand
rightOperand: (NSDecimalNumber*)rightOperand
{
return [[isa defaultBehavior] exceptionDuringOperation: method
error: error
leftOperand: leftOperand
rightOperand: rightOperand];
return [[[self class] defaultBehavior] exceptionDuringOperation: method
error: error
leftOperand: leftOperand
rightOperand: rightOperand];
}
- (NSRoundingMode) roundingMode
{
return [[isa defaultBehavior] roundingMode];
return [[[self class] defaultBehavior] roundingMode];
}
- (short) scale
{
return [[isa defaultBehavior] scale];
return [[[self class] defaultBehavior] scale];
}
- (Class) classForCoder

View file

@ -47,7 +47,7 @@
/*
* IMPLEMENTATION NOTES
*
* Originally, I wanted to do KVO via a proxy, with isa swizzling
* Originally, I wanted to do KVO via a proxy, with class pointer swizzling
* to turn the original instance into an instance of the proxy class.
* However, I couldn't figure a way to get decent performance out of
* this model, as every message to the instance would have to be
@ -57,7 +57,7 @@
* So, instead I arrived at the mechanism of creating a subclass of
* each class being observed, with a few subclass methods overriding
* those of the original, but most remaining the same.
* The same isa swizzling technique was used to convert between the
* The same class pointer swizzling technique was used to convert between the
* original class and the superclass.
* This subclass basically overrides several standard methods with
* those from a template class, and then overrides any setter methods
@ -211,7 +211,7 @@ static inline void setup()
{
// Turn off KVO for self ... then call the real dealloc implementation.
[self setObservationInfo: nil];
isa = [self class];
object_setClass(self, [self class]);
[self dealloc];
GSNOSUPERDEALLOC;
}
@ -1471,7 +1471,7 @@ replacementForClass(Class c)
{
info = [[GSKVOInfo alloc] initWithInstance: self];
[self setObservationInfo: info];
isa = [r replacement];
object_setClass(self, [r replacement]);
}
/*
@ -1521,7 +1521,7 @@ replacementForClass(Class c)
* The instance is no longer being observed ... so we can
* turn off key-value-observing for it.
*/
isa = [self class];
object_setClass(self, [self class]);
IF_NO_GC(AUTORELEASE(info);)
[self setObservationInfo: nil];
}

View file

@ -528,7 +528,7 @@ next_arg(const char *typePtr, NSArgumentInfo *info, char *outTypes)
{
return NO;
}
if (((NSMethodSignature *)other)->isa != isa)
if (object_getClass(other) != object_getClass(self))
{
return NO;
}

View file

@ -700,44 +700,6 @@ NSDeallocateObject(id anObject)
#endif /* GS_WITH_GC */
void
GSPrivateSwizzle(id o, Class c)
{
Class oc = object_getClass(o);
if (oc != c)
{
#if GS_WITH_GC
/* We only do allocation counting for objects that can be
* finalised - for other objects we have no way of decrementing
* the count when the object is collected.
*/
if (GSIsFinalizable(oc))
{
/* Already finalizable, so we just need to do any allocation
* accounting.
*/
AREM(oc, o);
AADD(c, o);
}
else if (GSIsFinalizable(c))
{
/* New class is finalizable, so we must register the instance
* for finalisation and do allocation acounting for it.
*/
AADD(c, o);
GC_REGISTER_FINALIZER (o, GSFinalize, NULL, NULL, NULL);
}
#else
AREM(oc, o);
AADD(c, o);
#endif /* GS_WITH_GC */
object_setClass(o, c);
}
}
BOOL
NSShouldRetainWithZone (NSObject *anObject, NSZone *requestedZone)
{
@ -1024,10 +986,9 @@ objc_create_block_classes_as_subclasses_of(Class super) __attribute__((weak));
* <p>
* 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 except the
* <code>isa</code> pointer which is set to point to the
* object class. No initialization of the instance is
* performed: it is your responsibility to initialize the
* 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 <code>init</code>
* method. If you are not using the garbage collector, it is
* also your responsibility to make sure the returned
@ -1135,11 +1096,10 @@ objc_create_block_classes_as_subclasses_of(Class super) __attribute__((weak));
/**
* Returns the class of which the receiver is an instance.<br />
* The default implementation returns the private <code>isa</code>
* instance variable of NSObject, which is used to store a pointer
* to the objects class.<br />
* NB. When NSZombie is enabled (see NSDebug.h) this pointer is
* changed upon object deallocation.
* The default implementation returns the actual class that the
* receiver is an instance of.<br />
* NB. When NSZombie is enabled (see NSDebug.h) this is changed
* to be the NSZombie class upon object deallocation.
*/
- (Class) class
{

View file

@ -49,9 +49,9 @@ extern BOOL __objc_responds_to(id, SEL);
* implement -forwardInvocation: to these <em>real</em> objects.</p>
*
* <p>Note that <code>NSProxy</code> is a different sort of class than others
* in the GNUstep Base library in that it is the only example of a root class
* besides [NSObject]. Thus, it defines its own <code><em>isa</em></code>
* variable and implements the <code>NSObject</code> protocol.</p>
* in the GNUstep Base library in that it is the only example of a root class
* besides [NSObject]. Thus, it implements the <code>NSObject</code> protocol
* but is not a subclass of NSObject.</p>
*/
@implementation NSProxy

View file

@ -1206,8 +1206,8 @@ static unsigned urlAlign;
{
if (NSShouldRetainWithZone(self, zone) == NO)
{
return [[isa allocWithZone: zone] initWithString: _urlString
relativeToURL: _baseURL];
return [[[self class] allocWithZone: zone] initWithString: _urlString
relativeToURL: _baseURL];
}
else
{

View file

@ -462,7 +462,9 @@ static NSURLProtocol *placeholder = nil;
{
if ((self = [super init]) != nil)
{
if (isa != abstractClass && isa != placeholderClass)
Class c = object_getClass(self);
if (c != abstractClass && c != placeholderClass)
{
_NSURLProtocolInternal = NSZoneCalloc([self zone],
1, sizeof(Internal));
@ -475,7 +477,9 @@ static NSURLProtocol *placeholder = nil;
cachedResponse: (NSCachedURLResponse *)cachedResponse
client: (id <NSURLProtocolClient>)client
{
if (isa == abstractClass || isa == placeholderClass)
Class c = object_getClass(self);
if (c == abstractClass || c == placeholderClass)
{
unsigned count;