mirror of
https://github.com/gnustep/libs-base.git
synced 2025-06-01 17:12:03 +00:00
Added implementations of the hooks provided by the new runtime. This brings
NSObject up to feature-parity with the OS X 10.5 implementation when using the new runtime and up to feature-parity with the 10.6 implementation if you are using the new runtime and compiling with clang. Also removes the objc_mutex_wibble stuff from NSObject in favour of just using NSLocks (which, with the new implementation, are now faster than using objc_mutex_stuff). git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@28657 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
4f13b89771
commit
023f3b5e17
4 changed files with 206 additions and 36 deletions
14
ChangeLog
14
ChangeLog
|
@ -1,3 +1,17 @@
|
||||||
|
2009-09-10 David Chisnall <csdavec@swan.ac.uk>
|
||||||
|
|
||||||
|
* Source/GSFFIInvocation.m:
|
||||||
|
* Source/NSObject.m:
|
||||||
|
* Headers/Foundation/NSObject.h:
|
||||||
|
Added implementations of the hooks provided by the new runtime. This
|
||||||
|
brings NSObject up to feature-parity with the OS X 10.5 implementation
|
||||||
|
when using the new runtime and up to feature-parity with the 10.6
|
||||||
|
implementation if you are using the new runtime and compiling with clang.
|
||||||
|
|
||||||
|
Also removes the objc_mutex_wibble stuff from NSObject in favour of just
|
||||||
|
using NSLocks (which, with the new implementation, are now faster than
|
||||||
|
using objc_mutex_stuff).
|
||||||
|
|
||||||
2009-09-10 Richard Frith-Macdonald <rfm@gnu.org>
|
2009-09-10 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
* Source/NSRunLoop.m: ([-limitDateForMode:]) on OSX it seems that only
|
* Source/NSRunLoop.m: ([-limitDateForMode:]) on OSX it seems that only
|
||||||
|
|
|
@ -234,6 +234,58 @@ extern "C" {
|
||||||
- (id) self;
|
- (id) self;
|
||||||
- (Class) superclass;
|
- (Class) superclass;
|
||||||
- (NSZone*) zone;
|
- (NSZone*) zone;
|
||||||
|
#if OS_API_VERSION(MAC_OS_X_VERSION_10_5, GS_API_LATEST)
|
||||||
|
/**
|
||||||
|
* This method will be called when attempting to send a message a class that
|
||||||
|
* does not understand it. The class may install a new method for the given
|
||||||
|
* selector and return YES, otherwise it should return NO.
|
||||||
|
*
|
||||||
|
* Note: This method is only reliable when using the GNUstep runtime. If you
|
||||||
|
* require compatibility with the GCC runtime, you must also implement
|
||||||
|
* -forwardInvocation: with equivalent semantics. This will be considerably
|
||||||
|
* slower, but more portable.
|
||||||
|
*/
|
||||||
|
+ (BOOL)resolveClassMethod:(SEL)name;
|
||||||
|
/**
|
||||||
|
* This method will be called when attempting to send a message an instance
|
||||||
|
* that does not understand it. The class may install a new method for the
|
||||||
|
* given selector and return YES, otherwise it should return NO.
|
||||||
|
*
|
||||||
|
* Note: This method is only reliable when using the GNUstep runtime. If you
|
||||||
|
* require compatibility with the GCC runtime, you must also implement
|
||||||
|
* -forwardInvocation: with equivalent semantics. This will be considerably
|
||||||
|
* slower, but more portable.
|
||||||
|
*/
|
||||||
|
+ (BOOL)resolveInstanceMethod:(SEL)name;
|
||||||
|
#endif
|
||||||
|
#if OS_API_VERSION(MAC_OS_X_VERSION_10_6, GS_API_LATEST)
|
||||||
|
/**
|
||||||
|
* If an object does not understand a message, it may delegate it to another
|
||||||
|
* object. Returning nil indicates that forwarding should not take place. The
|
||||||
|
* default implementation of this returns nil, but care should be taken when
|
||||||
|
* subclassing NSObject subclasses and overriding this method that
|
||||||
|
* the superclass implementation is called if returning nil.
|
||||||
|
*
|
||||||
|
* Note: This method is only reliable when using the GNUstep runtime and code
|
||||||
|
* compiled with clang. If you require compatibility with GCC and the GCC
|
||||||
|
* runtime, you must also implement -forwardInvocation: with equivalent
|
||||||
|
* semantics. This will be considerably slower, but more portable.
|
||||||
|
*/
|
||||||
|
- (id)forwardingTargetForSelector:(SEL)aSelector;
|
||||||
|
/**
|
||||||
|
* Returns an auto-accessing proxy for the given object. This proxy sends a
|
||||||
|
* -beginContentAccess message to the receiver when it is created and an
|
||||||
|
* -endContentAccess message when it is destroyed. This prevents an object
|
||||||
|
* that implements the NSDiscardableContent protocol from having its contents
|
||||||
|
* discarded for as long as the proxy exists.
|
||||||
|
*
|
||||||
|
* On systems using the GNUstep runtime, messages send to the proxy will be
|
||||||
|
* slightly slower than direct messages. With the GCC runtime, they will be
|
||||||
|
* approximately two orders of magnitude slower. The GNUstep runtime,
|
||||||
|
* therefore, is strongly recommended for code calling this method.
|
||||||
|
*/
|
||||||
|
- (id)autoContentAccessingProxy;
|
||||||
|
#endif
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -29,6 +29,10 @@
|
||||||
#import "GSInvocation.h"
|
#import "GSInvocation.h"
|
||||||
#import <config.h>
|
#import <config.h>
|
||||||
#import <objc/objc-api.h>
|
#import <objc/objc-api.h>
|
||||||
|
// FIXME: We should be using the new interfaces, not exposing the old ones.
|
||||||
|
#define __OBJC_LEGACY_GNU_MODE__
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
#import <pthread.h>
|
||||||
#import "cifframe.h"
|
#import "cifframe.h"
|
||||||
#import "mframe.h"
|
#import "mframe.h"
|
||||||
#import "GSPrivate.h"
|
#import "GSPrivate.h"
|
||||||
|
@ -209,6 +213,66 @@ IMP gs_objc_msg_forward (SEL sel)
|
||||||
{
|
{
|
||||||
return gs_objc_msg_forward2 (nil, sel);
|
return gs_objc_msg_forward2 (nil, sel);
|
||||||
}
|
}
|
||||||
|
#ifdef __GNUSTEP_RUNTIME__
|
||||||
|
pthread_key_t thread_slot_key;
|
||||||
|
static struct objc_slot_t gs_objc_msg_forward3(id receiver, SEL op)
|
||||||
|
{
|
||||||
|
/* The slot has its version set to 0, so it can not be cached. This makes it
|
||||||
|
* safe to free it when the thread exits. */
|
||||||
|
Slot_t slot = pthread_getspecific(thread_slot_key);
|
||||||
|
if (NULL == slot)
|
||||||
|
{
|
||||||
|
slot = calloc(sizeof(struct objc_slot), 1);
|
||||||
|
pthread_setspecific(thread_slot_key, slot);
|
||||||
|
}
|
||||||
|
slot->method = gs_objc_msg_forward2(receiver, op);
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Hidden by legacy API define. Declare it locally */
|
||||||
|
BOOL class_isMetaClass(Class cls);
|
||||||
|
BOOL class_respondsToSelector(Class cls, SEL sel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runtime hook used to provide message redirections. If lookup fails but this
|
||||||
|
* function returns non-nil then the lookup will be retried with the returned
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* Note: Every message sent by this function MUST be understood by the
|
||||||
|
* receiver. If this is not the case then there is a potential for infinite
|
||||||
|
* recursion.
|
||||||
|
*/
|
||||||
|
static id gs_objc_proxy_lookup(id receiver, SEL op)
|
||||||
|
{
|
||||||
|
/* FIXME: Should be isa, but legacy-compat mode makes it class_pointer */
|
||||||
|
Class cls = receiver->class_pointer;
|
||||||
|
BOOL resolved = NO;
|
||||||
|
/* Let the class try to add a method for this thing. */
|
||||||
|
if (class_isMetaClass(cls))
|
||||||
|
{
|
||||||
|
if (class_respondsToSelector(cls, @selector(resolveClassMethod:)))
|
||||||
|
{
|
||||||
|
resolved = [receiver resolveClassMethod: op];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (class_respondsToSelector(cls->class_pointer, @selector(resolveInstanceMethod:)))
|
||||||
|
{
|
||||||
|
resolved = [class resolveInstanceMethod: op];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (resolved)
|
||||||
|
{
|
||||||
|
return receiver;
|
||||||
|
}
|
||||||
|
if (class_respondsToSelector(cls, @selector(forwardingTargetForSelector:)))
|
||||||
|
{
|
||||||
|
return [receiver forwardingTargetForSelector: op]
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
+ (void) load
|
+ (void) load
|
||||||
{
|
{
|
||||||
|
@ -217,6 +281,11 @@ IMP gs_objc_msg_forward (SEL sel)
|
||||||
#else
|
#else
|
||||||
__objc_msg_forward = gs_objc_msg_forward;
|
__objc_msg_forward = gs_objc_msg_forward;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef __GNUSTEP_RUNTIME__
|
||||||
|
pthread_key_create(&thread_slot_key, free);
|
||||||
|
objc_msg_forward3 = gs_objc_msg_forward3;
|
||||||
|
objc_proxy_lookup = gs_objc_proxy_lookup;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id) initWithArgframe: (arglist_t)frame selector: (SEL)aSelector
|
- (id) initWithArgframe: (arglist_t)frame selector: (SEL)aSelector
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "GNUstepBase/preface.h"
|
#include "GNUstepBase/preface.h"
|
||||||
|
#include "GNUstepBase/GNUstep.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include "Foundation/NSObject.h"
|
#include "Foundation/NSObject.h"
|
||||||
#include <objc/Protocol.h>
|
#include <objc/Protocol.h>
|
||||||
|
@ -114,11 +115,18 @@ static Class NSConstantStringClass;
|
||||||
- (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector;
|
- (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@interface GSContentAccessingProxy : NSProxy
|
||||||
|
{
|
||||||
|
NSObject<NSDiscardableContent> *object;
|
||||||
|
}
|
||||||
|
- (id)initWithObject: (id)anObject;
|
||||||
|
@end
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* allocationLock is needed when running multi-threaded for
|
* allocationLock is needed when running multi-threaded for
|
||||||
* protecting the map table of zombie information.
|
* protecting the map table of zombie information.
|
||||||
*/
|
*/
|
||||||
static objc_mutex_t allocationLock = NULL;
|
static NSLock *allocationLock;
|
||||||
|
|
||||||
BOOL NSZombieEnabled = NO;
|
BOOL NSZombieEnabled = NO;
|
||||||
BOOL NSDeallocateZombies = NO;
|
BOOL NSDeallocateZombies = NO;
|
||||||
|
@ -135,15 +143,9 @@ static void GSMakeZombie(NSObject *o)
|
||||||
((id)o)->class_pointer = zombieClass;
|
((id)o)->class_pointer = zombieClass;
|
||||||
if (NSDeallocateZombies == NO)
|
if (NSDeallocateZombies == NO)
|
||||||
{
|
{
|
||||||
if (allocationLock != 0)
|
[allocationLock lock];
|
||||||
{
|
|
||||||
objc_mutex_lock(allocationLock);
|
|
||||||
}
|
|
||||||
NSMapInsert(zombieMap, (void*)o, (void*)c);
|
NSMapInsert(zombieMap, (void*)o, (void*)c);
|
||||||
if (allocationLock != 0)
|
[allocationLock unlock];
|
||||||
{
|
|
||||||
objc_mutex_unlock(allocationLock);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -154,15 +156,9 @@ static void GSLogZombie(id o, SEL sel)
|
||||||
|
|
||||||
if (NSDeallocateZombies == NO)
|
if (NSDeallocateZombies == NO)
|
||||||
{
|
{
|
||||||
if (allocationLock != 0)
|
[allocationLock lock];
|
||||||
{
|
|
||||||
objc_mutex_lock(allocationLock);
|
|
||||||
}
|
|
||||||
c = NSMapGet(zombieMap, (void*)o);
|
c = NSMapGet(zombieMap, (void*)o);
|
||||||
if (allocationLock != 0)
|
[allocationLock unlock];
|
||||||
{
|
|
||||||
objc_mutex_unlock(allocationLock);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (c == 0)
|
if (c == 0)
|
||||||
{
|
{
|
||||||
|
@ -339,9 +335,9 @@ GSAtomicDecrement(gsatomic_t X)
|
||||||
#define LOCKMASK (LOCKCOUNT-1)
|
#define LOCKMASK (LOCKCOUNT-1)
|
||||||
#define ALIGNBITS 3
|
#define ALIGNBITS 3
|
||||||
|
|
||||||
static objc_mutex_t allocationLocks[LOCKCOUNT] = { 0 };
|
static NSLock *allocationLocks[LOCKCOUNT] = { 0 };
|
||||||
|
|
||||||
static inline objc_mutex_t GSAllocationLockForObject(id p)
|
static inline NSLock *GSAllocationLockForObject(id p)
|
||||||
{
|
{
|
||||||
NSUInteger i = ((((NSUInteger)(uintptr_t)p) >> ALIGNBITS) & LOCKMASK);
|
NSUInteger i = ((((NSUInteger)(uintptr_t)p) >> ALIGNBITS) & LOCKMASK);
|
||||||
return allocationLocks[i];
|
return allocationLocks[i];
|
||||||
|
@ -422,18 +418,18 @@ NSDecrementExtraRefCountWasZero(id anObject)
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
#else /* GSATOMICREAD */
|
#else /* GSATOMICREAD */
|
||||||
objc_mutex_t theLock = GSAllocationLockForObject(anObject);
|
NSLock *theLock = GSAllocationLockForObject(anObject);
|
||||||
|
|
||||||
objc_mutex_lock(theLock);
|
[theLock lock];
|
||||||
if (((obj)anObject)[-1].retained == 0)
|
if (((obj)anObject)[-1].retained == 0)
|
||||||
{
|
{
|
||||||
objc_mutex_unlock(theLock);
|
[theLock unlock];
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
((obj)anObject)[-1].retained--;
|
((obj)anObject)[-1].retained--;
|
||||||
objc_mutex_unlock(theLock);
|
[theLock unlock];
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
#endif /* GSATOMICREAD */
|
#endif /* GSATOMICREAD */
|
||||||
|
@ -495,9 +491,9 @@ NSIncrementExtraRefCount(id anObject)
|
||||||
format: @"NSIncrementExtraRefCount() asked to increment too far"];
|
format: @"NSIncrementExtraRefCount() asked to increment too far"];
|
||||||
}
|
}
|
||||||
#else /* GSATOMICREAD */
|
#else /* GSATOMICREAD */
|
||||||
objc_mutex_t theLock = GSAllocationLockForObject(anObject);
|
NSLock *theLock = GSAllocationLockForObject(anObject);
|
||||||
|
|
||||||
objc_mutex_lock(theLock);
|
[theLock lock];
|
||||||
if (((obj)anObject)[-1].retained == UINT_MAX - 1)
|
if (((obj)anObject)[-1].retained == UINT_MAX - 1)
|
||||||
{
|
{
|
||||||
objc_mutex_unlock (theLock);
|
objc_mutex_unlock (theLock);
|
||||||
|
@ -505,7 +501,7 @@ NSIncrementExtraRefCount(id anObject)
|
||||||
format: @"NSIncrementExtraRefCount() asked to increment too far"];
|
format: @"NSIncrementExtraRefCount() asked to increment too far"];
|
||||||
}
|
}
|
||||||
((obj)anObject)[-1].retained++;
|
((obj)anObject)[-1].retained++;
|
||||||
objc_mutex_unlock (theLock);
|
[theLock lock];
|
||||||
#endif /* GSATOMICREAD */
|
#endif /* GSATOMICREAD */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -875,10 +871,10 @@ GSDescriptionForClassMethod(pcl self, SEL aSel)
|
||||||
|
|
||||||
for (i = 0; i < LOCKCOUNT; i++)
|
for (i = 0; i < LOCKCOUNT; i++)
|
||||||
{
|
{
|
||||||
allocationLocks[i] = objc_mutex_allocate();
|
allocationLocks[i] = [NSLock new];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
allocationLock = objc_mutex_allocate();
|
allocationLock = [NSLock new];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2018,6 +2014,22 @@ GSGarbageCollectorLog(char *msg, GC_word arg)
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (BOOL)resolveClassMethod:(SEL)name
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
+ (BOOL)resolveInstanceMethod:(SEL)name;
|
||||||
|
{
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
- (id)forwardingTargetForSelector:(SEL)aSelector;
|
||||||
|
{
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
- (id)autoContentAccessingProxy
|
||||||
|
{
|
||||||
|
return AUTORELEASE([[GSContentAccessingProxy alloc] initWithObject: self]);
|
||||||
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@ -2455,16 +2467,39 @@ GSGarbageCollectorLog(char *msg, GC_word arg)
|
||||||
{
|
{
|
||||||
Class c;
|
Class c;
|
||||||
|
|
||||||
if (allocationLock != 0)
|
[allocationLock lock];
|
||||||
{
|
|
||||||
objc_mutex_lock(allocationLock);
|
|
||||||
}
|
|
||||||
c = NSMapGet(zombieMap, (void*)self);
|
c = NSMapGet(zombieMap, (void*)self);
|
||||||
if (allocationLock != 0)
|
[allocationLock unlock];
|
||||||
{
|
|
||||||
objc_mutex_unlock(allocationLock);
|
|
||||||
}
|
|
||||||
return [c instanceMethodSignatureForSelector: aSelector];
|
return [c instanceMethodSignatureForSelector: aSelector];
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation GSContentAccessingProxy
|
||||||
|
- (id)initWithObject: (id)anObject
|
||||||
|
{
|
||||||
|
ASSIGN(object, anObject);
|
||||||
|
[object beginContentAccess];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
- (void)finalize
|
||||||
|
{
|
||||||
|
[object endContentAccess];
|
||||||
|
}
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
[object endContentAccess];
|
||||||
|
}
|
||||||
|
- (id)forwardingTargetForSelector: (SEL)aSelector
|
||||||
|
{
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
/* Support for legacy runtimes... */
|
||||||
|
- (void) forwardInvocation: (NSInvocation*)anInvocation
|
||||||
|
{
|
||||||
|
[anInvocation invokeWithTarget: object];
|
||||||
|
}
|
||||||
|
- (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector
|
||||||
|
{
|
||||||
|
return [object methodSignatureForSelector: aSelector];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue